一、概述
Django为了帮助我们解决关系型数据库多个表之间享用共同外键的问题时,提供了GenericForeignKey模型字段,虽然性能上有些许损耗,但是逻辑清楚、比较易用。
二、GenericForeignKey的使用
1、Model层使用通用外键:
这里为了实现多个不同情景的模型下(如文章、集体讨论等)下的评论Comment,可使用GenericForeignKey。(不过一般情况下通用外键更适合于如 点赞数、浏览数这样的情景)
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.auth.models import ContentType
...
class Comment(models.Model):
"""Comment aimed at: Discussion, Article and User's comment"""
user_belong = models.ForeignKey(to=User, on_delete=models.CASCADE)
content = models.CharField(max_length=100, verbose_name="评论内容")
created_time = models.DateTimeField(auto_now_add=True, verbose_name="评论时间")
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) #ContentType为Django自带模型。
object_id = models.PositiveIntegerField() #注意object_id必须设置为整数字段,其代表针对Model实例的id
#使用GenericForeignKey,该字段自动接受content_type和object_id作为它的参数!
content_object = GenericForeignKey()
...
2、GenericForeignKey的简单操作
(1)增加一条评论:在view模块的add_comment()函数中针对Article model的一个实例增加一条评论:
def add_comment(request):
"""add a comment to Article"""
target = request.POST.get('target')
article = Article.objects.get(id=target)
form = CommentForm(request.POST)
if form.is_valid():
new_comment = form.save(commit=False)
new_comment.content_object = article #重点在这里!
new_comment.user_belong = request.user
new_comment.save()
return HttpResponseRedirect(reverse('learning_logs:article',args=target))
...
(2)根据文章查询评论(正向查询):
快捷方法:
为了更方便的查询一篇文章下的所有评论,可在ArticleModel中增加:
from django.contrib.contenttypes.fields import GenericRelation
class Article(models.Model):
...
comment_info = GenericRelation(Comment)
...
然后便可根据此直接查询:
class Comment(models.Model):
@classmethod
def get_comments(cls, target):
article = amodel.Article.objects.get(id=target) #先获取特定的文章对象,注意是对象
comments = article.comment_info.all() #利用上述的GeneRelation直接得到该文章的所有评论。
return comments
通用方法:
from django.contrib.auth.models import ContentType
class Comment(models.Model):
...
def get_comments(self, article_id):
model_type = ContentType.objects.get_for_model(Comment)
inner_comments = Comment.objects.filter(content_type=model_type, object_id=article_id)
return comments
...
三、其它
在完成模型部分的设计并且完成数据库迁移之后,在数据库中可以看到有cotente_type这张表(它是创建项目时Django自动生成的表):
再来看看comment表: 注意这里的object_id和content_id属性,分别对应着之前Comment类中的object_id
和content_type
属性。