亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

什么是Django contenttypes框架

發布時間:2020-08-25 15:54:47 來源:億速云 閱讀:133 作者:Leah 欄目:編程語言

什么是Django contenttypes框架?很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。

什么是Django ContentTypes?

Django ContentTypes是由Django框架提供的一個核心功能,它對當前項目中所有基于Django驅動的model提供了更高層次的抽象接口。

然而,對于Django ContentTypes不熟悉的人來說,上面這句話說了跟沒說一樣,因此,筆者將一步一步解釋Django ContentTypes在Django框架中做了什么,以及如何使用Django ContentTypes。

當然,如果對于ContentTypes有了初步了解而只是不了解它的應用場景,可以直接查閱以下這兩個鏈接:

Django official documentation:The contenttypes framework

stackoverflow: How exactly do Django content types work?

Django ContentTypes做了什么?

當使用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是在django.contrib.auth之后,這是因為auth中的permission系統是根據contenttypes來實現的。

筆者緊接著查閱了一下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

大家可以看到ContentType就是一個簡單的django model,而且它在數據庫中的表的名字為django_content_type。

有經驗的Django開發者對于這個表的名字一般都不會陌生,在第一次對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屬性)。

當然,django_content_type并不只是記錄屬性這么簡單,在一開始的時候筆者就提及了contenttypes是對model的一次封裝,因此可以通過contenttypes動態的訪問model類型,而不需要每次import具體的model類型。

·ContentType實例提供的接口

    ·ContentType.model_class()

        ·獲取當前ContentType類型所代表的模型類

    ·ContentType.get_object_for_this_type()

        ·使用當前ContentType類型所代表的模型類做一次get查詢

·ContentType管理器(manager)提供的接口

    ·ContentType.objects.get_for_id()

        ·通過id尋找ContentType類型,這個跟傳統的get方法的區別就是它跟get_for_model共享一個緩存,因此更為推薦。

    ·ContentType.objects.get_for_model()

        ·通過model或者model的實例來尋找ContentType類型

Django ContentTypes的使用場景

Permission對ContentType的使用

在之前,筆者簡單地提及了auth中Permission有涉及到對ContentType的使用,下面來看一下Permission的model源碼:

class Permission(models.Model):
    """
    The permissions system provides a way to assign permissions to specific
    users and groups of users.
    The permission system is used by the Django admin site, but may also be
    useful in your own code. The Django admin site uses permissions as follows:
        - The "add" permission limits the user's ability to view the "add" form
          and add an object.
        - The "change" permission limits a user's ability to view the change
          list, view the "change" form and change an object.
        - The "delete" permission limits the ability to delete an object.
    Permissions are set globally per type of object, not per specific object
    instance. It is possible to say "Mary may change news stories," but it's
    not currently possible to say "Mary may change news stories, but only the
    ones she created herself" or "Mary may only change news stories that have a
    certain status or publication date."
    Three basic permissions -- add, change and delete -- are automatically
    created for each Django model.
    """
    name = models.CharField(_('name'), max_length=255)
    content_type = models.ForeignKey(ContentType,models.CASCADE,verbose_name=_('content type'),)
    codename = models.CharField(_('codename'), max_length=100)
    objects = PermissionManager()
    class Meta:
        verbose_name = _('permission')
        verbose_name_plural = _('permissions')
        unique_together = (('content_type', 'codename'),)
        ordering = ('content_type__app_label', 'content_type__model','codename')

大家可以看到Permission模型中設置了一個對ContentType的外鍵,這意味著每一個Permission的實例都具有關于一個ContentType的id作為外鍵,而ContentType的id恰恰代表著一個Model。

回想Permission模型在初始化的時候發生了什么,它為每個模型設置了三個權限,分別是add,change以及delete,那么它是如何跟每個模型聯系起來的呢?就是通過一個到ContentType的外鍵。

大家可以看一下Permission表,其中第二行就是content_type,然后將主鍵于django_content_type對比:

