Jadi, Anda ingin menggunakan kerangka Jenis Konten pada pekerjaan Anda?
Mulailah dengan bertanya pada diri sendiri pertanyaan ini: "Apakah ada dari model ini yang perlu dikaitkan dengan cara yang sama dengan model lain dan / atau akankah saya menggunakan kembali hubungan ini dengan cara yang tidak terduga nanti di ujung jalan?" Alasan mengapa kami mengajukan pertanyaan ini adalah karena inilah yang paling baik dilakukan oleh kerangka Jenis Konten: ini menciptakan hubungan generik antar model. Blah blah, mari selami beberapa kode dan lihat apa yang saya maksud.
# ourapp.models
from django.conf import settings
from django.db import models
# Assign the User model in case it has been "swapped"
User = settings.AUTH_USER_MODEL
# 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)
picture = models.ForeignKey(Picture)
Oke, jadi kami punya cara untuk membuat hubungan ini secara teoritis. Namun, sebagai programmer Python, kecerdasan atasan Anda memberi tahu Anda ini menyebalkan dan Anda bisa berbuat lebih baik. Tinggi lima!
Masukkan kerangka Jenis Konten!
Nah, sekarang kita akan melihat lebih dekat pada model kita dan mengolahnya menjadi lebih "dapat digunakan kembali" dan intuitif. Mari kita mulai dengan menyingkirkan dua kunci asing pada Comment
model kita dan menggantinya dengan a GenericForeignKey
.
# ourapp.models
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
...
class Comment(models.Model):
author = models.ForeignKey(User)
body = models.TextField(blank=True)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey()
Jadi apa yang terjadi? Yah, kami masuk dan menambahkan kode yang diperlukan untuk memungkinkan hubungan generik dengan model lain. Perhatikan bagaimana ada lebih dari sekedar GenericForeignKey
, tetapi juga ForeignKey
untuk ContentType
dan PositiveIntegerField
untuk object_id
. Bidang-bidang ini untuk memberi tahu Django jenis objek yang terkait dengan ini dan apa id untuk objek itu. Pada kenyataannya, ini masuk akal karena Django akan membutuhkan keduanya untuk mencari objek terkait ini.
Yah, itu tidak seperti Python ... itu agak jelek!
Anda mungkin mencari kode yang ketat, bersih, dan intuitif yang membuat Guido van Rossum bangga. Aku mengerti kamu Mari kita lihat GenericRelation
lapangan sehingga kita bisa membungkuk pada ini.
# ourapp.models
from django.contrib.contenttypes.fields import 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)
comments = GenericRelation('Comment')
class Picture(models.Model):
author = models.ForeignKey(User)
image = models.ImageField()
caption = models.TextField(blank=True)
comments = GenericRelation('Comment')
Bam! Sama seperti itu Anda dapat bekerja dengan Komentar untuk dua model ini. Bahkan, mari kita lakukan dan lakukan itu di shell kita (ketik python manage.py shell
dari direktori proyek Django Anda).
>>> from django.contrib.auth import get_user_model
>>> from ourapp.models import Picture, Post
# We use get_user_model() since we are referencing directly
User = get_user_model()
# Grab our own User object
>>> me = User.objects.get(username='myusername')
# Grab the first of our own pictures so we can comment on it
>>> pic = Picture.objects.get(author=me)
# Let's start making a comment for our own picture
>>> pic.comments.create(author=me, body="Man, I'm cool!")
# Let's go ahead and retrieve the comments for this picture now
>>> pic.comments.all()
[<Comment: "Man, I'm cool!">]
# Same for Post comments
>>> post = Post.objects.get(author=me)
>>> post.comments.create(author=me, body="So easy to comment now!")
>>> post.comments.all()
[<Comment: "So easy to comment now!"]
Sesederhana itu.
Apa implikasi praktis lain dari hubungan "generik" ini?
Kunci asing generik memungkinkan hubungan yang kurang mengganggu antara berbagai aplikasi. Sebagai contoh, katakanlah kita menarik model Komentar keluar ke aplikasi itu sendiri bernama chatterly
. Sekarang kami ingin membuat aplikasi lain bernamanoise_nimbus
mana orang menyimpan musik mereka untuk dibagikan kepada orang lain.
Bagaimana jika kita ingin menambahkan komentar ke lagu-lagu itu? Kita bisa menggambar relasi generik:
# noise_nimbus.models
from django.conf import settings
from django.contrib.contenttypes.fields import GenericRelation
from django.db import models
from chatterly.models import Comment
# For a third time, we take the time to ensure custom Auth isn't overlooked
User = settings.AUTH_USER_MODEL
# Create your models here
class Song(models.Model):
'''
A song which can be commented on.
'''
file = models.FileField()
author = models.ForeignKey(User)
title = models.CharField(max_length=75)
slug = models.SlugField(unique=True)
description = models.TextField(blank=True)
comments = GenericRelation(Comment)
Saya harap kalian menemukan ini membantu karena saya akan senang menemukan sesuatu yang menunjukkan kepada saya aplikasi GenericForeignKey
dan GenericRelation
bidang yang lebih realistis .
Apakah ini terlalu bagus untuk menjadi kenyataan?
Seperti apa pun dalam hidup, ada pro dan kontra. Setiap kali Anda menambahkan lebih banyak kode dan abstraksi lebih banyak, proses yang mendasarinya menjadi lebih berat dan sedikit lebih lambat. Menambahkan hubungan umum dapat menambahkan sedikit peredam kinerja meskipun faktanya itu akan mencoba dan smart cache hasilnya. Secara keseluruhan, ini tergantung pada apakah kebersihan dan kesederhanaan melebihi biaya kinerja yang kecil. Bagi saya, jawabannya adalah sejuta kali ya.
Ada lebih banyak kerangka kerja Jenis Konten daripada yang saya tampilkan di sini. Ada tingkat granularitas dan penggunaan verbose yang lebih banyak, tetapi untuk rata-rata individu, ini adalah bagaimana Anda akan menggunakannya 9 dari 10 kali menurut saya.
Berhubungan dengan generik (?) Berhati-hatilah!
Peringatan yang agak besar adalah bahwa ketika Anda menggunakan GenericRelation
, jika model yang telah GenericRelation
diterapkan ( Picture
) dihapus, semua objek terkait ( Comment
) juga akan dihapus. Atau setidaknya pada saat penulisan ini.