Djangoモデルで関係を回避するのに少し苦労しています。
誰かがOneToOne、ManyToMany、ForeignKeyの違いを説明できますか?
さて、ここには本質的に2つの質問があります。
これらの質問はどちらも簡単なGoogle検索で簡単に回答できますが、SOでこの質問の正確な重複を見つけることができないので、先に進んで回答します。
Djangoでは、関係は関係の一方の側でのみ定義されることに注意してください。
外部キー関係は、一般に多対1の関係として知られています。この関係の逆は1対多です(Djangoはアクセスするツールを提供します)。名前が示すように、多くのオブジェクトは1つに関連している可能性があります。
_Person >--| Birthplace
^ ^
| |
Many One
_
この例では、人の出生地は1つだけですが、出生地は多くの人に関連している場合があります。 Djangoでこの例を見てみましょう。これらが私たちのモデルだとしましょう:
_class Birthplace(models.Model):
city = models.CharField(max_length=75)
state = models.CharField(max_length=25)
def __unicode__(self):
return "".join(self.city, ", ", self.state)
class Person(models.Model):
name = models.CharField(max_length=50)
birthplace = models.ForeignKey(Birthplace)
def __unicode__(self):
return self.name
_
Birthplace
モデル内ではリレーションが定義されておらず、ForeignKey
モデル内ではPerson
リレーションが定義されていることがわかります。モデルの次のインスタンスを作成するとします(明らかにPython構文ではありません):
これで、Djangoがこれらのリレーションを使用する方法を確認できます(_./manage.py Shell
_はあなたの友達です!):
_>> from somewhere.models import Birthplace, Person
>> Person.objects.all()
[<Person: John Smith>, <Person: Maria Lee>, <Person: Daniel Lee>]
>> Birthplace.objects.all()
[<Birthplace: Dallas, Texas>, <Birthplace: New York City, New York>]
_
作成したモデルインスタンスを確認できます。それでは、誰かの生家をチェックしてみましょう。
_>> person = Person.object.get(name="John Smith")
>> person.birthplace
<Birthplace: Dallas, Texas>
>> person.birthplace.city
Dallas
_
特定の出生地を持つすべての人に会いたいとしましょう。前に言ったように、Djangoは逆の関係にアクセスできます。デフォルトでは、Djangoはマネージャーを作成します( RelatedManager
)これを処理するモデルでは、_<model>_set
_という名前で、_<model>
_は小文字のモデル名です。
_>> place = Birthplace.objects.get(city="Dallas")
>> place.person_set.all()
[<Person: John Smith>, <Person: Maria Lee>]
_
モデル関係で_related_name
_キーワード引数を設定することにより、このマネージャーの名前を変更できることに注意してください。したがって、birthplace
モデルのPerson
フィールドを次のように変更します。
_birthplace = models.ForeignKey(Birthplace, related_name="people")
_
これで、きれいな名前でその逆の関係にアクセスできます。
_>> place.people.all()
[<Person: John Smith>, <Person: Maria Lee>]
_
1対1の関係は、2つのオブジェクトを一意の関係に制限することを除いて、多対1の関係に非常に似ています。この例は、ユーザーとプロファイル(ユーザーに関する情報を保存する)です。 2人のユーザーが同じプロファイルを共有することはありません。
_User |--| Profile
^ ^
| |
One One
_
Djangoでこれを見てみましょう。 Djangoで定義されているため、ユーザーモデルを定義する必要はありません。ただし、DjangoはDjango.contrib.auth.get_user_model()
を使用してユーザーをインポートするため、これが実行されます。プロファイルモデルは次のように定義できます。
_class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL) # Note that Django suggests getting the User from the settings for relationship definitions
fruit = models.CharField(max_length=50, help_text="Favorite Fruit")
facebook = models.CharField(max_length=100, help_text="Facebook Username")
def __unicode__(self):
return "".join(self.fruit, " ", self.facebook)
_
必要なのは、シェルでこれをテストするプロファイルを持つ1人のユーザーだけです。
これで、ユーザーモデルからユーザーのプロファイルに簡単にアクセスできます。
_>> user = User.objects.all()[0]
>> user.username
johndt6
>> user.profile
<Profile: Kiwi blah_blah>
>> user.profile.fruit
Kiwi
>> profile = Profile.objects.get(user=user)
>> profile.user
<User: johndt6>
_
もちろん、上記の_related_name
_引数を使用して、逆リレーションの名前をカスタマイズできます。
多対多の関係は、少し注意が必要です。多対多のフィールドは乱雑であり、可能な場合は避けるべきだと言って始めましょう。それを考えると、多対多の関係が理にかなっている状況はたくさんあります。
2つのモデル間の多対多の関係は、最初のモデルのゼロ、1つまたは複数のオブジェクトが2番目のモデルのゼロ、1つまたは複数のオブジェクトに関連付けられることを定義します。例として、プロジェクトを通じてワークフローを定義する会社を想像してみましょう。プロジェクトは、注文なし、1つの注文のみ、または多くの注文に関連している場合があります。注文は、プロジェクトなし、1つのプロジェクト、または多くのプロジェクトに関連している場合があります。
_Order >--< Project
^ ^
| |
Many Many
_
モデルを次のように定義しましょう。
_class Order(models.Model):
product = models.CharField(max_length=150) # Note that in reality, this would probably be better served by a Product model
customer = models.CharField(max_length=150) # The same may be said for customers
def __unicode__(self):
return "".join(self.product, " for ", self.customer)
class Project(models.Model):
orders = models.ManyToManyField(Order)
def __unicode__(self):
return "".join("Project ", str(self.id))
_
Django=は、多対多の関係にアクセスするためにRelatedManager
フィールドにorders
を作成します。
モデルの次のインスタンスを作成してみましょう(一貫性のない構文で!):
これらの関係には、次のようにアクセスできます。
_>> Project.objects.all()
[<Project: Project 0>, <Project: Project 1>, <Project: Project 2>]
>> for proj in Project.objects.all():
.. print(proj)
.. proj.orders.all() # Note that we must access the `orders`
.. # field through its manager
.. print("")
Project 0
[]
Project 1
[<Order: Spaceship for NASA>]
Project 2
[<Order: Spaceship for NASA>, <Order: Race car for NASCAR>]
_
NASAの命令は2つのプロジェクトに関連しており、米海軍の命令はどれにも関連していないことに注意してください。また、1つのプロジェクトには注文がなく、1つのプロジェクトには複数の注文があることに注意してください。
以前と同じ方法で、逆に関係にアクセスすることもできます。
_>> order = Order.objects.filter(customer="NASA")[0]
>> order.project_set.all()
[<Project: Project 0>, <Project: Project 2>]
_
私のASCII図が少し混乱している可能性が高い場合、以下の説明が役立つかもしれません:
>
_または_<
_は「多」を意味します|
_は「1対1」を意味しますしたがって... _A --| B
_は、AのインスタンスがBの1つのインスタンスにのみ関連付けられることを意味します。
_A --< B
_は、AのインスタンスをBの多くのインスタンスに関連付けることができることを意味します。
_A >--< B
_は次と同等です...
_A --< B
A >-- B
_
したがって、関係の各「側面」または方向は個別に読み取ることができます。それらを一緒につぶすのは便利です。
これらの関係のいずれかを拡張すると、より意味があります。
_ +---- John Smith
|
Dallas|-------+---- Jane Doe
|
+---- Joe Smoe
_
データベース関係の適切な説明 @MarcBにより提供