2011-11-21 21 views
9

¿Cómo actualizo solo un campo en una instancia usando ModelForm si la solicitud POST solo tiene ese campo como parámetro? ModelField intenta anular los campos que no se pasaron en la solicitud POST con Ninguno que conduce a la pérdida de datos.Django actualiza un campo usando ModelForm

tengo un modelo con campos +25 decir

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

y tengo una aplicación de escritorio que hace las peticiones POST con el fin de editar una instancia de C a través de un método de API expuesta en views.py

En el método de la API estoy usando ModelForm para validar los campos de la siguiente manera:

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

al hacer save() django bien se queja de que algún otro campo no puede ser nulo o r (si todos los campos son opcionales) los sobrescribe con Ninguno.

¿Alguien sabe cómo administrarlo? Me gustaría hacer todos los cheques manualmente y actualizar de forma manual, pero el modelo tiene tan monstruosamente larga lista de campos ...

Respuesta

7

Se puede usar un subconjunto de los campos de su ModelForm especificando los campos de la siguiente manera:

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

a partir de los documentos:

Si especifica los campos o excluir al crear un formulario con ModelForm, a continuación los campos que no están en la forma resultante no serán fijados por método del formulario save().

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

+7

el problema es que hago no se sabe qué campo se va a actualizar: -/ –

10

tiene esta resuelto. Lo que hago es actualizar el diccionario request.POST con los valores de la instancia, para que todos los campos sin cambios estén presentes automáticamente. Esto lo hará:

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 

y luego se acaba de hacer:

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

Si k representa un campo ManyToMany, esto no funciona. – Erik

1

de Django ModelForm no está diseñado para manejar una actualización parcial de un subconjunto arbitrario de campos en el modelo.

El caso de uso descrito por el OP, una aplicación de escritorio que golpea una API, sería manejado mejor por Django Rest Framework.

Específicamente, crearía un serializador que hereda de ModelSerializer, y luego lo usa en un UpdateAPIView. Los serializadores en DRF son análogos a las formas en Django.

Si no le importa agregar otra dependencia con DRF, que es una gran biblioteca, probablemente sea mejor que lance su propia solución.

class MyModelSerializer(serializers.ModelSerializer): 

    class Meta: 
     model = MyModel 
     fields = '__all__' 


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

que resolvieron este similar a la respuesta de Romano Semko (que puede no funcionar con campos ManyToMany):

Alter método de su forma __init__ para actualizar los datos:

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) 
Cuestiones relacionadas