Джанго обновить одно поле с помощью ModelForm - PullRequest
11 голосов
/ 21 ноября 2011

Как обновить только одно поле в экземпляре, используя ModelForm, если в запросе POST в качестве параметра указано только это поле? ModelField пытается переопределить поля, которые не были переданы в запросе POST, и None приводит к потере данных.

У меня есть модель с +25 полями, скажем

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

и у меня есть настольное приложение, которое выполняет POST-запросы для редактирования экземпляра C с помощью открытого метода api в views.py

В методе API я использую ModelForm для проверки полей следующим образом:

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

При выполнении save () django либо жалуется на то, что какое-то другое поле не может быть пустым, либо (если все поля являются необязательными) заменяет их на None.

Кто-нибудь знает, как им управлять? Я бы делал все проверки вручную и обновлял вручную, но в модели так странно длинный список полей ...

Ответы [ 5 ]

12 голосов
/ 22 ноября 2011

Поняла это.Что я делаю, так это обновляю словарь 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)
8 голосов
/ 21 ноября 2011

Вы можете использовать подмножество полей в 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

1 голос
/ 19 апреля 2017

Я решил это подобно ответу Романа Семко (который может не работать с полями ManyToMany):

Измените метод __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 )
1 голос
/ 23 марта 2017

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 голосов
/ 14 ноября 2018

Ну, вы должны создать метод для инициализации формы с отсутствующими данными в вашем запросе, что-то вроде:

class MyModel(Model):
    ... your model ...

    def initial(self,data):
        fields = [list of possible fields here]

        for field in fields:
            if data.get(field) is None:
                data[field] = getattr(self,field)

        return data

Затем передайте эти данные в вашей форме, например:

form = MyForm(instance.initial(request.POST.copy()),instance=instance)

для JSON:

from json import loads

form = MyForm(instance.initial(loads(request.body)),instance=instance)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...