1. 程式人生 > >8.12 Django contenttypes組件

8.12 Django contenttypes組件

外鍵 code tin setup height 包含 cad key clas

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()

8.12 Django contenttypes組件