8.12 Django contenttypes組件
阿新 • • 發佈:2019-02-05
外鍵 code tin setup height 包含 cad key clas
只要使用django-admin startproject 命令創建的Django項目(PyCharm創建Django項目同理),默認都會在settings.py的INSTALLED_APPS列表中安裝好django.contrib.contenttypes。
我們執行了數據遷移命令之後,會自動在數據庫中創建一個名為django_content_type的表。
表結構如下圖所示:
其中,app_label字段存儲了APP的名稱,model字段存儲了APP下的具體的模型類的名稱。
在models.py中使用django.contrib.contenttypes中提供的特殊字段GenericForeignKey來實現:
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。
應用場景
我們在網上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來實現:
fromdjango.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組件