在Django中获取多对多关系中的第一个项目项

时间:2022-10-04 13:13:25

I have two models in Django linked together by ManyToMany relation like this:

我在Django中有两个模型由ManyToMany关联链接在一起,如下所示:

class Person(models.Model):
    name = models.CharField(max_length=128)

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person)

I need to get the main person in the group which is the first person in the group. How can I get the first person?

我需要让小组中的主要人物成为小组中的第一个人。我怎样才能得到第一个人?

Here's how I'm adding members:

这是我添加成员的方式:

grp = Group.objects.create(name="Group 1")
grp.save()
prs = Person.objects.create(name="Tom")
grp.members.add(prs) #This is the main person of the group.
prs = Person.objects.create(name="Dick")
grp.members.add(prs)
prs = Person.objects.create(name="Harry")
grp.members.add(prs)

I don't think I need any additional columns as the id of the table group_members is a running sequence right.

我不认为我需要任何其他列,因为表group_members的id是正确的运行序列。

If I try to fetch the main member of the group through Group.objects.get(id=1).members[0] then Django says that the manager is not indexable.

如果我尝试通过Group.objects.get(id = 1).members [0]获取组的主成员,那么Django说管理器不可索引。

If I try this Group.objects.get(id=1).members.all().order_by('id')[0], I get the member with the lowest id in the Person table.

如果我尝试这个Group.objects.get(id = 1).members.all()。order_by('id')[0],我会在Person表中获得id最低的成员。

How can I solve this?

我怎么解决这个问题?

Thanks

4 个解决方案

#1


5  

Django doesn't pay attention to the order of the calls to add. The implicit table Django has for the relationship is something like the following if it was a Django model:

Django没有注意添加调用的顺序。如果它是一个Django模型,Django对关系的隐式表就像下面这样:

class GroupMembers(models.Model):
    group = models.ForeignKey(Group)
    person = models.ForeignKey(Person)

Obviously, there's nothing there about an "order" or which you should come first. By default, it will probably do as you describe and return the lowest pk, but that's just because it has nothing else to go off of.

显然,没有任何关于“订单”或者你应该首先出现的信息。默认情况下,它可能会按照您描述的方式执行并返回最低的pk,但这只是因为它没有任何其他内容可以解决。

If you want to enforce an order, you'll have to use a through table. Basically, instead of letting Django create that implicit model, you create it yourself. Then, you'll add a field like order to dictate the order:

如果要强制执行订单,则必须使用直通表。基本上,不是让Django创建隐式模型,而是自己创建它。然后,您将添加一个类似顺序的字段来指示订单:

class GroupMembers(models.Model):
    class Meta:
        ordering = ['order']

    group = models.ForeignKey(Group)
    person = models.ForeignKey(Person)
    order = models.PositiveIntegerField(default=0)

Then, you tell Django to use this model for the relationship, instead:

然后,你告诉Django将这个模型用于关系,而不是:

class GroupMembers(models.Model):
    group = models.ForeignKey(Group)
    person = models.ForeignKey(Person, through='GroupMembers')

Now, when you add your members, you can't use add anymore, because additional information is need to complete the relationship. Instead, you must use the through model:

现在,当您添加成员时,您不能再使用添加,因为需要其他信息来完成关系。相反,您必须使用直通模型:

prs = Person.objects.create(name="Tom")
GroupMembers.objects.create(person=prs, group=grp, order=1)
prs = Person.objects.create(name="Dick")
GroupMembers.objects.create(person=prs, group=grp, order=2)
prs = Person.objects.create(name="Harry")
GroupMembers.objects.create(person=prs, group=grp, order=3)

Then, just use:

然后,只需使用:

Group.objects.get(id=1).members.all()[0]

Alternatively, you could simply add a BooleanField to specify which is the main user:

或者,您可以简单地添加一个BooleanField来指定哪个是主要用户:

class GroupMembers(models.Model):
    group = models.ForeignKey(Group)
    person = models.ForeignKey(Person)
    is_main_user = models.BooleanField(default=False)

Then, add "Tom" like:

然后,添加“Tom”,如:

prs = Person.objects.create(name="Tom")
GroupMembers.objects.create(person=prs, group=grp, is_main_user=True)

And finally, retrieve "Tom" via:

最后,通过以下方式检索“Tom”:

Group.objects.get(id=1).members.filter(is_main_user=True)[0]

#2


3  

