django - update model with FormView and ModelForm

夙愿已清 提交于 2019-11-29 19:38:53

After some discussion with you, I still don't see why you can't use an UpdateView. It seems like a very simple use case if I understand correctly. You have a model that you want to update. And you have a custom form to do cleaning before saving it to that model. Seems like an UpdateView would work just fine. 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())

Of course, if I am misunderstanding you, please let me know. You should be able to get this to work though.

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.

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)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!