我很难理解 Django 模型中的关系.
I'm having a little difficulty getting my head around relationships in Django models.
有人能解释一下 OneToOne、ManyToMany 和 ForeignKey 之间的区别吗?
Could someone explain what the difference is between a OneToOne, ManyToMany and ForeignKey?
嗯,这里基本上有两个问题:
Well, there's essentially two questions here:
这两个问题都可以通过简单的谷歌搜索很容易地回答,但由于我在 SO 上找不到这个问题的确切欺骗,我会继续回答.
Both of these questions are quite easily answered through a simple Google search, but as I cannot find an exact dupe of this question on SO, I'll go ahead and answer.
请注意,在 Django 中,关系只能定义在关系的一侧.
Note that in Django, relationships should only be defined on one side of the relationship.
外键关系通常称为多对一关系.请注意,这种关系的反面是一对多(Django 提供了访问工具).顾名思义,许多对象可能与一个对象相关.
A foreign key relationship is generally known as a many-to-one relationship. Note that the reverse of this relationship is one-to-many (which Django provides tools to access). As the name implies, many objects may be related to one.
Person >--| Birthplace
^ ^
| |
Many One
在这个例子中,一个人可能只有一个出生地,但一个出生地可能与很多人有关.让我们看一下 Django 中的这个例子.假设这些是我们的模型:
In this example, a person may only have one birthplace, but a birthplace may be related to many people. Let's look at this example in Django. Say these are our models:
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
模型中没有定义任何关系,而 Person
模型中定义了 ForeignKey
关系.假设我们创建了以下模型实例(显然不是 Python 语法):
You can see that no relations are defined within the Birthplace
model, and a ForeignKey
relationship is defined within the Person
model. Say that we create the following instances of our models (obviously not in Python syntax):
现在我们可以看到 Django 如何让我们使用这些关系(注意 ./manage.py shell
是你的朋友!):
Now we can see how Django lets us use these relations (note that ./manage.py shell
is your friend!):
>> 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>]
您可以看到我们创建的模型实例.现在让我们来看看某人的出生地:
You can see the model instances we created. Now let's checkout someone's birthplace:
>> person = Person.object.get(name="John Smith")
>> person.birthplace
<Birthplace: Dallas, Texas>
>> person.birthplace.city
Dallas
假设您想查看具有给定出生地的所有人.正如我之前所说,Django 允许您访问反向关系.默认情况下,Django 创建一个管理器 (RelatedManager
) 来处理这个问题,命名为 <model>_set
,其中 <model>
是你的小写的型号名称.
Let's say you want to see all people with a given birthplace. As I said earlier, Django allows you to access reverse relations. By default, Django creates a manager (RelatedManager
) on your model to handle this, named <model>_set
, where <model>
is your model name in lowercase.
>> place = Birthplace.objects.get(city="Dallas")
>> place.person_set.all()
[<Person: John Smith>, <Person: Maria Lee>]
请注意,我们可以通过在模型关系中设置 related_name
关键字参数来更改此管理器的名称.因此,我们将 Person
模型中的 birthplace
字段更改为:
Note that we can change the name of this manager by setting the related_name
keyword argument in our model relation. So, we would change the birthplace
field in the Person
model to:
birthplace = models.ForeignKey(Birthplace, related_name="people")
现在,我们可以用一个漂亮的名字来访问这种反向关系:
Now, we can access that reverse relationship with a pretty name:
>> place.people.all()
[<Person: John Smith>, <Person: Maria Lee>]
<小时>
一对一关系与多对一关系非常相似,只是它将两个对象限制为具有唯一关系.这方面的一个例子是用户和个人资料(存储有关用户的信息).没有两个用户共享相同的个人资料.
A one-to-one relationship is quite similar to a many-to-one relationship, except that it restricts two objects to having a unique relationship. An example of this would be a User and a Profile (which stores information about the user). No two users share the same profile.
User |--| Profile
^ ^
| |
One One
让我们在 Django 中看看这个.我不会费心去定义用户模型,因为 Django 为我们定义了它.但是请注意,Django 建议使用 django.contrib.auth.get_user_model()
来导入用户,这就是我们要做的.配置文件模型可以定义如下:
Let's look at this in Django. I won't bother to define the user model, as Django defines it for us. Do note, however, that Django suggests using django.contrib.auth.get_user_model()
to import the user, so that's what we'll do. The profile model may be defined as follows:
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)
我们只需要一个具有配置文件的用户就可以在 shell 中进行测试:
All we need is one user with a profile to test this out in the shell:
现在您可以轻松地从 User 模型访问用户的个人资料:
Now you may easily access the user's profile from the User model:
>> 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
参数自定义反向关系的名称.
Of course, you may customize the name of the reverse relation using the related_name
argument as above.
多对多关系可能有点棘手.让我首先说多对多字段是混乱的,应该尽可能避免.鉴于此,在很多情况下多对多关系是有意义的.
Many-to-many relationships can be a bit tricky. Let me start by saying that many-to-many fields are messy, and should be avoided when possible. Given that, there are plenty of situations where a many-to-many relationship makes sense.
两个模型之间的多对多关系定义了第一个模型的零个、一个或多个对象可能与第二个模型的零个、一个或多个对象相关.例如,让我们设想一家通过项目定义其工作流程的公司.一个项目可能与无订单、只有一个订单或多个订单相关.一个订单可能与没有项目、一个项目或多个项目相关.
A many-to-many relationship between two models defines that zero, one or more objects of the first model may be related to zero, one or more objects of the second model. As an example, let's envision a company that defines their workflow through projects. A project may be related to no orders, only one order, or many orders. An order may be related to no projects, one project, or many.
Order >--< Project
^ ^
| |
Many Many
让我们这样定义我们的模型:
Let's define our models as so:
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 将为 orders
字段创建一个 RelatedManager
以访问多对多关系.
Note that Django will create a RelatedManager
for the orders
field to access the many-to-many relationship.
让我们创建模型的以下实例(我的语法不一致!):
Let's create the following instances of our models (in my inconsistent syntax!):
我们可以按如下方式访问这些关系:
We can access these relationships as follows:
>> 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 个项目相关,而美国海军订单与任何项目无关.另请注意,一个项目没有订单,一个项目有多个.
Note that the NASA order is related to 2 projects, and the US Navy order is related to none. Also note that one project has no orders, and one has multiple.
我们也可以像以前一样反向访问关系:
We may also access the relationship in reverse in the same way we have before:
>> order = Order.objects.filter(customer="NASA")[0]
>> order.project_set.all()
[<Project: Project 0>, <Project: Project 2>]
<小时>
在我的 ASCII 图表可能有点混乱的情况下,以下解释可能会有所帮助:
In the likely case that my ASCII diagrams are a bit confusing, the following explanations might be helpful:
>
或 <
表示对多个"|
意思是合一">
or <
means "to many"|
means "to one"所以... A --|B
表示 A 的一个实例只能与 B 的一个实例相关.
So... A --| B
means an instance of A can be related to only ONE instance of B.
和 A --<B
表示 A 的一个实例可以与 B 的许多实例相关.
And A --< B
means an instance of A can be related to MANY instances of B.
A >--<B
等价于....
A --< B
A >-- B
因此,关系的每个边"或方向都可以单独阅读.把它们挤在一起很方便.
Thus, each "side" or direction of the relationship can be read separately. It's just convenient to squish them together.
扩展其中一种关系可能更有意义:
Expanding one of these relationships might make more sense:
+---- John Smith
|
Dallas|-------+---- Jane Doe
|
+---- Joe Smoe
对数据库关系的良好解释 由@MarcB 提供
Good explanation of db relationships provided by @MarcB
关于基数的维基百科页面
models.ForeignKey代码>
models.OneToOneField代码>
models.ManyToManyField代码>
一对一关系
多对多关系
这篇关于Django 中的 OneToOne、ManyToMany 和 ForeignKey 字段有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!