Làm thế nào chính xác các loại nội dung Django hoạt động?


148

Tôi thực sự gặp khó khăn trong việc nắm bắt khái niệm về các loại nội dung của Django. Nó cảm thấy rất hackish và cuối cùng, chống lại cách Python có xu hướng làm mọi thứ. Điều đó đang được nói, nếu tôi sẽ sử dụng Django thì tôi phải làm việc trong giới hạn của khung.

Vì vậy, tôi đến đây tự hỏi liệu có ai có thể đưa ra một ví dụ thực tế thực tế về cách thức một loại nội dung hoạt động và cách bạn sẽ triển khai nó không. Hầu như tất cả các hướng dẫn (chủ yếu trên blog) tôi đã xem xét không làm một công việc tuyệt vời thực sự bao gồm các khái niệm. Họ dường như chọn nơi tài liệu Django để lại (có vẻ như không có gì).


5
Tôi tin rằng (ai đó đã sửa cho tôi nếu tôi sai) rằng các loại Nội dung giống như đa hình, nó sẽ trở thành một công cụ trong tay bạn khi dự án của bạn bắt đầu có các mô hình có thể có nhiều dạng khác nhau. Ví dụ về thẻ trong tài liệu khá đơn giản, bạn muốn có thể Gắn thẻ các mục, nhưng bạn không muốn cụ thể về loại Mục nào, sau tất cả, Thẻ có thể hỗ trợ, bài đăng, trang, người dùng, các sản phẩm. Với việc sử dụng các loại Nội dung, bạn có thể tạo các mối quan hệ để triển khai khác nhau mà không cần phải biết chính xác mô hình liên quan là gì.
petkostas

1
Được rồi, vì vậy nơi tôi bị vấp ngã là họ đã tạo ra một lớp có tên "TaggedItem" không rõ ràng với tôi. Tôi không chắc chắn nếu TaggedItem là lớp "cầu nối" giữ chỗ. Xu hướng tự nhiên của tôi sẽ là một cái gì đó như "Tag" với một tài sản có tên là "hạn".
Chris Shelton

Câu trả lời:


307

Vì vậy, bạn muốn sử dụng khung Kiểu nội dung cho công việc của bạn?

Bắt đầu bằng cách tự hỏi mình câu hỏi này: "Có bất kỳ mô hình nào trong số những mô hình này cần phải liên quan theo cùng một cách với các mô hình khác không và / hoặc tôi sẽ sử dụng lại các mối quan hệ này theo những cách chưa được giải quyết sau này?" Lý do tại sao chúng tôi đặt câu hỏi này là vì đây là khung công tác Kiểu nội dung tốt nhất: nó tạo ra các mối quan hệ chung giữa các mô hình. Blah blah, hãy đi sâu vào một số mã và xem ý tôi là gì.

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

Được rồi, vì vậy chúng tôi có một cách để lý thuyết tạo mối quan hệ này. Tuy nhiên, là một lập trình viên Python, trí tuệ vượt trội của bạn đang nói với bạn điều này thật tệ và bạn có thể làm tốt hơn. Đập tay!

Nhập khung loại nội dung!

Chà, bây giờ chúng ta sẽ xem xét kỹ các mô hình của chúng ta và làm lại chúng để "tái sử dụng" và trực quan hơn. Hãy bắt đầu bằng cách loại bỏ hai khóa ngoại trên Commentmô hình của chúng tôi và thay thế chúng bằng một 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()

Vậy chuyện gì đã xảy ra? Vâng, chúng tôi đã đi vào và thêm mã cần thiết để cho phép có mối quan hệ chung với các mô hình khác. Thông báo như thế nào có nhiều hơn chỉ là một GenericForeignKey, mà còn là một ForeignKeyđến ContentTypevà một PositiveIntegerFieldcho object_id. Các trường này là để cho Django biết loại đối tượng này có liên quan đến và id là gì cho đối tượng đó. Trong thực tế, điều này có ý nghĩa bởi vì Django sẽ cần cả hai để tra cứu các đối tượng liên quan này.

Chà, nó không giống Python lắm ... xấu quá!

Có lẽ bạn đang tìm kiếm mã trực quan, không tì vết, trực quan sẽ khiến Guido van Rossum tự hào. Tôi hiểu bạn Chúng ta hãy nhìn vào GenericRelationlĩnh vực này để chúng ta có thể đặt một cái cung đẹp trên này.

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

