Kerangka contenttypes

Django menyertakan sebuah aplikasi contenttypes yang dapat melacak semua model-model terpasang dalam proyek Django-powered anda, menyediakan tingkat-tinggi, antarmuka umum untuk bekerja dengan model-model anda.

Ikhtisar

Di jantung dari aplikasi contenttype adalah model ContentType, yang tinggal di django.contrib.contenttypes.models.ContentType`. Instance dari ContentType mewakili dan menyimpan informasi tentang model-model terpasang dalam proyek anda, dan instance baru dari ContentType otomatis dibuat ketika model-model baru terpasang.

Instance dari ContentType mempunai metode-metode untuk mengembalikan kelas-kelas model mereka wakilkan dan untuk meminta obyek dari model-model itu. ContentType juga mempunyai sebuah custom manager 1 yang menambahkan metode untuk bekerja dengan ContentType dan untuk mendapatkan instance dari ContentType untuk model tertentu.

Hubungan diantara model-model anda dan ContentType dapat juga digunakan untuk mengadakan hubungan "umum" diantara sebuah instance dari satu dari model-model anda dan instance dari model apapun anda telah pasang.

Memasang kerangka contenttypes

Kerangka kerja contenttype disertakan dalam daftar INSTALLED_APPS awalan dibuat oleh django-admin startproject, tetapi jika anda telah memindahkan itu atau jika anda secara manual menyetel daftar INSTALLED_APPS anda, anda dapat mengadakan itu dengan menambahkan 'django.contrib.contenttypes' ke pengaturan INSTALLED_APPS anda.

Umumnya ide bagus memiliki kerangka contenttype terpasang; beberapa aplikasi gabungan lain Django membutuhkan itu:

  • Apliaksi admin menggunakan itu utuk mencatat riwayat dari setiap obyek ditambahkan atau dirubah melalui antarmuka admin.
  • authentication framework Django menggunakan itu untuk mengikat perizinan pengguna pada model-model tertentu.

Model ContentType

class ContentType

Setiap instance dari ContentType mempunyai dua bidang yang, diambil bersama-sama, secara unik menggambarkan sebuah model terpasang:

app_label

Nama dari aplikasi model adalah bagian darinya. Ini diambil dari atribut app_label dari model, dan menyertakan hanya bagian terakhir dari django.contrib.contenttypes jalur impor Python aplikasi, sebagai contoh, menjadi app_label dari contenttypes.

model

Nama dari kelas model.

Sebagai tambahan, sifat berikut tersedia:

name

Nama dapat-dibaca-manusia dari jenis isi. Ini adalah diambil dari atribut verbose_name dari model.

Mari kita lihat sebuah contoh untuk melihat bagaimana ini bekerja. Jika anda seudah memiliki aplikasi contenttypes terpasang, dan kemudian tambah the sites application ke pengaturan INSTALLED_APPS anda dan menjalankan manage.py migrate untuk memasangnya, model django.contrib.sites.models.Site akan dipasang kedalam basisdata anda. Bersama dengan itu sebuah instance baru dari ContentType akan dibuat dengan nilai-nilai berikut:

  • app_label akan disetel menjadi 'sites' (bagian terakhir dari jalur Python django.contrib.sites).
  • model akan disetel menjadi 'site'.

Metode pada instance ContentType

Setiap instance ContentType mempunyai metode-metode yang mengizinkan anda mendapatkan dari sebuah instance ContentType pada model yang itu wakili, atau untuk mengambil obyek-obyek dari model itu:

ContentType.get_object_for_this_type(**kwargs)

Mengambil sekumpulan dari perwakilan lookup arguments 1 for the model the ContentType sah, dan melakukan a get() lookup pada model itu, mengembalikan obyek yang sesuai.

ContentType.model_class()

Mengembalikan kelas model diwakilkan oleh instance ContentType ini.

For example, we could look up the ContentType for the User model:

>>> from django.contrib.contenttypes.models import ContentType
>>> user_type = ContentType.objects.get(app_label="auth", model="user")
>>> user_type
<ContentType: user>

And then use it to query for a particular User, or to get access to the User model class:

>>> user_type.model_class()
<class 'django.contrib.auth.models.User'>
>>> user_type.get_object_for_this_type(username="Guido")
<User: Guido>

Bersama-sama, meth:~django.contrib.contenttypes.models.ContentType.get_object_for_this_type dan model_class() mengadakan dua sangat penting penggunaan kasus:

  1. Menggunakan metode ini, anda dapat menulis kode umum tingkat-tinggi yang melakukan permintaan pada mode terpasang apapun -- daripada mengimpor dan menggunakan kelas model khusus, anda dapat melewatkan sebuah app_label dan model kedalam sebuah pencarian ContentType pada waktu berjalan dan kemudian bekerja dengan kelas model atau mengambil obyek dari itu.
  2. Anda dapat menghubungkan model lain ke ContentType sebagai sebuah cara dari mengikat instance dari itu ke kelas-kelas model tertentu, dan gunakan metode ini untuk mendapatkan akses ke kelas-kelas model tersebut.

Beberapa dari aplikasi gabungan Django membuat dari teknik terakhir. Sebagai contoh, the permissions system dalam kerangka kerja autentifikasi Django menggunakan model Permission dengan sebuah foreign key pada ContentType; ini membuat Permission mewakili konsep-konsep seperti "dapat menambah masukan blog" atau "dapat menghapus cerita berita".

ContentTypeManager

class ContentTypeManager

ContentType juga mempunyai pengelola penyesuaian, ContentTypeManager, yang menambahkan metode berikut:

clear_cache()

Bersihkan cache internal digunakan oleh ContentType untuk menjaga lintasan dari model-model untuk yang itu telah membuat instance ContentType. Anda mungkin tidak pernah butuh memanggil metode ini anda sendiri; Django akan memanggil itu secara otomatis ketika itu dibutuhkan.

get_for_id(id)

Pencarian ContentType berdasarkan ID. Sejak metode ini menggunakan cache dibagi yang sama seperti get_for_model(), itu lebih disukai untuk menggunakan metode ini terhadap ContentType.objects.get(pk=id) biasa

get_for_model(model, for_concrete_model=True)

Ambil antara sebuah kelas model atau sebuah instance dari model, dan kembalikan instance ContentType mewakili model itu. for_concrete_model=False mengizinkan mengambil ContentType dari model proxy.

get_for_models(*models, for_concrete_models=True)

Mengambil sejumlah variabel apapun dari kelas-kelas model, dan mengembalikan sebuah kamus memetakan kelas-kelas model pada instance ContentType mewakili mereka. for_concrete_models=False mengizinkan mengambil ContentType dari model proxy.

get_by_natural_key(app_label, model)

Mengembalikan instance ContentType secara unik dicirikan dengan label aplikasi yang diberikan dan nama model. Tujuan utama dari metode ini adalah mengizinkan obyek ContentType untuk diacukan melalui natural key1 selama deserialisasi.

The get_for_model() method is especially useful when you know you need to work with a ContentType but don't want to go to the trouble of obtaining the model's metadata to perform a manual lookup:

>>> from django.contrib.auth.models import User
>>> ContentType.objects.get_for_model(User)
<ContentType: user>

Hubungan umum

Menambahkan sebuah foreign key dari satu dari model anda sendiri pada ContentType mengizinkan model anda secara efektif mengikat diri sendiri ke kelas model lain, seperti dalam contoh dari model Permission diatas. Tetapi itu memungkinkan pergi satu langkah lebih jauh dan menggunakan ContentType untuk mengadakan hubungan umum sebenarnya (terkadang disebut "polimorfik") diantara model.

Sebagai contoh, itu dapat digunakan untuk sistem pe etiketan seperti itu:

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

    class Meta:
        indexes = [
            models.Index(fields=["content_type", "object_id"]),
        ]

Sebuah ForeignKey biasa dapat hanya "menunjuk" satu model lain, yang berarti bahwa jika model TaggedItem menggunakan sebuah ForeignKey itu akan harus memilih satu dan hanya satu model untuk menyimpan etiket-etiket. Aplikasi contenttype menyediakan jenis bidang khusus (GenericForeignKey) yang memecahkan ini dan mengizinkan hubungan dengan model apapun.

class GenericForeignKey

Terdapat tiga bagian untuk mengatur GenericForeignKey:

  1. Berikan model anda sebuah ForeignKey pada ContentType. Nama biasa untuk bidang ini adalah "content_type".
  2. Berikan model anda sebuah bidang yang dapat menyimpan nilai-nilai primary key dari model-model anda akan kaitkan. Untuk kebanyakan model, ini berarti PositiveIntegerField. Nama biasa untuk bidang ini adalah "object_id".
  3. Berikan model anda GenericForeignKey, dan lewatkan itu nama-nama dari dua bidang digambarkan diatas. Jika bidang-bidang ini bernama "content_type" dan "object_id", anda dapat mengabaikan ini --yaitu nama-nama bidang awalan GenericForeignKey akan mencari.

Unlike for the ForeignKey, a database index is not automatically created on the GenericForeignKey, so it's recommended that you use Meta.indexes to add your own multiple column index. This behavior may change in the future.

for_concrete_model

Jika False, bidang akan dapat mengacukan model-model proxy. Awalan adalah True. Ini mencerminkan argumen for_concrete_model pada get_for_model().

Kesesuaian jenis primary key

Bidang "object_id" tidak harus mempunyai jenis sama sebagai bidang primary key pada model-model terkait, tetapi nilai-nilai primary key harus dapat dipaksa ke jenis sama sebagai bidang "object_id" dengan metode get_db_prep_value() nya.

Sebagai contoh, jika anda ingin mengizinkan hubungan umum pada model-model dengan salah satu primary key IntegerField atau CharField, anda dapat menggunakan CharField untuk bidang "object_id" pada model anda karena integer dapat dipaksa menjadi string oleh get_db_prep_value().

Untuk keluwesan maksimal anda dapat menggunakan TextField yang tidak mempunyai panjang maksimal ditentukan, bagaimanapun ini mungkin mendatangkan denda penampilan yang berarti bergantung pada backend basisdata anda.

Tidak ada pemecahan satu-ukuran-cocok-semua untuk jenis bidang yang terbaik. Anda harus menilai model-model anda harapkan untuk ditunjuk dan menentukan pemecahan mana akan menjadi paling efektif untuk penggunaan kasus anda.

Menserialisasikan acuan pada obyek ContentType

Jika anda sedang menserialkan data(sebagai contoh, ketika membangkitkan fixtures) dari sebuah model yang menerapkan hubungan umum, anda harus mungkin menggunakan kunci alami pada secara unik mencirikan obyek ContentType terkait. Lihat natural keys1 and dumpdata --natural-foreign untuk informasi lebih.

This will enable an API similar to the one used for a normal ForeignKey; each TaggedItem will have a content_object field that returns the object it's related to, and you can also assign to that field or use it when creating a TaggedItem:

>>> from django.contrib.auth.models import User
>>> guido = User.objects.get(username="Guido")
>>> t = TaggedItem(content_object=guido, tag="bdfl")
>>> t.save()
>>> t.content_object
<User: Guido>

If the related object is deleted, the content_type and object_id fields remain set to their original values and the GenericForeignKey returns None:

>>> guido.delete()
>>> t.content_object  # returns None

Due to the way GenericForeignKey is implemented, you cannot use such fields directly with filters (filter() and exclude(), for example) via the database API. Because a GenericForeignKey isn't a normal field object, these examples will not work:

# This will fail
>>> TaggedItem.objects.filter(content_object=guido)
# This will also fail
>>> TaggedItem.objects.get(content_object=guido)

Juga, GenericForeignKey tidak muncul dalam ModelForm.

Membalikkan hubungan umum

class GenericRelation
related_query_name

Hubungan pada obyek terkait kembali ke obyek ini tidak ada secara awalan. Pengaturan related_query_name membuat sebuah hubungan dari obyek terkait kembali ke satu ini. Ini mengizinkan meminta dan menyaring dari obyek terkait.

Jika anda mengetahui model-model mana anda akan menggunakan paling sering, anda dapat juga menambahkan hubungan umum "reverse" untuk mengadakan sebuah tambahan API. Sebagai contoh:

from django.contrib.contenttypes.fields import GenericRelation
from django.db import models


class Bookmark(models.Model):
    url = models.URLField()
    tags = GenericRelation(TaggedItem)

Bookmark instances will each have a tags attribute, which can be used to retrieve their associated TaggedItems:

>>> 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>]>

You can also use add(), create(), or set() to create relationships:

>>> t3 = TaggedItem(tag="Web development")
>>> b.tags.add(t3, bulk=False)
>>> b.tags.create(tag="Web framework")
<TaggedItem: Web framework>
>>> b.tags.all()
<QuerySet [<TaggedItem: django>, <TaggedItem: python>, <TaggedItem: Web development>, <TaggedItem: Web framework>]>
>>> b.tags.set([t1, t3])
>>> b.tags.all()
<QuerySet [<TaggedItem: django>, <TaggedItem: Web development>]>

The remove() call will bulk delete the specified model objects:

>>> b.tags.remove(t3)
>>> b.tags.all()
<QuerySet [<TaggedItem: django>]>
>>> TaggedItem.objects.all()
<QuerySet [<TaggedItem: django>]>

The clear() method can be used to bulk delete all related objects for an instance:

>>> b.tags.clear()
>>> b.tags.all()
<QuerySet []>
>>> TaggedItem.objects.all()
<QuerySet []>

Menentukan GenericRelation dengan kumpulan related_query_name mengizinkan meminta dari obyek terkait:

tags = GenericRelation(TaggedItem, related_query_name="bookmark")

This enables filtering, ordering, and other query operations on Bookmark from TaggedItem:

>>> # Get all tags belonging to bookmarks containing `django` in the url
>>> TaggedItem.objects.filter(bookmark__url__contains="django")
<QuerySet [<TaggedItem: django>, <TaggedItem: python>]>

If you don't add the related_query_name, you can do the same types of lookups manually:

>>> bookmarks = Bookmark.objects.filter(url__contains="django")
>>> bookmark_type = ContentType.objects.get_for_model(Bookmark)
>>> TaggedItem.objects.filter(content_type__pk=bookmark_type.id, object_id__in=bookmarks)
<QuerySet [<TaggedItem: django>, <TaggedItem: python>]>

Sama seperti GenericForeignKey menerima nama-nama dari bidang content-type dan object-ID sebagai argumen, begitu juga GenericRelation; jika model yang mempunyai foreign key umum menggunakan nama bukan-awalan untuk bidang-bidang tersebut, anda harus melewatkan nama-nama dari bidang ketika mengatur sebuah GenericRelation untuk itu. Sebagai contoh, jika model TaggedItem mengacu pada diatas menggunakan bidang bernama content_type_fk dan object_primary_key untuk membuat foreign key umumnya, kemudian GenericRelation kembali ke itu akan butuh ditentukan seperti itu:

tags = GenericRelation(
    TaggedItem,
    content_type_field="content_type_fk",
    object_id_field="object_primary_key",
)

Catat juga, bahwa jika anda menghapus sebuah obyek yang mempunyai sebuah GenericRelation, obyek apapun yang mempunyai GenericForeignKey menunjuk ke itu akan dihapus juga. Dalam contoh diatas, ini berarti bahwa jika sebuah obyek Bookmark dihapus, obyek TaggedItem apapun menunjuk pada itu akan dihapus pada waktu yang sama.

Unlike ForeignKey, GenericForeignKey does not accept an on_delete argument to customize this behavior; if desired, you can avoid the cascade-deletion by not using GenericRelation, and alternate behavior can be provided via the pre_delete signal.

Hubungan umum dan pengumpulan

Django's database aggregation API works with a GenericRelation. For example, you can find out how many tags all the bookmarks have:

>>> Bookmark.objects.aggregate(Count("tags"))
{'tags__count': 3}

Hubungan umum di formulir

Modul django.contrib.contenttypes.forms menyediakan:

class BaseGenericInlineFormSet
generic_inlineformset_factory(model, form=ModelForm, formset=BaseGenericInlineFormSet, ct_field='content_type', fk_field='object_id', fields=None, exclude=None, extra=3, can_order=False, can_delete=True, max_num=None, formfield_callback=None, validate_max=False, for_concrete_model=True, min_num=None, validate_min=False, absolute_max=None, can_delete_extra=True)

Mengembalikan GenericInlineFormSet menggunakan modelformset_factory().

Anda harus menyediakan ct_field dan fk_field jika mereka berbeda dari awalan, content_type dan object_id masing-masing. Parameter lain adalah mirip ke yang didokumentasi di modelformset_factory() dan inlineformset_factory().

Argumen for_concrete_model berhubungan ke argumen for_concrete_model pada GenericForeignKey.

Hubungan umum di admin

Modul django.contrib.contenttypes.admin menyediakan GenericTabularInline dan GenericStackedInline (subkelas-subkelas dari GenericInlineModelAdmin)

Kelas-kelas dan fungsi-fungsi ini mengadakan penggunaan hubungan umum di formulir dan admin. Lihat dokumentasi model formset dan admin untuk informasi lebih.

class GenericInlineModelAdmin

Kelas GenericInlineModelAdmin mewarisi semua sifat-sifat dari sebuah kelas InlineModelAdmin. Bagaimanapun, itu menambahkan sebuah pasang dari itu sendiri untuk bekerja dengan hubungan umum:

ct_field

Nama dari bidang foreign key ContentType pada model. Awalan pada content_type.

ct_fk_field

Nama dari bidang integer yang mewakili ID dari obyek terkait. Awalan pada object_id.

class GenericTabularInline
class GenericStackedInline

Subkelas-subkelas dari GenericInlineModelAdmin dengan tata letak bertumpuk dan datar, masing-masing.