Django contenttypes组件

contenttypes组件

介绍

Django包含一个contenttypes应用程序(app),能够跟踪Django项目中安装的全部模型(Model),提供用于处理模型的高级通用接口。
Contenttypes应用的核心是ContentType模型,位于django.contrib.contenttypes.models.ContentType。 ContentType的实例表示并保存项目中安装的模型的信息,每当有新的模型时会自动建立新的ContentType实例。

只要使用django-admin startproject 命令建立的Django项目(PyCharm建立Django项目同理),默认都会在settings.py的INSTALLED_APPS列表中安装好django.contrib.contenttypes。
咱们执行了数据迁移命令以后,会自动在数据库中建立一个名为django_content_type的表。
表结构以下图所示:
其中,app_label字段存储了APP的名称,model字段存储了APP下的具体的模型类的名称。

应用场景

咱们在网上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项目中的表名都存储在一个表里面。而后评论表里外键关联这个表就能够了。测试

这个时候咱们就用上了前面讲到的contenttypes,借助contenttypes咱们就可以在建立Comment的时候再决定和Post关联仍是和Picture关联。

在models.py中使用django.contrib.contenttypes中提供的特殊字段GenericForeignKey来实现:
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')
复制代码

contenttypes使用

引入后相关模块后这三个字段一般固定在被关联表就好优化

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)
复制代码
接下来若是咱们想要查看某篇帖子或者某个照片的全部评论,这个时候就能够用上另一个工具--GenericRelation了。
from django.contrib.contenttypes.fields import GenericRelation
修改models.py中的Post和Picture,添加用于反向查询的comments字段:
复制代码
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()
相关文章
相关标签/搜索