Django içerik türleri tam olarak nasıl çalışır?


154

Django'nun içerik türleri kavramını kavramakta gerçekten zorlanıyorum. Çok hilekar ve nihayetinde Python'un işleri yapma eğilimine karşı geliyor. Bununla birlikte, Django'yu kullanacaksam, çerçevenin sınırları içinde çalışmam gerekiyor.

Bu yüzden buraya, bir içerik türünün nasıl çalıştığına ve onu nasıl uygulayacağınıza dair pratik bir gerçek dünya örneği verebilir mi diye merak ediyorum. İncelediğim hemen hemen tüm eğitimler (çoğunlukla bloglarda) konsepti kapsayan harika bir iş çıkarmıyor. Django belgelerinin kaldığı yerden devam ediyor gibi görünüyorlar (hiçbir yere benzemiyor).


6
İçerik türlerinin polimorfizm gibi bir şey olduğuna inanıyorum (birisi beni düzeltir), projeniz birçok farklı biçime sahip olabilecek modellere sahip olmaya başladığında sizin elinizde bir araç haline gelecektir. Belgelerdeki etiket örneği oldukça basittir, Öğeleri Etiketleyebilmek istiyorsunuz, ancak ne tür Öğeler olduklarına özel olmak istemiyorsunuz, sonuçta bir Etiket, gönderileri, sayfaları, kullanıcıları, Ürün:% s. İçerik türlerinin kullanımıyla, ilgili modelin tam olarak ne olduğunu bilmenize gerek kalmadan çeşitli farklı uygulamalarla ilişkiler oluşturabilirsiniz.
petkostas

1
Tamam, benim için net olmayan "TaggedItem" adında bir sınıf oluşturdular. O zaman TaggedItem'in bir yer tutucu "köprü" sınıfı olup olmadığından emin değildim. Benim doğal eğilimim, "terim" adlı özelliğe sahip "Etiket" gibi bir şey olurdu.
Chris Shelton

Yanıtlar:


322

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.

# 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)

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. CommentModelimizdeki iki yabancı anahtardan kurtularak başlayalım ve bunları bir 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()

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 ForeignKeykarşı ContentTypeve PositiveIntegerFieldiç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 GenericRelationSahaya bakalım, böylece buna güzel bir selam verelim .

# 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! 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 shellDjango proje dizininizden yazın).

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

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:

# 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)

Umarım bunu yararlı bulmuşsunuzdur, çünkü bana GenericForeignKeyve GenericRelationalanları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, GenericRelationuygulanan ( Picture) model silinirse, ilgili tüm ( Comment) nesnelerin de silineceğidir. Ya da en azından bu yazı yazıldığı sırada.


13
Yani kullanırsanız GenericRelationiçinde Postve Picturesonra kullanıma gerek yok object_id, content_typeve content_objectde Comment?
avi

9
İçerik türü çerçevesinin bu kadar net bir tanımının resmi Django belgelerinde bir yerde olması güzel olurdu. Bana gelince, bu çerçevenin ne yaptığını ancak bu limanı okuduktan sonra anladım. Teşekkür ederim.
prokher

2
biraz geç ... ama içerik türü çerçevesini kullandığınızda uygulamanızın düzgün ölçeklenemeyebileceğini duydum. Biri bana bunun doğru mu yoksa bir aldatmaca mı olduğunu söyleyebilir mi?
Karan Kumar

1
Programlamadaki her şeyde olduğu gibi, Karan, cevap her zaman "duruma bağlıdır". İçerik türlerini kullanın derdim. Bu, tablo odaklı bir SQL sisteminin bazı katı temellerini atlamak için bir tür "uzlaşmadır". Uygulamanızı zamanından önce optimize etmeyin! Django yolunuzdan çekilmede en iyisidir, böylece her zaman istediğiniz yeni nesil uygulamayı yazabilirsiniz: özelliklerini kendi yararınıza kullanın!
Chris Shelton

2
Karan, bazı gerçekler var. Kullanıcılar için bildirimleri izleyen bir uygulama üzerinde çalışıyorum. Her bildirimin, sakladığımız diğer bazı içerik türleriyle bir GenericForeignKey ilişkisi vardır. Bir kullanıcı bildirimleri her görüntülediğinde, ORM ilgili tüm içeriği almak için N sorgu yayınlar. Pek ideal değil.
Travis Mehlinger

-2

Pekala, sorunuzun doğrudan cevabı: (django kaynak kodundan): Ortam Türleri RFC 2616, bölüm 3.7'ye göre ayrıştırılıyor.

Bu, 'Content-type' httpd başlığını okuduğunu / değiştirmenize izin verdiğini / geçtiğini söylemenin gözyaşları yoldur .

Ancak, daha pratik bir kullanım örneği istiyorsunuz. Size 2 önerim var:

1: bu kodu inceleyin

def index(request):
   media_type='text/html'
   if request.META.has_key('CONTENT_TYPE'):
      media_type = request.META['CONTENT_TYPE'].split(';')[0]

   if media_type.lower() == 'application/json':
      return HttpResponse("""{ "ResponseCode": "Success"}""", content_type="application/json; charset=UTF-8")

   return HttpResponse("<h1>regular old joe</h1>");

2: Django'nun python olduğunu ve bu nedenle python topluluğunun gücünü kullandığını unutmayın. Django için 2 harika RESTFul eklentisi var. Yani, tavşanın bütününün ne kadar derine gittiğini görmek istiyorsanız, kontrol edebilirsiniz.

Özellikle 'farklı içerik / türler üzerinde hareket etme' konusunu ele alacak django-rest-framework eğitimini incelemenizi öneririm. Not: Restful API'leri 'version' olarak kullanmak yaygın bir uygulamadır .


1
Bahsettiği şey bu mu? veya içerik türleri
petkostas

1
Evet, içerik türleri çerçevesinden bahsediyordum. Kendimi iletmek için yeterince iyi bir iş çıkarmamış olabilirim. Ne olursa olsun yanıtı takdir ediyorum. Değeri ne olursa olsun, sorum bu olsaydı, onu parkın dışına
Chris Shelton
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.