それで、あなたはあなたの仕事でコンテンツタイプフレームワークを使いたいですか?
「これらのモデルのいずれかを他のモデルと同じように関連付ける必要がありますか、そして/または将来、予期しない方法でこれらの関係を再利用しますか?」私たちがこの質問をする理由は、これがコンテンツタイプフレームワークが最も得意とすることであり、モデル間に一般的な関係を作成します。何とか何とか、いくつかのコードに飛び込んで、私が何を意味するのか見てみましょう。
# 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
モデルの2つの外部キーを削除して、それらをに置き換えます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はこれらの関連オブジェクトを検索するために両方が必要になるため、実際にはこれは理にかなっています。
まあ、それはあまりPython風ではありません...ちょっと醜いです!
おそらく、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')
バム!同様に、これら2つのモデルのコメントを操作できます。実際、それをシェルで実行してみましょう(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!"]
とても簡単です。
これらの「一般的な」関係の他の実際的な意味は何ですか?
ジェネリック外部キーを使用すると、さまざまなアプリケーション間の煩わしい関係を減らすことができます。たとえば、Commentモデルをという独自のアプリに引き出したとしましょう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
フィールドのより現実的なアプリケーションを示す何かに出会うのが大好きだったので、皆さんがこれが役に立ったことを願っています。
これは本当であるには余りにも良いですか?
人生のあらゆるものと同様に、長所と短所があります。コードと抽象化を追加するたびに、基礎となるプロセスが重くなり、少し遅くなります。ジェネリックリレーションを追加すると、結果をスマートキャッシュしようとするにもかかわらず、パフォーマンスダンパーが少し追加されます。全体として、クリーンさとシンプルさが小さなパフォーマンスコストを上回っているかどうかにかかっています。私にとっては、答えは100万回そうです。
コンテンツタイプフレームワークには、ここに表示した以上のものがあります。全体的なレベルの粒度とより詳細な使用法がありますが、平均的な個人の場合、これは、私の意見では10回のうち9回使用する方法です。
一般的な関係者(?)は注意してください!
かなり大きな注意点は、を使用するGenericRelation
場合、GenericRelation
適用された(Picture
)を持つモデルが削除されると、関連するすべての(Comment
)オブジェクトも削除されることです。または、少なくともこの執筆時点で。