django - 使用FormView和ModelForm更新模型

时间:2014-02-06 15:16:14

标签: django django-views django-forms

我无法弄清楚如何在ModelForm中使用FormView以便更新已存在的实例?

此网址上的表单POST:r'/object/(?P<pk>)/'

我使用ModelForm(而不是直接使用UpdateView),因为其中一个字段是必需的,我会对其执行清理。

我基本上喜欢在instance=...(在POST时)初始化表单时提供kwarg FormView,以便它绑定到在url中给出pk的对象。但我无法弄清楚在哪里这样做......

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 ...

3 个答案:

答案 0 :(得分:25)

对于此主题的任何其他访问者,是的,您可以制作FormView,其行为与CreateViewUpdateView相同。这个,尽管有其他用户的一些意见,如果你想要一个单个表单/ URL /页面的Web表单来保存一些可选的但需要的用户数据,这很有意义。只保存一次。您不希望有2个URL /视图,但只有一个页面/ URL显示表单,如果用户已保存模型,则填充以前要更新的数据。

想象一下像这样的“联系”模式:

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)

所以,你为它写了一个ModelForm,就像这样:

from django import forms

from .models import Contact


class ContactForm(forms.ModelForm):
    class Meta:
        model = Contact
        exclude = ('user',)  # We'll set the user later.

具有“创建”和“更新”功能的FormView将如下所示:

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)

您甚至不需要在此示例的URL中使用pk,因为通过user一对一字段从数据库中检索对象。如果您的案例与此类似,其中要创建/更新的模型与用户具有独特的关系,则非常容易。

希望这有助于某人...

干杯。

答案 1 :(得分:23)

在与您讨论之后,我仍然不明白为什么您不能使用UpdateView。如果我理解正确,这似乎是一个非常简单的用例。您有一个要更新的模型。并且您有一个自定义表单,在将其保存到该模型之前进行清洁。似乎UpdateView可以正常工作。像这样:

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())

当然,如果我误解你,请告诉我。你应该可以让它工作。

答案 2 :(得分:3)

您可以使用FormView的post方法获取发布的数据,并使用form.save()保存到模型中。希望这会有所帮助。

试试这个

    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)