sqlite> select * from auth_permission;
1|1|add_logentry|Can add log entry
2|1|change_logentry|Can change log entry
3|1|delete_logentry|Can delete log entry
4|2|add_group|Can add group
5|2|change_group|Can change group
6|2|delete_group|Can delete group
7|3|add_user|Can add user
8|3|change_user|Can change user
9|3|delete_user|Can delete user
10|4|add_permission|Can add permission
11|4|change_permission|Can change permission
12|4|delete_permission|Can delete permission
13|5|add_contenttype|Can add content type
14|5|change_contenttype|Can change content type
15|5|delete_contenttype|Can delete content type
16|6|add_session|Can add session
17|6|change_session|Can change session
18|6|delete_session|Can delete session

如此,Permission模型借助ContentType表達了對一個model的權限操作。

ContentType的通用類型

筆者將引用在頂部的stackoverflow中回答的例子講述對通用類型的理解。

假設以下的應用場景:

from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Post(models.Model):
    author = models.ForeignKey(User)
    title = models.CharField(max_length=75)
    slug = models.SlugField(unique=True)
    body = models.TextField(blank=True)
class Picture(models.Model):
    author = models.ForeignKey(User)
    image = models.ImageField()
    caption = models.TextField(blank=True)
class Comment(models.Model):
    author = models.ForeignKey(User)
    body = models.TextField(blank=True)
    post = models.ForeignKey(Post, null=True)
    picture = models.ForeignKey(Picture, null=True)

注意筆者這里跟原回答做了一些更改,在原回答中Comment中沒有null的選項,筆者覺得回答者真正要表達的是Comment是分別和Picture或者Post中其中一個對應即可,一個Comment并不既需要Post又需要Picture才能建立,可能是回答者寫錯沒注意的緣故。

當筆者對以上model進行migrate之后,發現Comment表中的foreignkey是可以被設置為null的。

那么,如何通過Contenttype框架對以上代碼進行改進呢?

ContentType提供了一種GenericForeignKey的類型,通過這種類型可以實現在Comment對其余所有model的外鍵關系。

修改后的Comment模型如下:

class Comment(models.Model):
    author = models.ForeignKey(User)
    body = models.TextField(blank=True)
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = fields.GenericForeignKey()

在這里,通過使用一個content_type屬性代替了實際的model(如Post,Picture),而object_id則代表了實際model中的一個實例的主鍵,其中,content_type和object_id的字段命名都是作為字符串參數傳進content_object的。即:

content_object = fields.GenericForeignKey('content_type', 'object_id')

筆者先準備一些測試用的數據:

user = User.objects.create_user(username='user1', password='2333')
post = Post.objects.create(author=user,title='title1',slug=slugify('title1'),body='')
picture = Picture.objects.create(author=user,image="http://www.picture1.com",caption='picture1')

接著在shell中創建Comment:

>>> from foreign.models import Post, Picture, Common
>>> from django.contrib.auth.models import User
>>> user = User.objects.get(username='user1')
>>> post = Post.objects.get(title='title1')
>>> c = Comment.objects.create(author=user, body='', content_object=post)
>>> c
<Comment: Comment object>
>>> c.content_type
<ContentType: post>
>>> c.object_id
1
>>> picture = Picture.objects.get(caption='picuture1')
>>> c = Comment.objects.create(author=user, body='', content_object=picture)
>>> c.content_type
<ContentType: picture>
>>> c.object_id
1

在django中,也提供從諸如Post,Picture訪問Comment的查詢,通過GenericRelation類型。如:

class Post(models.Model):
    author = models.ForeignKey(User)
    title = models.CharField(max_length=75)
    slug = models.SlugField(unique=True)
    body = models.TextField(blank=True)
    comment = GenericRelation('Comment')

值得注意的是,如果在Post中定義了GenericRelation,刪除了一個實例,在Comment中所有的相關實例也會被刪除,GenericForeignKey不支持設置on_delete參數。

因此,如果對級聯刪除不滿意的話就不要設置GenericRelation。

看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

肇庆市| 呼玛县| 建水县| 尖扎县| 柘城县| 旺苍县| 宽甸| 永吉县| 中江县| 翁牛特旗| 蓝山县| 峨眉山市| 青州市| 依兰县| 遵义市| 固安县| 滕州市| 大宁县| 庐江县| 北宁市| 松原市| 公主岭市| 荣成市| 永兴县| 辽源市| 达拉特旗| 博罗县| 临江市| 吐鲁番市| 祁连县| 泸水县| 昌黎县| 洛扎县| 惠州市| 金平| 河间市| 自治县| 剑河县| 徐州市| 新余市| 亳州市|