如何使用 manyToMany 和 inlineformset 在 Django 中表示家庭关系?
How to represent a family relationship in Django using manyToMany and inlineformset?
我想创建一个更新视图,其中 Person 模型将其相关的 FamilyMember 作为模板中的内联表单集。
在我的 model.py 中,我有:
class Person(models.Model):
Name = models.CharField(max_length=50)
class FamilyMember(models.Model):
person = models.ManyToManyField(Person, through='PersonFamilyMember')
relationType= models.CharField(max_length=3, choices=FAMILYRELATION_CHOICE)
class PersonFamilyMember(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
related = models.ForeignKey(FamilyMember, on_delete=models.CASCADE)
在我的 form.py 中,我有:
class PersonForm(ModelForm):
class Meta:
model = Person
fields = '__all__'
class FamilyMemberForm(ModelForm):
class Meta:
model = FamilyMember
fields = '__all__'
RelatedFMFormSet = inlineformset_factory(Person, PersonFamilyMember.useCase.through, form=FamilyMemberForm, can_delete=True, extra=1)
在我的 view.py 中,我有:
class PersonView(UpdateView):
template_name = 'some.html'
model = Person
form_class = PersonForm
def get_context_data(self, **kwargs):
context = super(PersonView, self).get_context_data(**kwargs)
if self.request.POST:
context['familymember_form'] = RelatedFMFormSet(self.request.POST, self.request.FILES,
instance=self.object, prefix='relatedMember')
else:
context['familymember_form'] = RelatedFMFormSet(instance=self.object, prefix='relatedMember')
return context
在我的模板中,我有:
<form method="POST" enctype="multipart/form-data" style="margin-left: 40px; margin-right: 40px">
{% for hidden_field in form.hidden_fields %}
{% endfor %}
{% csrf_token %}
<fieldset>
<legend>[Person Profile][1]</legend>
{{ form.management_form }}
{{ form.non_form_errors }}
<div class="form-inline">
{% bootstrap_form form %}
</div>
</fieldset>
<fieldset>
<legend>Related Member(s)</legend>
{{ familymember_form.management_form }}
{{ familymember_form.non_form_errors }}
<div class="formset-{{ relatedusecase_form.prefix }}">
{% for hidden_field in familymember_form.hidden_fields %}
{% endfor %}
{% for relatedform in familymember_form.forms %}
<div class="form-inline">
{% if relatedform.instance.pk %}
{{ relatedform.DELETE }}
{% endif %}
{{ relatedform }}
</div>
{% endfor %}
</div>
</fieldset>
<!--Other Code--!>
</form>
使用上面的代码段,当我渲染模板时,我得到(参见 link 1 中的图像:
因此,我无法单击相关下拉列表以 select 相关人员。另外,模板中也没有显示相关类型。
您需要两个模型,而不是 3 个,因为您实际上是将一个人与另一个人联系起来。
class Person(Model):
name = ...
family_members = ManyToManyField('self', through=FamilyMemberRelationship, through_fields=('person', 'relation'))
class FamilyMemberRelationship(Model):
person = ForeignKey(Person, on_delete=CASCADE, related_name='relationships')
related = ForeignKey(Person, on_delete=CASCADE, related_name='reverse_relationships')
relation_type = CharField(max_length=3, choices=FAMILYRELATION_CHOICE)
请注意,该关系不是对称的。现在如果你有 phil
并且 james
是 Phil 的兄弟,那么你可以这样做:
relation = FamilyMemberRelationship(person=phil, related=james, relation_type='brother')
relation.save()
phil.family_members.all() # james
phil.relations.filter(related=james).first().relation_type # "brother"
james.family_members.all() # phil
这里唯一的问题是 relation_type 有一个方向(不对称),所以你不能:
james.relations.filter(related=phil).first() # None
但你可以:
james.reverse_relations.filter(related=phil).first().relation_type # "brother"
您可能还想保存一个 reverse_relation_type
,这样如果 phil
是女孩,您就可以在那里放置 'sister'。
我想创建一个更新视图,其中 Person 模型将其相关的 FamilyMember 作为模板中的内联表单集。
在我的 model.py 中,我有:
class Person(models.Model):
Name = models.CharField(max_length=50)
class FamilyMember(models.Model):
person = models.ManyToManyField(Person, through='PersonFamilyMember')
relationType= models.CharField(max_length=3, choices=FAMILYRELATION_CHOICE)
class PersonFamilyMember(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
related = models.ForeignKey(FamilyMember, on_delete=models.CASCADE)
在我的 form.py 中,我有:
class PersonForm(ModelForm):
class Meta:
model = Person
fields = '__all__'
class FamilyMemberForm(ModelForm):
class Meta:
model = FamilyMember
fields = '__all__'
RelatedFMFormSet = inlineformset_factory(Person, PersonFamilyMember.useCase.through, form=FamilyMemberForm, can_delete=True, extra=1)
在我的 view.py 中,我有:
class PersonView(UpdateView):
template_name = 'some.html'
model = Person
form_class = PersonForm
def get_context_data(self, **kwargs):
context = super(PersonView, self).get_context_data(**kwargs)
if self.request.POST:
context['familymember_form'] = RelatedFMFormSet(self.request.POST, self.request.FILES,
instance=self.object, prefix='relatedMember')
else:
context['familymember_form'] = RelatedFMFormSet(instance=self.object, prefix='relatedMember')
return context
在我的模板中,我有:
<form method="POST" enctype="multipart/form-data" style="margin-left: 40px; margin-right: 40px">
{% for hidden_field in form.hidden_fields %}
{% endfor %}
{% csrf_token %}
<fieldset>
<legend>[Person Profile][1]</legend>
{{ form.management_form }}
{{ form.non_form_errors }}
<div class="form-inline">
{% bootstrap_form form %}
</div>
</fieldset>
<fieldset>
<legend>Related Member(s)</legend>
{{ familymember_form.management_form }}
{{ familymember_form.non_form_errors }}
<div class="formset-{{ relatedusecase_form.prefix }}">
{% for hidden_field in familymember_form.hidden_fields %}
{% endfor %}
{% for relatedform in familymember_form.forms %}
<div class="form-inline">
{% if relatedform.instance.pk %}
{{ relatedform.DELETE }}
{% endif %}
{{ relatedform }}
</div>
{% endfor %}
</div>
</fieldset>
<!--Other Code--!>
</form>
使用上面的代码段,当我渲染模板时,我得到(参见 link 1 中的图像:
因此,我无法单击相关下拉列表以 select 相关人员。另外,模板中也没有显示相关类型。
您需要两个模型,而不是 3 个,因为您实际上是将一个人与另一个人联系起来。
class Person(Model):
name = ...
family_members = ManyToManyField('self', through=FamilyMemberRelationship, through_fields=('person', 'relation'))
class FamilyMemberRelationship(Model):
person = ForeignKey(Person, on_delete=CASCADE, related_name='relationships')
related = ForeignKey(Person, on_delete=CASCADE, related_name='reverse_relationships')
relation_type = CharField(max_length=3, choices=FAMILYRELATION_CHOICE)
请注意,该关系不是对称的。现在如果你有 phil
并且 james
是 Phil 的兄弟,那么你可以这样做:
relation = FamilyMemberRelationship(person=phil, related=james, relation_type='brother')
relation.save()
phil.family_members.all() # james
phil.relations.filter(related=james).first().relation_type # "brother"
james.family_members.all() # phil
这里唯一的问题是 relation_type 有一个方向(不对称),所以你不能:
james.relations.filter(related=phil).first() # None
但你可以:
james.reverse_relations.filter(related=phil).first().relation_type # "brother"
您可能还想保存一个 reverse_relation_type
,这样如果 phil
是女孩,您就可以在那里放置 'sister'。