I have a listing model and a photo model:
class Listing(models.Model):
title = models.CharField(max_length=255)
<more fields>...
class Photo(models.Model):
image = models.ImageField(upload_to=create_file_path)
listing = models.ForeignKey(Listing, related_name='photos')
I am using a CBV, UpdateView, to edit a listing. I am using this form:
class ListingDetailForm(forms.ModelForm):
class Meta:
model = Listing
exclude = []
and the inline formset in forms.py to make deleting/changing the image possible:
PhotoFormset = inlineformset_factory(Listing, Photo, fields='__all__', extra=1)
here is my view:
class ListingDetailView(UpdateView):
model = Listing
template_name = 'listing/listing_detail.html'
form_class = ListingDetailForm
success_url = '/store/'
def get_context_data(self, **kwargs):
self.object = self.get_object()
context = super(ListingDetailView, self).get_context_data(**kwargs)
if self.request.POST:
context['form'] = ListingDetailForm(self.request.POST, instance=self.object)
context['photo_form'] = PhotoFormset(self.request.POST, self.request.FILES, instance=self.object)
else:
context['form'] = ListingDetailForm(instance=self.object)
context['photo_form'] = PhotoFormset(instance=self.object)
return context
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form_class = self.get_form_class()
form = self.get_form(form_class)
photo_form = PhotoFormset(self.request.POST)
print photo_form.is_valid()
if form.is_valid() and photo_form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
print 'in form valid for update'
context = self.get_context_data()
base_form = context['form']
photo_form = context['photo_form']
# print base_form
# print photo_form
if base_form.is_valid() and photo_form.is_valid():
print 'forms are valid for update'
base_form.save()
photo_form.save()
return super(ListingDetailView, self).form_valid(form)
else:
return self.render_to_response(self)
and the relevant template section:
{% block body %}
<form action="" method="post">
{% csrf_token %}
{% for field in form %}
{{ field.errors }}
{{ field.label_tag }} {{ field }}<br><br>
{% endfor %}
{% for field in photo_form %}
{{ field.errors }}
{{ field.label_tag }} {{ field }}<br><br>
{% endfor %}
{{ photo_form.management_form }}
<input type="submit" value="Update" />
</form>
{% endblock %}
The issues I am having are:
1) If there is a photo attached to the listing, through the admin, the photo form does not pass validation if I do nothing with the photo form, e.g. change only fields from the listing model. The photo form displays no errors when the page reloads after invalid.
2) selecting a new photo does not change the current photo, the photo form does not validate and displays no errors.
3) if there is currently no photo related to the listing trying to add one validates through the form but does not actually save a photo related to that listing.
Deleting an image, if there is one attached to the listing, works just fine. Deleting the image and updating some other field from the listing works. If there is no image updating only a listing field works. Adding a second photo to the listing through the form does not work and displays no form errors.
There are a few issues I noticed with your form.
Once you implement these changes your formset should work just fine.