web-dev-qa-db-ja.com

django-FormViewとModelFormでモデルを更新

ModelFormFormViewを使用して既存のインスタンスを更新する方法がわかりませんか?

このURLでのフォームPOST:r'/object/(?P<pk>)/'

ModelFormを使用します(直接UpdateViewではありません)。これは、フィールドの1つが必須であり、クリーンアップを実行するためです。

基本的にkwarg instance=...(POSTで)FormView内のフォームを初期化して、そのpkがURLで指定されているオブジェクトにバインドされる場合。しかし、私はそれをどこで行うべきかわかりません...

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

あなたとのいくつかの議論の後、あなたが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())

もちろん、私があなたを誤解しているなら、私に知らせてください。ただし、これを機能させることができるはずです。

24
jproffitt

このスレッドをさらに訪問する場合は、はい、FormViewCreateViewの両方のように動作するUpdateViewを作成できます。これは、他のユーザーの意見にも関わらず、Webフォームのsingle form/URL/pageを使用してオプションのユーザーデータを保存する必要がある場合に非常に有効です。一度だけ保存されます。このために2つのURL /ビューは必要ありませんが、モデルがユーザーによって既に保存されている場合に更新される前のデータで満たされたフォームを表示する1つのページ/ 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)

オブジェクトはpk一対一フィールドを介してDBから取得されるため、この例のURLでuserを使用する必要さえありません。これと似たケースがあり、作成/更新されるモデルがユーザーと一意の関係にある場合、それは非常に簡単です。

これが誰かを助けることを願っています...

乾杯。

28

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)
3
Shanki