2011-11-21 241 views
9

如果POST請求只有一個字段作爲參數,如何使用ModelForm更新實例中的一個字段? ModelField嘗試覆蓋POST請求中未傳遞的字段,其中None導致數據丟失。Django使用ModelForm更新一個字段

我有+25領域模型說

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

,我有一個桌面應用程序,不POST請求,以便通過一個公開的API方法views.py

編輯C的實例

在API方法我使用的ModelForm驗證字段如下:

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

當這樣做節省()要麼Django的抱怨一些其它字段不能爲空ö r(如果所有字段都是可選的)用None覆蓋它們。

有人知道如何管理它嗎?我會做手工所有檢查和手動更新,但該模型領域的這樣異想天開的長列表...

回答

7

你可以通過指定這些字段使用您的ModelForm領域的一個子集,如下所示:

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

從文檔:

如果指定的字段或排除創建具有的ModelForm形式, 那麼是不是在生成的表單字段將不會被 形式的save()方法來設置時。

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

+7

問題是我做的不知道哪個字段將被更新: -/ –

10

得到這個想通。我所做的是使用實例中的值更新request.POST字典 - 以便所有未更改的字段自動顯示。這將做到這一點:

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 

,然後你只是做:

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

如果k代表ManyToMany字段,則不起作用。 – Erik

1

Django的ModelForm是不是設計來處理的模型字段的任意子集的部分更新。

由OP描述的用例(桌面應用程序觸擊API)將由Django Rest Framework更好地處理。

具體而言,您將創建一個繼承自ModelSerializer的序列化程序,然後在UpdateAPIView中使用它。 DRF中的序列化器類似於Django中的表單。

如果您不介意添加DRF的另一個依賴項,這是一個非常棒的庫,這可能會打敗您自己的解決方案。

class MyModelSerializer(serializers.ModelSerializer): 

    class Meta: 
     model = MyModel 
     fields = '__all__' 


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

我解決了這個類似羅馬塞姆科的答案(這可能不與多對多下地幹活):

改變窗體的__init__方法來更新數據:

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)