Django contenttypes的作用
1.django.contrib.contenttypes
Django創建項目后,在settings.py中默認加載了以下幾個app:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
其中有個app為django.contrib.contenttypes,在使用了python manage.py makemigrations 和 python manage.py migrate命令后,這個app會在數據庫創建表 django_content_type,數據表字段如下:
django_content_type表存儲了用戶所提交的所有model名稱與model所在的app名稱
其中的model字段為用戶定義的模型類的名稱,app_label為該模型所在app名稱
2.實例分析
那么這個表的意義在哪?我們可以用這個表來干嘛?引用網上諸多博文使用的例子,現在有四個model,我們自己創建的Post,Picture和Comment,加上django原生的User。
django原生的User model即用戶表
Comment為用戶提交的評論表
Picture為存儲圖片信息的表
Post為存儲文章信息的表
場景如下:用戶可以對圖片或者文章提交評論,那么Comment中首先要存儲的是,該評論對應的用戶,再就是該評論是針對哪張圖片或者哪篇文章的評論,代碼如下:
from django.db import models
from django.contrib.auth.models import User
class Post(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
body = models.TextField(blank=True)
class Picture(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
body = models.TextField(blank=True)
class Comment(models.Model):
author = models.ForeignKey(to=User, on_delete=models.CASCADE)
body = models.TextField(blank=True)
pic = models.ForeignKey(to=Picture, on_delete=models.CASCADE, null=True)
post = models.ForeignKey(to=Post, on_delete=models.CASCADE, null=True)
為了建立Comment與Post或者Picture的關系,我們就需要創建外鍵,如果該Comment與Picture有關聯,那么pic字段是有值的,而其余的關聯字段為null。這樣實現的缺點是,每增加一種被評論的類型,在Comment model中就需要多新增一個外鍵,擴展性極差。
3.使用contenttypes來解決問題
如果使用contenttypes就不需要再使用多個Foreignkey,因為在django_content_type表已經存儲了app名和model名,所以我們只需要將我們創建的模型與django_content_type表關聯起來,然后再存儲一個實例 id 即可準確定位到某個app中某個模型的具體實例。代碼如下:
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import User
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
class Post(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
body = models.TextField(blank=True)
comments = GenericRelation('Comment') # 使用GenericRelation可以建立該類與Comment類的反向關聯,
# 那么可以通過該類的實例來創建對應的comment
class Picture(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
body = models.TextField(blank=True)
comments = GenericRelation('Comment')
class Comment(models.Model):
# user_name = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
author = models.ForeignKey(to=User, on_delete=models.CASCADE)
body = models.TextField(blank=True)
# step1
# ForeignKey為外鍵,即在Comment類中,content_type對應了django_content_type表中的某個對象
content_type = models.ForeignKey(to=ContentType, on_delete=models.CASCADE) # 與數據庫中的django_content_type表關聯起來
# step2
object_id = models.PositiveIntegerField() # 正整數類型,在被關聯的表中的實例id,以此來定位具體的實例
# step3
content_object = GenericForeignKey() # 根據content_type和object_id來指向一個模型中的具體實例
首先看Comment這個模型,與contenttypes相關的就三個字段:content_tpye object_id content_object
content_type字段為外鍵,指向ContentType這個模型,也就是上面提到的django_content_type表
object_id為一個整數,存儲了實例id,實例id不理解可以看下面的數據表結構分析
content_object為GenericForeignKey類型,主要作用是根據content_type字段和object_id字段來定位某個模型中具體某個實例
所以實際上在使用GenericForeignKey()函數時需要傳入兩個參數,即content_type和object_id字段的名字,注意是名字不是value。但是默認在該函數的構造函數中已經賦予了默認值,即"content_type"和"object_id",所以如果我們定義的變量名為這兩個,那么我們可以省略該參數。該字段不會存儲到數據庫中,在查詢的時候ORM會用到。
GenericForeignKey構造函數如下:
def __init__(self, ct_field='content_type', fk_field='object_id', for_concrete_model=True):
self.ct_field = ct_field
self.fk_field = fk_field
self.for_concrete_model = for_concrete_model
self.editable = False
self.rel = None
self.column = None
將模型同步到數據庫,并創建幾個測試數據,使用manage.py自帶的shell可以輕松的創建測試數據。
python manage.py shell
from app1.models import Post, Picture, Comment # app1即為你自己所創建的app名
from django.contrib.auth.models import User # django原生用戶模型
user = User.objects.get(username='admin-x')
post = Post.objects.create(author=user, body='admin-x post test')
picture = Picture.objects.create(author=user, body='admin-x pic test')
pic = Picture.objects.get(id=1) # 獲取id為1的pic對象
c1 = Comment.objects.create(author=user, body='test', content_object=pic) # 創建一個評論并與上述的pic對象關聯起來
還可以注意到,在Post和Picture模型中我們定義了comments = GenericRelation('Comment')
GenericRelation的作用是建立該model與Comment的反向關聯,我們這樣就可以通過Post實例或者Picture實例直接查詢屬于該實例的所有評論,或者創建一個屬于該實例的新評論。
pic = Picture.objects.get(id=1) # 獲取id為1的pic對象
pic.comments.create(author=user, body='test02') # 創建一個屬于pic對象的評論
pic.comments.all() # 獲取屬于pic對象的所有評論
數據表結構分析,這樣應該一目了然了吧
實際上在數據表中,根據content_type_id就可以在django_content_type這個表中定位到哪個app的哪個model,然后根據object_id定位到該model中具體實例。
智能推薦
Django基礎---Web框架、Django的使用
Django基礎—Web框架 MVC和MTV框架 MVC 把Web應用分為模型(M)、視圖(V)、控制器(C)三層,他們之間以一種插件式的,松耦合的方式聯系在一起。模型負責業務對象與數據庫的映射(ORM),視圖負責與用戶的交互(頁面),控制器接收用戶的輸入調用模型和視圖完成用戶的請求。 MTV Django的MTV模式本質上和MVC是一樣的,也是為了各組件間保持松耦合關系,只是定義上有...
Django基礎篇--Django的Form組件
Django基礎篇–Django的Form組件 這篇文章來記錄我學習Django中的Form組件。 之前實現在注冊功能的實現中都是使用html中的form表單提交數據,會發現使用起來不夠方便。因此,Django提供的Form組件,使用起來會比html中的form表單更加方便。 Django的Form組件的常用的字段參數 字段參數 意義 required=True 是否可以為空 widg...
freemarker + ItextRender 根據模板生成PDF文件
1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...
電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!
Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...
猜你喜歡
requests實現全自動PPT模板
http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...
Linux C系統編程-線程互斥鎖(四)
互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...
統計學習方法 - 樸素貝葉斯
引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...
styled-components —— React 中的 CSS 最佳實踐
https://zhuanlan.zhihu.com/p/29344146 Styled-components 是目前 React 樣式方案中最受關注的一種,它既具備了 css-in-js 的模塊化與參數化優點,又完全使用CSS的書寫習慣,不會引起額外的學習成本。本文是 styled-components 作者之一 Max Stoiber 所寫,首先總結了前端組件化樣式中的最佳實踐原則,然后在此基...