I face up with the problem of inability to iterate through my formsets. I have already create an inline structure between Client model(form) and Phone model(formset). My aim is to be able to store more than one phone for each client.
The issue is that despite the fact that I can create more than one inlines, when it comes the phase of storing, my code only stores the last phone and not each phone as expected.
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
template
{% 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 %}
I noticed that the phones = PhoneFormSet.save(commit=False) line returns only one instance. Why is this happening?
Any help will be appreciated.
Try changing
phones = PhoneFormSet.save(commit=False) for instance in phones: instance.save()
into