如何使用内联结构迭代表单集

时间:2018-12-07 07:23:09

标签: django django-forms formset inlines

我面对着无法遍历我的表单集的问题。 我已经在客户端模型(窗体)和电话模型(窗体集)之间创建了一个内联结构。我的目标是能够为每个客户存储多于一部电话。

问题在于,尽管我可以创建多个内联,但是在存储阶段,我的代码仅存储了最后一部电话,而不是预期的每部电话。

models.py

class Client(models.Model):
    name = models.CharField(max_length=50, verbose_name="Όνομα")
    surname = models.CharField(max_length=50, verbose_name="Επίθετο")
    amka_amesa = models.BigIntegerField( validators=[MaxValueValidator(99999999999)],null=True,blank=True, verbose_name="AΜΚΑ Άμεσα Ασφαλισμένου")
    amka_emesa = models.BigIntegerField( validators=[MaxValueValidator(99999999999)], unique=True, null=True, blank=True, verbose_name="ΑΜΚΑ Έμεσα Ασφαλισμένου")
    am_asfa = models.CharField( max_length=11, validators=[RegexValidator(r'^\d+$')], null=True, blank=True, verbose_name="Α.Μητρώου Ασφαλισμένου")
    address = models.CharField(max_length=100, null=True, blank=True, verbose_name="Διεύθυνση")
    ika_branch = models.ForeignKey(Client_IKA_Branch, null=True, blank=True, verbose_name=u'Υποκατάστημα Ασφαλισμένου')
    notes = models.CharField(max_length=100, null=True, blank=True, verbose_name="Σημειώσεις")
    #active field=1
    #inactive field=0
    INACTIVE, ACTIVE = range(0, 2)
    ACTIVITY_OPTIONS = (
        (INACTIVE, 'Ανενεργός'),
        (ACTIVE, 'Ενεργός'),
        )
    activity = models.IntegerField(choices=ACTIVITY_OPTIONS, null=True,default=ACTIVE)

class Phone(models.Model):
    MOBILE, WORK, HOME = range(0, 3)
    CATEGORIES = (
        (MOBILE, 'Κινητό'),
        (WORK, 'Δουλειά'),
        (HOME, 'Σπίτι'),
        )
    number = models.CharField(max_length=14, null=True)
    category = models.IntegerField(choices=CATEGORIES, null=True,default=MOBILE)
    client = models.ForeignKey(Client, null=True)

    def __unicode__(self):
        return self.number

    def get_absolute_url(self):
        return reverse('client_list')

forms.py

class ClientForm(ModelForm):
    class Meta:
        model = Client
        exclude=('activity',)

class PhoneForm(ModelForm):
    class Meta:
        model = Phone
        exclude = ('client',)

ClientPhoneFormSet=inlineformset_factory(Client,Phone,form=PhoneForm,extra=1) 

views.py

class ClientCreateView(LoginRequiredMixin, CreateView):
    model = Client
    form_class = ClientForm
    template_name='test/test_client_phone.html'

    def get_success_url(self):         
        return reverse('client_edit', args=(self.object.id,))

    def form_valid(self, form):
        ctx = self.get_context_data()
        PhoneFormSet = ctx['PhoneFormSet']
        if PhoneFormSet.is_valid() and form.is_valid():
            self.object = form.save() # saves Father and Children
            phones = PhoneFormSet.save(commit=False) 
            for instance in phones:                 
                instance.save()
            return redirect(self.get_success_url())
        else:
            return self.render_to_response(self.get_context_data(form=form))

    def form_invalid(self, form):
        return self.render_to_response(self.get_context_data(form=form))

    def get_context_data(self, **kwargs):
        ctx = super(ClientCreateView, self).get_context_data(**kwargs)
        if self.request.POST:
            ctx['form'] = ClientForm(self.request.POST)
            ctx['PhoneFormSet'] = ClientPhoneFormSet(self.request.POST)
        else:
            ctx['form'] = ClientForm()
            ctx['PhoneFormSet'] = ClientPhoneFormSet()
        return ctx

模板

{% extends 'base.html' %}
{% load bootstrap3 %}
{% load static %}
<!-- Latest compiled and minified JavaScript -->


{% block content %}

<div class="col-md-12 text-center">
<h2>Δημιουργία / Αλλαγή Πελάτη </h2>
</div>

<hr>
<form class="well" method="post" action="">
{% csrf_token %}
{% bootstrap_form form %}

<table class="table phone">
  {{ PhoneFormSet.management_form }}

  {% for form in PhoneFormSet.forms %}
      {% if forloop.first %}
          <thead>
          <tr>
              {% for field in form.visible_fields %}
                  <th>{{ field.label|capfirst }}</th>
              {% endfor %}
          </tr>
          </thead>
      {% endif %}
      <tr class="{% cycle row1 row2 %} formset_row">
          {% for field in form.visible_fields %}
              <td>
                  {# Include the hidden fields in the form #}
                  {% if forloop.first %}
                      {% for hidden in form.hidden_fields %}
                          {{ hidden }}
                      {% endfor %}
                  {% endif %}
                  {{ field.errors.as_ul }}
                  {{ field }}
              </td>
          {% endfor %}
      </tr>
  {% endfor %}
</table>


<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="{% static 'jquery.formset.js' %}"></script>
<script type="text/javascript">
  $('table.phone tr.formset_row').formset({
      addText: 'Πρόσθεσε Τηλέφωνο',
      deleteText: 'Διαγραφή',
      prefix: 'client_phone_set',
      animateForms: true
  });
</script>

    {% buttons %}
      <button type="submit" class="btn btn-primary">
         Submit
      </button>
    {% endbuttons %}
</form>


<hr>
{{ form.media }}
<link rel="stylesheet" type="text/css" href="{% static 'admin/css/forms.css' %}"/>
<link rel="stylesheet" type="text/css" href="{% static 'admin/css/base.css' %}"/>
<link rel="stylesheet" type="text/css" href="{% static 'admin/css/widgets.css' %}"/>
<script type="text/javascript" src="/admin/jsi18n/"></script>
<script type="text/javascript" src="/static/admin/js/core.js"></script>
<script type="text/javascript" src="/static/admin/js/admin/RelatedObjectLookups.js"></script>
<script type="text/javascript" src="/static/admin/js/vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="/static/admin/js/jquery.init.js"></script>
<script type="text/javascript" src="/static/admin/js/actions.min.js"></script>
<script type="text/javascript" src="/static/admin/js/calendar.js"></script>
<script type="text/javascript" src="/static/admin/js/admin/DateTimeShortcuts.js"></script>

{% endblock %}

我注意到 phones = PhoneFormSet.save(commit = False)行仅返回一个实例。为什么会这样?

任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:0)

尝试更改

phones = PhoneFormSet.save(commit=False) for instance in phones: instance.save()

进入

phones = PhoneFormSet.save(commit=False) 
phones.instance=self.object
phones.save()

答案 1 :(得分:0)

与模板中的前缀有关的修复。它必须是前缀:'phone_set',而不是像我以前那样的前缀:'client_phone_set'。