คุณต้องการใช้เฟรมเวิร์กประเภทเนื้อหาในงานของคุณหรือไม่?
เริ่มต้นด้วยการถามตัวเองด้วยคำถามนี้: "โมเดลใด ๆ เหล่านี้จำเป็นต้องเกี่ยวข้องในแบบเดียวกันกับโมเดลอื่น ๆ และ / หรือฉันจะนำความสัมพันธ์เหล่านี้กลับมาใช้ซ้ำในแบบที่ไม่เป็นไปตามถนนหรือไม่" เหตุผลที่เราถามคำถามนี้เป็นเพราะนี่คือสิ่งที่กรอบประเภทเนื้อหาดีที่สุด: มันสร้างความสัมพันธ์ทั่วไประหว่างแบบจำลอง Blah blah ลองดำดิ่งลงไปในโค้ดและดูว่าฉันหมายถึงอะไร
# 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)
ตกลงดังนั้นเราจึงมีวิธีในการสร้างความสัมพันธ์นี้ในทางทฤษฎี อย่างไรก็ตามในฐานะโปรแกรมเมอร์ Python สติปัญญาระดับสูงของคุณกำลังบอกคุณเรื่องนี้และคุณสามารถทำได้ดีกว่า แตะมือ!
ใส่เฟรมเวิร์กประเภทเนื้อหา!
ทีนี้เราจะมาดูแบบจำลองของเราอย่างใกล้ชิดและนำมันกลับมาใช้ใหม่เพื่อให้สามารถ "นำกลับมาใช้ใหม่" และใช้งานง่ายยิ่งขึ้น ขอเริ่มต้นโดยการกำจัดของสองปุ่มต่างประเทศของเรารูปแบบและแทนที่พวกเขาด้วยComment
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()
แล้วเกิดอะไรขึ้น? เราเข้าไปข้างในและเพิ่มรหัสที่จำเป็นเพื่ออนุญาตให้มีความสัมพันธ์ทั่วไปกับรุ่นอื่น ๆ แจ้งให้ทราบว่ามีมากกว่าเพียงGenericForeignKey
แต่ยัง ForeignKey
ไปContentType
และPositiveIntegerField
สำหรับobject_id
สำหรับฟิลด์เหล่านี้มีไว้เพื่อบอก Django ว่าวัตถุชนิดนี้เกี่ยวข้องกับอะไรและ id นั้นสำหรับวัตถุนั้น ในความเป็นจริงสิ่งนี้สมเหตุสมผลเนื่องจาก Django ต้องการทั้งสองเพื่อค้นหาวัตถุที่เกี่ยวข้องเหล่านี้
นั่นไม่เหมือนงูหลาม ... มันช่างน่าเกลียด!
คุณอาจกำลังมองหารหัสที่แน่นหนาไร้อากาศและใช้งานง่ายซึ่งจะทำให้Guido van Rossumภูมิใจ ฉันเข้าใจคุณ ลองดูที่GenericRelation
ทุ่งนาเพื่อที่เราจะได้น้อมคันนี้
# 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')
ปัง! เช่นเดียวกับที่คุณสามารถทำงานกับความคิดเห็นสำหรับทั้งสองรุ่น ในความเป็นจริงเราจะไปข้างหน้าและทำในเปลือกของเรา (พิมพ์python manage.py shell
จากไดเรกทอรีโครงการ Django ของคุณ)
>>> 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!"]
มันง่ายมาก
อะไรคือความหมายเชิงปฏิบัติอื่น ๆ ของความสัมพันธ์ "ทั่วไป" เหล่านี้?
คีย์ต่างประเทศทั่วไปช่วยให้มีความสัมพันธ์ที่ล่วงล้ำน้อยลงระหว่างแอปพลิเคชันต่างๆ ตัวอย่างเช่นสมมติว่าเราดึงรูปแบบการแสดงความคิดเห็นออกมาใน app chatterly
ของตัวเองชื่อ ตอนนี้เราต้องการสร้างแอปพลิเคชันอื่นที่มีชื่อnoise_nimbus
ซึ่งผู้คนเก็บเพลงไว้เพื่อแบ่งปันกับผู้อื่น
หากเราต้องการเพิ่มความคิดเห็นให้กับเพลงเหล่านั้น ทีนี้เราสามารถวาดความสัมพันธ์ทั่วไป:
# 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)
ฉันหวังว่าพวกคุณจะพบว่าสิ่งนี้มีประโยชน์เพราะฉันอยากจะพบสิ่งที่แสดงให้ฉันเห็นว่าแอปพลิเคชันGenericForeignKey
และGenericRelation
ฟิลด์ที่สมจริงยิ่งขึ้น
สิ่งนี้ดีเกินกว่าที่จะเป็นจริงหรือไม่?
เช่นเดียวกับสิ่งใดในชีวิตมีข้อดีและข้อเสีย เมื่อใดก็ตามที่คุณเพิ่มรหัสและนามธรรมมากขึ้นกระบวนการพื้นฐานจะหนักขึ้นและช้าลงเล็กน้อย การเพิ่มความสัมพันธ์ทั่วไปสามารถเพิ่มตัวหน่วงประสิทธิภาพเล็กน้อยแม้ว่าจะพยายามและแคชผลลัพธ์อย่างชาญฉลาด สรุปแล้วก็คือว่าความสะอาดและความเรียบง่ายมีค่ามากกว่าประสิทธิภาพการทำงานเล็กน้อยหรือไม่ สำหรับฉันคำตอบคือล้านครั้งใช่
มีกรอบเนื้อหาประเภทมากกว่าที่ฉันแสดงที่นี่ มีทั้งระดับละเอียดและการใช้อย่างละเอียดมากขึ้น แต่สำหรับคนทั่วไปนี่คือวิธีที่คุณจะใช้ 9 ใน 10 ครั้งในความคิดของฉัน
ความสัมพันธ์ทั่วไป (?) ระวัง!
ข้อแม้ที่ค่อนข้างใหญ่คือเมื่อคุณใช้ a GenericRelation
หากรูปแบบที่มีการGenericRelation
ใช้ ( Picture
) ถูกลบComment
วัตถุที่เกี่ยวข้องทั้งหมด ( ) จะถูกลบเช่นกัน หรืออย่างน้อย ณ เวลาที่เขียนนี้