it-swarm.com.ru

Django ModelForm с дополнительными полями, которых нет в модели

Я сделал ModelForm, добавив некоторые дополнительные поля, которые не в модели. Я использую эти поля для некоторых расчетов при сохранении формы.

Дополнительные поля появляются в форме и отправляются в запросе POST при загрузке формы. Проблема в том, что они не добавляются в словарь cleaned_data, когда я проверяю форму. Как я могу получить к ним доступ?

31
Antonio Melé

Возможно расширение Django ModelForm дополнительными полями. Представьте, что у вас есть пользовательская модель пользователя и эта ModelForm:

class ProfileForm(forms.ModelForm):

    class Meta:
        model = User
        fields = ['username', 'country', 'website', 'biography']

Теперь представьте, что вы хотите включить дополнительное поле (не присутствует в вашей пользовательской модели, скажем, аватар изображения). Расширьте свою форму, выполнив это:

from Django import forms

class AvatarProfileForm(ProfileForm):

    profile_avatar = forms.ImageField()

    class Meta(ProfileForm.Meta):
        fields = ProfileForm.Meta.fields + ('profile_avatar',)

Наконец (учитывая, что форма имеет ImageField), не забудьте включить request.FILES при создании экземпляра формы в вашем представлении:

# (view.py)

def edit_profile(request):
    ...
    form = AvatarProfileForm(
        request.POST or None, 
        request.FILES or None, 
        instance=request.user
    )
    ...

Надеюсь, поможет. Удачи!

Правка: 

В атрибуте AvatarProfileForm.Meta.fields я получаю сообщение об ошибке «могу только объединить Tuple (не« list ») в Tuple» ». Поменял его на кортеж и все заработало.

20
Cartucho

Во-первых, у вас не должно быть полей artist_id и artist. Они построены по модели. Если вам нужно имя исполнителя, добавьте поле artist_name, то есть CharField .

Кроме того, вы пытаетесь получить что-то из cleaned_data внутри чистого значения. Возможно, вам не нужны данные - вы должны использовать значения из self.data, где данные находятся непосредственно из POST.

5
gruszczy

Этот ответ может быть слишком поздно для оригинального постера, но я подумал, что он может помочь другим. У меня была та же проблема, и я заметил, что self.cleaned_data ('artist_id') может быть доступен в методе clean (), но не в clean_artist (). 

Когда я добавил дополнительные поля в объявлении Meta 'fields', это сработало.

    class Meta:
        model = Music
        fields=[..., 'artist_id']

Вы должны иметь доступ к self.cleaned_data ('artist_id') в clean_artist (). 

4
B. Choung

Хорошо, я решил это. Кажется, что доступ к дополнительным полям с помощью cleaned_data ['field_name'] вызывает KeyError, но использование cleaned_data.get ('field_name') работает. Это странно, потому что к нормальным полям модели можно получить доступ через cleaned_data ['field_name'].

Обновление: Нет, это не работает. С get () он не вызывает KeyError, но устанавливает значение None, потому что дополнительные поля отсутствуют в словаре cleaned_data.

Вот код В шаблонах есть автозаполнение, поэтому в форме есть поле «Artist», отображаемое как CharField, и скрытое IntegerField, которое будет автоматически заполнено указанным идентификатором Artist. В методе clean_artist я хочу выбрать объект Artist и сохранить его в поле Artist формы.

models.py

class Music(models.Model):
    artist = models.ForeignKey(Artist, related_name='music', blank=True, null=True)
    # other fields...

forms.py

class MusicForm(forms.ModelForm):
    artist_id = forms.IntegerField(label="", widget=forms.HiddenInput(), required=False)
    artist = forms.CharField(required=False)
    # other fields ...

    class Meta:
        model = Music

    def clean_artist(self):
        if self.cleaned_data.get('artist') == '':
            artist = None
        else:
            artist_id = self.cleaned_data.get('artist_id') # this returns always None because artist_id is not in cleaned_fields (this seemed to work with previous Django versions but not with current SVN version)
            if artist_id != None:
                artist = Artist.objects.get(id=artist_id)
            else:
                artist = None

    return artist
2
Antonio Melé

У меня была очень похожая проблема, за исключением того, что казалось, что я сделал все необходимое, но я получал эту ошибку, когда запускался Django:

Django.core.exceptions.FieldError: Unknown field(s) (my_new_field) specified for MyModel

Это было моей глупой ошибкой, я случайно объявил свое поле, используя Widget class:

class MyForm(forms.ModelForm):
    my_new_field = forms.HiddenInput()

Вместо Поле Класс:

class MyForm(forms.ModelForm):
    my_new_field = forms.CharField(widget=forms.HiddenInput())

Не отвечая на данный вопрос (на который уже дан хороший ответ), но может помочь другим.

2
Bruno A.

Сначала добавьте поле в форму

class CreateForm(forms.ModelForm):

extra_field     = forms.CharField(label = 'extra_field', required = False)

Теперь при очистке данных вам нужно извлечь дополнительное поле из self.dataNOTself.cleaned_data

Правильный :

 self.data.get('extra_field')

Неправильно :

 self.cleaned_data.get('extra_field')
0
Sreeram