I can't figure out how to use a ModelForm
in a FormView
so that it updates an already existing instance??
The form POSTs on this URL: r'/object/(?P<pk>)/'
I use a ModelForm
(and not directly an UpdateView
) because one of the fields is required and I perform a clean on it.
I'd basically like to provide the kwarg instance=...
when initializing the form in the FormView
(at POST) so that it's bound to the object whose pk is given in the url. But I can't figure out where to do that...
class SaveForm(ModelForm): somedata = forms.CharField(required=False) class Meta: model = SomeModel # with attr somedata fields = ('somedata', 'someotherdata') def clean_somedata(self): return sometransformation(self.cleaned_data['somedata']) class SaveView(FormView): form_class = SaveForm def form_valid(self, form): # form.instance here would be == SomeModel.objects.get(pk=pk_from_kwargs) form.instance.save() return ...
For any further visitors of this thread, yes, you can make a FormView
that acts like both a CreateView
and an UpdateView
. This, despite some opinions of other users, can make a lot of sense if you want to have a single form/URL/page for a web form to save some user data which can be optional but needs to be saved once and only once. You don't want to have 2 URLs/views for this, but just only one page/URL which shows a form, filled with previous data to be updated if a model was already saved by the user.
Think in a kind of "contact" model like this one:
from django.conf import settings from django.db import models class Contact(models.Model): """ Contact details for a customer user. """ user = models.OneToOneField(settings.AUTH_USER_MODEL) street = models.CharField(max_length=100, blank=True) number = models.CharField(max_length=5, blank=True) postal_code = models.CharField(max_length=7, blank=True) city = models.CharField(max_length=50, blank=True) phone = models.CharField(max_length=15) alternative_email = models.CharField(max_length=254)
So, you write a ModelForm
for it, like this:
from django import forms from .models import Contact class ContactForm(forms.ModelForm): class Meta: model = Contact exclude = ('user',) # We'll set the user later.
And your FormView
with both "create" and "update" capabilities will look like this:
from django.core.urlresolvers import reverse from django.views.generic.edit import FormView from .forms import ContactForm from .models import Contact class ContactView(FormView): template_name = 'contact.html' form_class = ContactForm success_url = reverse('MY_URL_TO_REDIRECT') def get_form(self, form_class): """ Check if the user already saved contact details. If so, then show the form populated with those details, to let user change them. """ try: contact = Contact.objects.get(user=self.request.user) return form_class(instance=contact, **self.get_form_kwargs()) except Contact.DoesNotExist: return form_class(**self.get_form_kwargs()) def form_valid(self, form): form.instance.user = self.request.user form.save() return super(ContactView, self).form_valid(form)
You don't even need to use a pk
in the URL of this example, because the object is retrieved from the DB via the user
one-to-one field. If you have a case similar than this, in which the model to be created/updated has a unique relationship with the user, it is very easy.
Hope this helps somebody...
Cheers.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With