web-dev-qa-db-fra.com

django - mettre à jour le modèle avec FormView et ModelForm

Je ne sais pas comment utiliser un ModelForm dans un FormView pour qu'il mette à jour une instance déjà existante ??

Les formulaires POST sur cette URL: r'/object/(?P<pk>)/'

J'utilise un ModelForm (et pas directement un UpdateView) car l'un des champs est obligatoire et j'effectue un nettoyage dessus.

Je voudrais essentiellement fournir le kwarg instance=... lors de l'initialisation du formulaire dans le FormView (au POST) afin qu'il soit lié à l'objet dont le pk est donné dans l'url. Mais je ne sais pas où faire ça ...

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

Après quelques discussions avec vous, je ne vois toujours pas pourquoi vous ne pouvez pas utiliser un UpdateView. Cela semble être un cas d'utilisation très simple si je comprends bien. Vous avez un modèle que vous souhaitez mettre à jour. Et vous avez un formulaire personnalisé pour faire le nettoyage avant de l'enregistrer sur ce modèle. On dirait qu'un UpdateView fonctionnerait très bien. Comme ça:

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

Bien sûr, si je vous comprends mal, faites-le moi savoir. Vous devriez cependant pouvoir faire fonctionner cela.

24
jproffitt

Pour tous les autres visiteurs de ce fil, oui, vous pouvez créer un FormView qui agit à la fois comme un CreateView et un UpdateView. Cela, malgré certaines opinions d'autres utilisateurs, peut avoir beaucoup de sens si vous voulez avoir un nique formulaire/URL/page pour un formulaire Web pour enregistrer certaines données utilisateur qui peuvent être facultatives mais doivent être sauvé une seule fois. Vous ne voulez pas avoir 2 URL/vues pour cela, mais juste une seule page/URL qui montre un formulaire, rempli de données précédentes à mettre à jour si un modèle a déjà été enregistré par l'utilisateur.

Pensez à une sorte de modèle "contact" comme celui-ci:

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)

Donc, vous écrivez un ModelForm pour cela, comme ceci:

from Django import forms

from .models import Contact


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

Et votre FormView avec les capacités "créer" et "mettre à jour" ressemblera à ceci:

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)

Vous n'avez même pas besoin d'utiliser un pk dans l'URL de cet exemple, car l'objet est récupéré de la base de données via le champ un-à-un user. Si vous avez un cas similaire à celui-ci, dans lequel le modèle à créer/mettre à jour a une relation unique avec l'utilisateur, c'est très simple.

J'espère que cela aide quelqu'un ...

À votre santé.

28
José L. Patiño

Vous pouvez utiliser la méthode post de FormView pour obtenir les données publiées et les enregistrer dans le modèle à l'aide de form.save (). J'espère que cela vous aidera.

Essaye ça

    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