Bế! Cũng giống như vậy, bạn có thể làm việc với các Nhận xét cho hai mô hình này. Trong thực tế, hãy tiếp tục và làm điều đó trong vỏ của chúng tôi (nhập python manage.py shelltừ thư mục dự án Django của bạ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!"]

Nó đơn giản mà.

Ý nghĩa thực tế khác của các mối quan hệ "chung chung" này là gì?

Khóa ngoại chung cho phép mối quan hệ ít xâm phạm hơn giữa các ứng dụng khác nhau. Ví dụ: giả sử chúng tôi đã kéo mô hình Nhận xét ra thành ứng dụng riêng có tên chatterly. Bây giờ chúng tôi muốn tạo một ứng dụng khác có tên là noise_nimbusnơi mọi người lưu trữ nhạc của họ để chia sẻ với người khác.

Nếu chúng ta muốn thêm ý kiến ​​cho những bài hát đó thì sao? Chà, chúng ta chỉ có thể vẽ một mối quan hệ chung chung:

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

Tôi hy vọng các bạn thấy điều này hữu ích vì tôi rất thích đã bắt gặp một cái gì đó cho tôi thấy ứng dụng GenericForeignKeyGenericRelationlĩnh vực thực tế hơn .

Điều này là quá tốt để là sự thật?

Như với bất cứ điều gì trong cuộc sống, có những ưu và nhược điểm. Bất cứ khi nào bạn thêm nhiều mã hơn và trừu tượng hơn, các quy trình cơ bản trở nên nặng hơn và chậm hơn một chút. Thêm các mối quan hệ chung có thể thêm một chút bộ giảm hiệu suất mặc dù thực tế nó sẽ thử và thông minh lưu trữ kết quả của nó. Nói chung, vấn đề là sự sạch sẽ và đơn giản có cao hơn chi phí hiệu suất nhỏ hay không. Đối với tôi, câu trả lời là một triệu lần có.

Có nhiều khung công tác Kiểu nội dung hơn tôi đã hiển thị ở đây. Có một mức độ chi tiết và mức độ sử dụng dài dòng hơn, nhưng đối với cá nhân trung bình, đây là cách bạn sẽ sử dụng nó 9 trên 10 lần theo ý kiến ​​của tôi.

Quan hệ chung (?) Hãy coi chừng!

Một cảnh báo khá lớn là khi bạn sử dụng a GenericRelation, nếu mô hình đã GenericRelationáp dụng ( Picture) bị xóa, tất cả các Commentđối tượng ( ) có liên quan cũng sẽ bị xóa. Hoặc ít nhất là tại thời điểm viết bài này.


11
Vì vậy, nếu tôi sử dụng GenericRelationtrong PostPicturesau đó tôi không cần phải sử dụng object_id, content_typecontent_objecttrong Comment?
avi

5
Sẽ thật tuyệt nếu có mô tả rõ ràng như vậy về khung nội dung ở đâu đó trong tài liệu chính thức của Django. Đối với tôi, tôi đã nhận ra những gì khung này chỉ làm sau khi đọc cổng này. Cảm ơn bạn.
prokher 2/2/2016

2
hơi muộn ... nhưng tôi đã nghe nói rằng sử dụng khung loại nội dung, ứng dụng của bạn có thể không mở rộng đúng cách. ai đó có thể vui lòng cho tôi biết nếu điều này là đúng hay một trò lừa bịp?
Karan Kumar

1
Như với mọi thứ trong lập trình, Karan, câu trả lời luôn là "nó phụ thuộc". Tôi sẽ nói sử dụng các loại nội dung. Đó là một "sự thỏa hiệp" của các loại để bỏ qua một số nguyên tắc cơ bản cứng nhắc của một hệ thống SQL định hướng bảng. Đừng sớm tối ưu hóa ứng dụng của bạn! Django là tốt nhất để thoát khỏi cách của bạn để bạn có thể viết ứng dụng thế hệ tiếp theo mà bạn luôn muốn: sử dụng các tính năng của nó để lợi thế của bạn!
Chris Shelton

2
Karan, có một số sự thật với nó. Tôi đang làm việc trên một ứng dụng theo dõi thông báo cho người dùng. Mỗi thông báo có mối quan hệ GenericForeignKey với một số loại nội dung khác mà chúng tôi lưu trữ. Mỗi khi người dùng xem thông báo, ORM sẽ đưa ra N truy vấn để nhận tất cả nội dung liên quan. Khó lý tưởng.
Travis Mehlinger

-2

Vâng, câu trả lời trực tiếp cho câu hỏi của bạn: (từ mã nguồn django) là: Phân tích kiểu phương tiện theo RFC 2616, phần 3.7.

Đó là cách nói hay mà nó đọc / cho phép bạn sửa đổi / chuyển dọc theo tiêu đề httpd 'Kiểu nội dung' .

Tuy nhiên, bạn đang yêu cầu một ví dụ sử dụng thực tế hơn. Tôi có 2 gợi ý cho bạn:

1: kiểm tra mã này

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: hãy nhớ django là python, và như vậy nó mang sức mạnh của cộng đồng python. Có 2 plugin RESTFul tuyệt vời cho django. Vì vậy, nếu bạn muốn xem toàn bộ con thỏ đi sâu như thế nào, bạn có thể kiểm tra.

Tôi khuyên bạn nên xem qua hướng dẫn django-rest-framework sẽ đề cập đến 'hành động trên các nội dung / loại khác nhau' một cách cụ thể. Lưu ý: Thông thường sử dụng tiêu đề loại nội dung để API nghỉ ngơi của 'phiên bản' .


1
Có phải đó là những gì anh ấy đang đề cập? hoặc vào khung nội dung?: docs.djangoproject.com/en/dev/ref/contrib/contenttypes
petkostas

1
Vâng, tôi đã đề cập đến khung loại nội dung. Tôi có thể đã không làm một công việc đủ tốt để truyền đạt bản thân mình. Tôi đánh giá cao phản ứng bất kể. Vì giá trị của nó, nếu đó là câu hỏi của tôi, bạn sẽ đánh bật nó ra khỏi công viên =)
Chris Shelton
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.