• 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项目中的表名都存储在一个表里面。然后评论表里外键关联这个表就可以了。

    这个时候我们就用上了前面讲到的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')

    关联表设置一个反向查询用的字段即可

     具体实例

    复制代码
    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()
  • 相关阅读:
    Java Switch
    老徐杂谈:年后的第一个双休,你在做什么?
    测试必备技能系列4:如何用SSH向linux服务器上传下载文件
    Git从零教你入门(4):Git服务之 gogs部署安装
    你知道哪些linux命令,能把文件上传到远程linux服务器
    一个7年以上测试工程师的2016思考
    老徐谈谈软件测试职业的现状,以及市场情况
    mac 远程连接服务器
    Git从零开始怎么学?
    分享 | Git常用的一些命令
  • 原文地址:https://www.cnblogs.com/shijieli/p/10352471.html
Copyright © 2020-2023  润新知