咱们在网上po一段散文诗也能够po一张旅途的风景图,文字能够被评论,图片也能够被评论。咱们须要在数据库中建表存储这些数据,咱们可能会设计出下面这样的表结构。数据库
class Post(models.Model): """帖子表""" author = models.ForeignKey(User) title = models.CharField(max_length=72) class Picture(models.Model): """图片表""" author = models.ForeignKey(User) image = models.ImageField() class Comment(models.Model): """评论表""" author = models.ForeignKey(User) content = models.TextField() post = models.ForeignKey(Post, null=True, blank=True, on_delete=models.CASCADE) picture = models.ForeignKey(Picture, null=True, blank=True, on_delete=models.CASCADE)
这表结构看起来不太简洁,咱们画个图来看一下:django
能用是能用,可是评论表有点冗余啊。好多列都空着呢啊!app
咱们优化一下,咱们在评论表里不直接外键关联 文字和图片,而是存储一下关联的表名和字段,这样就好不少了。工具
看下图:post
那咱们不妨步子再大一点,再往前走一步试试,由于表名在评论里面重复了不少次,咱们彻底能够把Django项目中的表名都存储在一个表里面。而后评论表里外键关联这个表就能够了。测试
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.fields import GenericForeignKey
class Comment(models.Model): """评论表""" author = models.ForeignKey(User) content = models.TextField() content_type = models.ForeignKey(ContentType) # 外键关联django_content_type表 object_id = models.PositiveIntegerField() # 关联数据的主键 content_object = GenericForeignKey('content_type', 'object_id')
引入后相关模块后这三个字段一般固定在被关联表就好优化
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey
content_type = models.ForeignKey(ContentType) # 外键关联django_content_type表 object_id = models.PositiveIntegerField() # 关联数据的主键 content_object = GenericForeignKey('content_type', 'object_id')
关联表设置一个反向查询用的字段便可spa
import os if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_contenttype.settings") import django django.setup() from app01.models import Post, Picture, Comment from django.contrib.auth.models import User # 准备测试数据 user_1 = User.objects.create_user(username='aaa', password='123') user_2 = User.objects.create_user(username='bbb', password='123') user_3 = User.objects.create_user(username='ccc', password='123') post_1 = Post.objects.create(author=user_1, title='Python入门教程') post_2 = Post.objects.create(author=user_2, title='Python进阶教程') post_3 = Post.objects.create(author=user_1, title='Python入土教程') picture_1 = Picture.objects.create(author=user_1, image='小姐姐01.jpg') picture_2 = Picture.objects.create(author=user_1, image='小姐姐02.jpg') picture_3 = Picture.objects.create(author=user_3, image='小哥哥01.jpg') # 给帖子建立评论数据 comment_1 = Comment.objects.create(author=user_1, content='好文!', content_object=post_1) # 给图片建立评论数据 comment_2 = Comment.objects.create(author=user_2, content='好美!', content_object=picture_1)
from django.contrib.contenttypes.fields import GenericRelation
class Post(models.Model): """帖子表""" author = models.ForeignKey(User) title = models.CharField(max_length=72) comments = GenericRelation('Comment') # 支持反向查找评论数据(不会在数据库中建立字段) class Picture(models.Model): """图片表""" author = models.ForeignKey(User) image = models.ImageField() comments = GenericRelation('Comment') # 支持反向查找评论数据(不会在数据库中建立字段)
查询示例:设计
post_1 = Post.objects.filter(id=1).first() comment_list = post_1.comments.all()