33👍
You can still use an UpdateView
. You have a model that you want to update, and you have a custom form to do cleaning before saving it to that model. Like this:
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(UpdateView):
template_name = 'sometemplate.html'
form_class = SaveForm
model = SomeModel
# That should be all you need. If you need to do any more custom stuff
# before saving the form, override the `form_valid` method, like this:
def form_valid(self, form):
self.object = form.save(commit=False)
# Do any custom stuff here
self.object.save()
return render_to_response(self.template_name, self.get_context_data())
35👍
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.
- [Django]-Get list of Cache Keys in Django
- [Django]-How to force migrations to a DB if some tables already exist in Django?
- [Django]-Django Admin: how to display fields from two different models in same view?
3👍
You can use the post method of FormView to get the posted data and save to model using form.save(). Hope this will help.
Try this
class SaveForm(ModelForm):
somedata = forms.CharField(required=False)
class Meta:
model = SomeModel # with attr somedata
fields = ('somedata', 'someotherdata')
def __init__(self, *args, **kwargs):
super(SaveForm, self).__init__(*args, **kwargs)
def save(self, id):
print id #this id will be sent from the view
instance = super(SaveForm, self).save(commit=False)
instance.save()
return instance
class SaveView(FormView):
template_name = 'sometemplate.html'
form_class = SaveForm
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
form.save(kwargs.get('pk'))
else:
return self.form_invalid(form)
- [Django]-Is there a datetime ± infinity?
- [Django]-Is it possible to pass query parameters via Django's {% url %} template tag?
- [Django]-Django Delete all but last five of queryset