2011-11-21 22 views
9

Come aggiornare un solo campo in un'istanza utilizzando ModelForm se la richiesta POST ha solo quel campo come parametro? ModelField tenta di sovrascrivere i campi che non sono stati passati nella richiesta POST con Nessuno che porta alla perdita di dati.Django aggiorna un campo utilizzando ModelForm

ho un modello con campi +25 dire

class C(models.Model): 
    a = models.CharField(max_length=128) 
    b = models.CharField(max_length=128) 
    ... 
    x = models.IntegerField() 

e ho un'applicazione desktop che fa richieste POST al fine di modificare un'istanza di C attraverso un metodo API esposte in views.py

Nel metodo api che sto usando ModelForm per convalidare i campi come segue:

form = CModelForm(request.POST, instance=c_instance) 
if form.is_valid(): 
    form.save() 

Nel fare save() Django o si lamenta che qualche altro campo non può essere nullo o r (se tutti i campi sono opzionali) li sovrascrive con Nessuno.

Qualcuno sa come gestirlo? Vorrei fare tutti i controlli manualmente e aggiornare manualmente, ma il modello ha così freakishly lungo elenco di campi ...

risposta

7

Si potrebbe utilizzare un sottoinsieme dei campi nel ModelForm specificando i campi come segue:

class PartialAuthorForm(ModelForm): 
    class Meta: 
     model = Author 
     fields = ('name', 'title') 

dalla documentazione:

Se si specificano i campi o escludere durante la creazione di un modulo con ModelForm, poi i campi che non sono nella forma risultante non verranno impostate da metodo save() del form.

https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#using-a-subset-of-fields-on-the-form

+7

il problema è che faccio non so quale campo verrà aggiornato: -/ –

10

Ottenuto questo capito. Quello che faccio è aggiornare il dizionario request.POST con i valori dell'istanza - in modo che tutti i campi non modificati siano automaticamente presenti. Questo lo farà:

from django.forms.models import model_to_dict 
from copy import copy 

def UPOST(post, obj): 
    '''Updates request's POST dictionary with values from object, for update purposes''' 
    post = copy(post) 
    for k,v in model_to_dict(obj).iteritems(): 
     if k not in post: post[k] = v 
    return post 

e poi basta fare:

form = CModelForm(UPOST(request.POST,c_instance),instance=c_instance) 
+1

Se k rappresenta un campo ManyToMany, questo non funziona. – Erik

1

Django di ModelForm non è progettato per gestire un aggiornamento parziale di un sottoinsieme arbitrario di campi sul modello.

Il caso d'uso descritto dall'OP, un'app desktop che colpisce un'API, sarebbe gestito meglio da Django Rest Framework.

In particolare, è necessario creare un serializzatore che eredita da ModelSerializer e quindi utilizzarlo in un UpdateAPIView. I serializzatori in DRF sono analoghi alle forme in Django.

Se non ti dispiace aggiungere un'altra dipendenza con DRF, che è davvero una grande libreria, questo probabilmente migliora la tua soluzione.

class MyModelSerializer(serializers.ModelSerializer): 

    class Meta: 
     model = MyModel 
     fields = '__all__' 


class MyModelDetail(generics.RetrieveUpdateAPIView): 
    queryset = MyModel.objects.all() 
    serializer_class = MyModelSerializer 
0

Ho risolto questo simile alla risposta di Roman Semko (che potrebbe non funzionare con campi ManyToMany):

Alter metodo del form __init__ per aggiornare i dati:

import urllib 

from django import forms 
from django.http import QueryDict 
from django.forms.models import model_to_dict 

class MyModelForm (forms.ModelForm): 
    class Meta: 
     model = MyModel 

    def __init__ (self, *args, **kwargs): 
     super(MyModelForm, self).__init__(*args, **kwargs) 

     # if form has being submitted and 
     # model instance exists, then get data 

     if self.is_bound and self.instance.pk: 

      # get current model values 
      modeldict = model_to_dict(instance) 
      modeldict.update(self.data.dict()) 

      # add instance values to data 
      urlencoded = urllib.urlencode(modeldict) 
      self.data = QueryDict(urlencoded) 
Problemi correlati