Python 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來實現:
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使用

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()
相關文章
相關標籤/搜索