具有多个模型依赖关系的Django ModelForm字段过滤

时间:2013-09-04 19:36:20

标签: python django django-forms

我有会员模型和组模型,其中包含来自会员的外键

class Member(models.Model):
    member_name = models.CharField(max_length=100)
    member_dob = models.DateField()

class Group(models.Model):
    group_name = models.CharField(max_length=100)
    group_owner = models.ForeignKey(Member, related_name='owner')
    group_members = models.ManyToManyField(Member, related_name='members')

我创建了另一个模型,Activity将引用Group和Member

class Activity(models.Model):
    group_id = models.ForeignKey(Group)
    topic = models.CharField(max_length=100)
    start_by = models.ForeignKey(Member, related_name='started')
    participants = models.ManyToManyField(Member, related_name='participants')

现在我已经为Acivity创建了一个ModelForm

class ActivityForm(ModelForm):
    class Meta:
        model = Activity

如果我在模板中使用了ActivityForm的对象,则所有用户都将加载到参与者的“选择”输入中。我希望仅显示属于选择选项中显示的组(具有id = self.group_id)的成员。

有人可以帮我编写一个查询集,我可以将其包含在ActivityForm的 init 函数中吗?

2 个答案:

答案 0 :(得分:2)

Member不应该Group拥有外键吗?您希望组中的许多成员不是很多,只有一个成员的组吗?

class Member(models.Model):
    name = models.CharField(max_length=100)
    dob = models.DateField()
    group = modes.ForeignKey('Group', related_name='members')

class Group(models.Model):
    name = models.CharField(max_length=100)
    owner = models.ForeignKey('Member', related_name='owned_groups')

class Activity(models.Model):
    group = models.ForeignKey('Group', related_name='activities')
    topic = models.CharField(max_length=100)
    start_by = models.ForeignKey('Member', related_name='started_activities')
    participants = models.ManyToManyField('Member', related_name='participating_activities')

然后你可以这样做:

class ActivityForm(ModelForm):
    def __init__(self, *args, **kwargs):
        super(ActivityForm, self).__init__(*args, **kwargs)
        if 'initial' in kwargs:
            self.fields['participants'].queryset = Member.objects.filter(group=initial.group)
    class Meta:
        model = Activity

修改


如果更改为使用ManyToManyField,我建议您修改字段名称和相关名称。在开发过程的早期进行更改会更容易,而不是在遇到无法修复的其他问题时。如果它更容易理解,只需这样思考:相关名称将在ForeignKeyManyToManyField指向的模型上可访问,并包含queryset 0或更多条目。

所以,如果你有......

class Member(models.Model):
    name = models.CharField(max_length=100)
    dob = models.DateField()

class Group(models.Model):
    name = models.CharField(max_length=100)
    owner = models.ForeignKey('Member', related_name='owned_groups')
    members = models.ManyToManyField('Member', related_name='groups')

class Activity(models.Model):
    group = models.ForeignKey(Group)
    topic = models.CharField(max_length=100)
    start_by = models.ForeignKey('Member', related_name='started_activities')
    participants = models.ManyToManyField('Member', related_name='activities')

然后你可以做像...这样的事情。

g1 = Group.objects.create(name='Group 1', ...)
g2 = Group.objects.create(name='Group 2', ...)

member = Member.objects.get(name='John')
member.groups.all() # Get all the groups for the member
member.groups.add(g1, g2) # Add the member to 2 groups
member.activities.all() # Get all activities the member is a participant in
member.started_activities.all() # Get all activities started by the user

你的表格......

class ActivityForm(ModelForm):
    ...
    def __init__(self, *args, **kwargs):
        super(ActivityForm, self).__init__(*args, **kwargs)
        if 'initial' in kwargs:
            self.fields['participants'].queryset = initial.group.members.all()

    class Meta: 
        model = Activity

我认为这样可行,但如果没有:

class ActivityForm(ModelForm):
    ...
    def __init__(self, *args, **kwargs):
        super(ActivityForm, self).__init__(*args, **kwargs)
        if 'initial' in kwargs:
            self.fields['participants'].queryset = Member.objects.filter(group__id=initial.group.id)

    class Meta: 
        model = Activity

答案 1 :(得分:0)

您的ActivityForm类需要有一个属性:

class ActivityForm(ModelForm):
    participants = forms.ModelMultipleChoiceField(queryset=Member.objects.filter(members__id==self.instance.group_id))

你的__init__函数应如下所示:

def __init__(self, *args, **kwargs):
    # call parent
    super(ActivityForm, self).__init__(*args, **kwargs)
    # fill initial values
    self.fields['participants'].initial = [c.pk for c in Member.objects.filter(members__id=self.instance.group_id, participants__in=self.instance)

1)您应该在组中重命名“related_name”。相关名称表示如何从其他类中获知该字段,例如。来自会员班

2)我认为你的上下文中的“group_members”应该是ManyToManyField。您的班级组现在允许您只将一个人存储到一个组中。

命名时可能会出现一些错误,因为您的相关名称非常混乱。