Relational database don't have any notion of ordering, by default. There's no such thing as "first". You need to add an explicit "order" field which keeps the order, and order by it.

默认情况下,关系数据库没有任何排序概念。没有“第一”这样的东西。您需要添加一个显式的“订单”字段来保存订单,并按顺序排序。

#3


1  

You were pretty close:

你非常接近:

Group.objects.get(id=1).members.all()[0]

(But as Alex Gaynor says in his answer, for predictable behaviour you need a proper field to sort on)

(但正如Alex Gaynor在他的回答中所说,对于可预测的行为,你需要一个适当的字段来排序)

#4


0  

to reliably keep a record of who is the "main" person in a group, you may want to have a look at using a through table to keep this metadata

为了可靠地记录谁是组中的“主要”人员,您可能希望查看使用直通表来保留此元数据

#1


5  

Django doesn't pay attention to the order of the calls to add. The implicit table Django has for the relationship is something like the following if it was a Django model:

Django没有注意添加调用的顺序。如果它是一个Django模型,Django对关系的隐式表就像下面这样:

class GroupMembers(models.Model):
    group = models.ForeignKey(Group)
    person = models.ForeignKey(Person)

Obviously, there's nothing there about an "order" or which you should come first. By default, it will probably do as you describe and return the lowest pk, but that's just because it has nothing else to go off of.

显然,没有任何关于“订单”或者你应该首先出现的信息。默认情况下,它可能会按照您描述的方式执行并返回最低的pk,但这只是因为它没有任何其他内容可以解决。

If you want to enforce an order, you'll have to use a through table. Basically, instead of letting Django create that implicit model, you create it yourself. Then, you'll add a field like order to dictate the order:

如果要强制执行订单,则必须使用直通表。基本上,不是让Django创建隐式模型,而是自己创建它。然后,您将添加一个类似顺序的字段来指示订单:

class GroupMembers(models.Model):
    class Meta:
        ordering = ['order']

    group = models.ForeignKey(Group)
    person = models.ForeignKey(Person)
    order = models.PositiveIntegerField(default=0)

Then, you tell Django to use this model for the relationship, instead:

然后,你告诉Django将这个模型用于关系,而不是:

class GroupMembers(models.Model):
    group = models.ForeignKey(Group)
    person = models.ForeignKey(Person, through='GroupMembers')

Now, when you add your members, you can't use add anymore, because additional information is need to complete the relationship. Instead, you must use the through model:

现在,当您添加成员时,您不能再使用添加,因为需要其他信息来完成关系。相反,您必须使用直通模型:

prs = Person.objects.create(name="Tom")
GroupMembers.objects.create(person=prs, group=grp, order=1)
prs = Person.objects.create(name="Dick")
GroupMembers.objects.create(person=prs, group=grp, order=2)
prs = Person.objects.create(name="Harry")
GroupMembers.objects.create(person=prs, group=grp, order=3)

Then, just use:

然后,只需使用:

Group.objects.get(id=1).members.all()[0]

Alternatively, you could simply add a BooleanField to specify which is the main user:

或者,您可以简单地添加一个BooleanField来指定哪个是主要用户:

class GroupMembers(models.Model):
    group = models.ForeignKey(Group)
    person = models.ForeignKey(Person)
    is_main_user = models.BooleanField(default=False)

Then, add "Tom" like:

然后,添加“Tom”,如:

prs = Person.objects.create(name="Tom")
GroupMembers.objects.create(person=prs, group=grp, is_main_user=True)

And finally, retrieve "Tom" via:

最后,通过以下方式检索“Tom”:

Group.objects.get(id=1).members.filter(is_main_user=True)[0]

#2


3  

Relational database don't have any notion of ordering, by default. There's no such thing as "first". You need to add an explicit "order" field which keeps the order, and order by it.

默认情况下,关系数据库没有任何排序概念。没有“第一”这样的东西。您需要添加一个显式的“订单”字段来保存订单,并按顺序排序。

#3


1  

You were pretty close:

你非常接近:

Group.objects.get(id=1).members.all()[0]

(But as Alex Gaynor says in his answer, for predictable behaviour you need a proper field to sort on)

(但正如Alex Gaynor在他的回答中所说,对于可预测的行为,你需要一个适当的字段来排序)

#4


0  

to reliably keep a record of who is the "main" person in a group, you may want to have a look at using a through table to keep this metadata

为了可靠地记录谁是组中的“主要”人员,您可能希望查看使用直通表来保留此元数据