Как представить семейные отношения в Django, используя manyToMany и inlineformset? - PullRequest
0 голосов
/ 05 марта 2019

Я хотел бы создать представление обновления, в котором модель 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>

С фрагментами кода выше, при рендеринге шаблона я получаю (см. Изображение в ссылке 1:

В результате я не могу щелкнуть по соответствующему раскрывающемуся списку, чтобы выбрать связанное лицо. Кроме того, связанный тип также не отображается в шаблоне.

1 Ответ

0 голосов
/ 05 марта 2019

Вам нужны две модели, а не 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 брат Фила, вы можете сделать:

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

Единственное, что здесь есть, это то, что тип_отношения имеет направление (не симметричное), так что вы можете 't:

james.relations.filter(related=phil).first()  # None

, но вы можете:

james.reverse_relations.filter(related=phil).first().relation_type  # "brother"

Возможно, вы захотите также сохранить reverse_relation_type, чтобы у вас там была «сестра», если phil была девушкой.

...