[Django學習] Django基礎(10)_ContentType學習總結
一. 什麽是ContentTypes
Django ContentTypes是由Django框架提供的一個核心功能。Django ContentTypes是一個記錄了項目中所有model元數據的表,表中一條記錄對應著一個存在的model。
當使用django-admin初始化一個django項目的時候,可以看到在默認的INSTALL_APPS已經包含了django.contrib.contenttypes:
INSTALLED_APPS = [ ‘django.contrib.admin‘, ‘django.contrib.auth‘, ‘django.contrib.contenttypes‘,‘django.contrib.sessions‘, ‘django.contrib.messages‘, ‘django.contrib.staticfiles‘, ]
django.contrib.contenttypes.models文件:
class ContentType(models.Model): app_label = models.CharField(max_length=100) model = models.CharField(_(‘python model class name‘), max_length=100) objects = ContentTypeManager() class Meta: verbose_name = _(‘content type‘) verbose_name_plural = _(‘content types‘) db_table = ‘django_content_type‘ unique_together = ((‘app_label‘, ‘model‘),) def __str__(self): return self.name
在第一次對Django的model進行migrate之後,就可以發現在數據庫中出現了一張默認生成的名為django_content_type的表。 如果沒有建立任何的model,默認django_content_type是這樣的:
sqlite> select * from django_content_type; 1|admin|logentry 2|auth|group 3|auth|user 4|auth|permission 5|contenttypes|contenttype 6|sessions|session
django_content_type記錄了當前的Django項目中所有model所屬的app(即app_label屬性)以及model的名字(即model屬性)。 所以可以通過一個ContentType表的id和一個具體表中的id找到任何記錄,即先通過ContenType表的id可以得到某個model,再通過model的id得到具體的對象。
二. ContentType實例的基本方法
1. ContentType.
get_object_for_this_type
(**kwargs)
為ContentType表示的模型獲取一組有效的查找參數,並執行get()查找該模型,返回相應的對象。
2. ContentType.
model_class
()- 返回由這個ContentType實例表示的模型類。
>>> from django.contrib.contenttypes.models import ContentType >>> user_type = ContentType.objects.get(app_label="auth", model="user") <ContentType: user> >>> >>> user_type.model_class() <class ‘django.contrib.auth.models.User‘> >>> >>> user_type.get_object_for_this_type(username=‘Guido‘) <User: Guido>
使用這些方法,您可以編寫高級通用代碼執行查詢任何安裝模型——而不是import和使用一個特定的模型類;再運行時,您可以傳遞app_label和model到一個ContentType的查詢中,然後就可以使用查詢結果中的model class或檢索model中的對象。
- 您可以將另一個模型與ContentType關聯起來,將它的實例與特定的模型類綁定在一起,並使用這些方法訪問這些模型類。
三. 自定義管理器ContentTypeManager
1. get_for_id
(id)
通過id來查詢ContentType
3. get_for_model
(model, for_concrete_model=True)
獲取模型類或模型實例,並返回表示該模型的ContentType實例
4. get_for_models
(*models, for_concrete_models=True)
獲取模型類的可變數量,並返回一個字典,該字典將模型類映射到表示它們的ContentType實例。
5. get_by_natural_key
(app_label, model)
返回由給定的應用程序標簽和模型名稱唯一標識的ContentType實例。
>>> ct=ContentType.objects.all() >>> ct <QuerySet [<ContentType: log entry>, <ContentType: permission>, <ContentType: group>, <ContentType: user>, <ContentType: content type>, <ContentType: session>, <ContentType: blog>, <ContentType: blog type>, <ContentType: readnum>, <ContentType: read num>, <ContentType: read detail num>]> >>> >>> ContentType.objects.get_for_id(1) <ContentType: log entry> >>> >>> from blog.models import Blog >>> from blog.models import BlogType >>> ContentType.objects.get_for_model(Blog) <ContentType: blog> >>> ContentType.objects.get_for_models(Blog,BlogType) {<class ‘blog.models.Blog‘>: <ContentType: blog>, <class ‘blog.models.BlogType‘>: <ContentType: blog type>} >>> ContentType.objects.get_by_natural_key(app_label=‘blogstatistics‘,model=‘readnum‘) <ContentType: read num>
四. Generic relations
從某個模型中添加外鍵到ContentType可以使您的模型有效地綁定到另一個模型類,從而使用ContentType來啟用模型之間的真正泛型(有時稱為“多態”)關系。
from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType from django.db import models class TaggedItem(models.Model): tag = models.SlugField() content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) object_id = models.PositiveIntegerField() content_object = GenericForeignKey(‘content_type‘, ‘object_id‘) def __str__(self): return self.tag
普通的ForeignKey只能“指向”另一個模型,這意味著如果TaggedItem模型使用了ForeignKey,那麽它必須選擇一個特定模型來存儲Tag。contenttypes應用程序提供了一個特殊的字段類型(GenericForeignKey),它並允許與任何模型的關系。
一個標準的GenericForeignKey由三部分組成:
- 在model中定義ForeignKey字段,並關聯到ContentType表。通常這個字段命名為“content_type”
- 在model中定義PositiveIntegerField字段,用來存儲關聯表中的主鍵。通常這個字段命名為“object_id”
- 在model中定義GenericForeignKey字段,傳入上述兩個字段的名字。
這將使API與普通的ForeignKey相似;每個TaggedItem都有一個content_object字段,該字段返回與之相關的對象,您也可以將其分配給該字段,或者在創建TaggedItem時使用:
五. Reverse generic relations
如果您知道您將最經常使用哪些模型,您還可以添加一個“反向”泛型關系來啟用一個額外的API。
from django.contrib.contenttypes.fields import GenericRelation from django.db import models class Bookmark(models.Model): url = models.URLField() tags = GenericRelation(TaggedItem) #不會在數據庫中創建字段
Bookmark實例將每個實例都有一個Tags屬性,可以用來檢索它們關聯的taggeditem:
>>> b = Bookmark(url=‘https://www.djangoproject.com/‘) >>> b.save() >>> t1 = TaggedItem(content_object=b, tag=‘django‘) >>> t1.save() >>> t2 = TaggedItem(content_object=b, tag=‘python‘) >>> t2.save() >>> b.tags.all() <QuerySet [<TaggedItem: django>, <TaggedItem: python>]>
From: Django文檔
[Django學習] Django基礎(10)_ContentType學習總結