Yani işinizde İçerik Türleri çerçevesini mi kullanmak istiyorsunuz?
Kendinize şu soruyu sorarak başlayın: "Bu modellerden herhangi birinin diğer modellerle aynı şekilde ilişkili olması gerekiyor mu ve / veya bu ilişkileri daha sonra beklenmedik şekillerde yeniden kullanacak mıyım?" Bu soruyu sormamızın nedeni, İçerik Türleri çerçevesinin en iyi yaptığı şeydir: modeller arasında genel ilişkiler oluşturur. Blah blah, hadi bazı kodlara dalalım ve ne demek istediğimi görelim.
from django.conf import settings
from django.db import models
User = settings.AUTH_USER_MODEL
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)
Tamam, bu ilişkiyi teorik olarak yaratmanın bir yolunu bulduk. Ancak, bir Python programcısı olarak, üstün zekanız size bunun berbat olduğunu ve daha iyisini yapabileceğinizi söylüyor. Çak beşlik!
İçerik Türleri çerçevesine girin!
Pekala, şimdi modellerimize daha yakından bakacağız ve onları daha "yeniden kullanılabilir" ve sezgisel olacak şekilde yeniden çalışacağız. Comment
Modelimizdeki iki yabancı anahtardan kurtularak başlayalım ve bunları bir GenericForeignKey
.
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()
Peki ne oldu? İçeri girdik ve diğer modellerle genel bir ilişkiye izin vermek için gerekli kodu ekledik. Bildirim sadece daha var nasıl GenericForeignKey
, aynı zamanda bir ForeignKey
karşı ContentType
ve PositiveIntegerField
için object_id
. Bu alanlar, Django'ya bunun ne tür bir nesneyle ilişkili olduğunu ve bu nesne için kimliğin ne olduğunu söylemek içindir. Gerçekte, bu mantıklıdır çünkü Django'nun bu ilgili nesneleri aramak için her ikisine de ihtiyacı olacaktır.
Pekala, bu Python'a benzemiyor ... biraz çirkin!
Muhtemelen Guido van Rossum'u gururlandıracak hava geçirmez, lekesiz, sezgisel kod arıyorsunuz . Seni anlıyorum GenericRelation
Sahaya bakalım, böylece buna güzel bir selam verelim .
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! Tıpkı bu iki model için Yorumlar ile çalışabileceğiniz gibi. Aslında, devam edelim ve bunu kabuğumuzda yapalım ( python manage.py shell
Django proje dizininizden yazın).
>>> from django.contrib.auth import get_user_model
>>> from ourapp.models import Picture, Post
User = get_user_model()
>>> me = User.objects.get(username='myusername')
>>> pic = Picture.objects.get(author=me)
>>> pic.comments.create(author=me, body="Man, I'm cool!")
>>> pic.comments.all()
[<Comment: "Man, I'm cool!">]
>>> 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!"]
Bu kadar basit.
Bu "genel" ilişkilerin diğer pratik sonuçları nelerdir?
Genel yabancı anahtarlar, çeşitli uygulamalar arasında daha az müdahaleci ilişkilere izin verir. Örneğin, Yorum modelini adlı kendi uygulamasına çektiğimizi varsayalım chatterly
. Şimdi noise_nimbus
, başkalarıyla paylaşmak için insanların müziklerini depoladıkları başka bir uygulama oluşturmak istiyoruz .
Ya bu şarkılara yorum eklemek istersek? Pekala, genel bir ilişki çizebiliriz:
from django.conf import settings
from django.contrib.contenttypes.fields import GenericRelation
from django.db import models
from chatterly.models import Comment
User = settings.AUTH_USER_MODEL
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)
Umarım bunu yararlı bulmuşsunuzdur, çünkü bana GenericForeignKey
ve GenericRelation
alanlarının daha gerçekçi uygulamasını gösteren bir şeyle karşılaşmayı çok isterdim .
Bu gerçek olmak için çok mu iyi?
Hayattaki her şeyde olduğu gibi, artıları ve eksileri var. Ne zaman daha fazla kod ve daha fazla soyutlama eklediğinizde, temeldeki işlemler daha ağır ve biraz daha yavaş hale gelir. Genel ilişkiler eklemek, sonuçlarını önbelleğe almayı deneyecek ve akıllıca önbelleğe almasına rağmen, bir miktar performans sönümleyici ekleyebilir. Sonuç olarak, önemli olan temizlik ve basitliğin küçük performans maliyetlerinden daha ağır basıp basmamasına bağlıdır. Benim için cevap milyonlarca kez evet.
İçerik Türleri çerçevesinde burada gösterdiğimden daha fazlası var. Tam bir ayrıntı düzeyi ve daha ayrıntılı kullanım var, ancak ortalama bir kişi için, bence onu 10 defadan 9'unu nasıl kullanacaksınız.
Genel ilişkilendiriciler (?) Dikkatli olun!
Oldukça büyük bir uyarı , a kullandığınızda GenericRelation
, GenericRelation
uygulanan ( Picture
) model silinirse, ilgili tüm ( Comment
) nesnelerin de silineceğidir. Ya da en azından bu yazı yazıldığı sırada.