Создание экземпляра ModelForm с заменой полей модели

#django #django-forms

#django #django-forms

Вопрос:

У меня есть поле ModelForm, основанное на следующей модели:

 class Phrase(models.Model):
   subject = models.ForeignKey(Entity) # Entity is unique on a per Entity.name basis
   object = models.ForeignKey(Entity) # Entity is unique on a per Entity.name basis
  

В modelform (PhraseForm) есть поле ‘subject’, которое является символьным полем. Я хочу, чтобы пользователи могли вводить строку. Когда modelform сохраняется, а строка не соответствует существующему объекту, создается новый объект.

Вот почему мне пришлось перезаписать поле «subject» формы модели, поскольку я не могу использовать автоматически сгенерированное поле «subject» формы модели (надеюсь, я здесь ясно выражаюсь).

Теперь все тесты выполняются нормально при создании новой фразы через modelform. Но при изменении фразы:

 p = Phrase.objects.latest()
pf = PhraseForm({'subject': 'anewsubject'}, instance=p).
  

pf.is_valid() возвращает False. Ошибка, которую я получаю, заключается в том, что «объект» не может быть None. Это имеет смысл, поскольку поле объекта действительно не было заполнено.

Каков был бы наилучший способ справиться с этим? Я мог бы, конечно, проверить, предоставлен ли экземпляр в функции init() фразеформы, а затем присвоить отсутствующие значения полей из переданного экземпляра. Мне кажется, что это неправильный способ, так есть ли менее громоздкий способ убедиться, что данные экземпляра передаются через ModelForm?

Теперь, когда я набираю это, я предполагаю, что это не так, поскольку базовые поля модели перезаписываются, что означает, что значения полей формы должны быть заполнены снова, чтобы все работало нормально. Что заставляет меня перефразировать мой вопрос: является ли способ, которым я разрешил пользователям вводить произвольный текст и связывать это с новым или существующим объектом, правильным способом сделать это?

Заранее спасибо!

Ответ №1:

Почему вы изменяете форму с помощью.

 p = Phrase.objects.latest()
p.subject = Entity.objects.get_or_create(name='anewsubject')[0]
  

docs для get_or_create

Если вы действительно используете форму, она должна работать нормально:

 def mod_phrase(request, phrase_id=None):
    phrase = get_object_or_404(Phrase, pk=phrase_id)

    if request.method == 'POST':
        form = PhraseForm(request.POST, instance=phrase)
        if form.is_valid():
            form.save()
            return HttpResponse("Success")
    else:
        form = PhraseForm(instance=phrase)

    context = { 'form': form }

    return render_to_response('modify-phrase.html', context,
        context_instance=RequestContext(request))
  

Установка экземпляра для ModelForm задает исходные данные, а также позволяет форме узнать, с каким объектом работает форма. То, как вы пытаетесь использовать форму, вы передаете недопустимый data словарь (отсутствуют object ), о котором форма правильно сообщает вам, что он недействителен. Когда вы устанавливаете data значение request.POST в request.POST приведенном выше примере, в него включаются исходные данные, которые позволяют форме проверять правильность.

Комментарии:

1. Ах, черт. Перечитав это, я понимаю, что форма, естественно, ожидает данных для всех полей. Мне следовало сделать перерыв, прежде чем публиковать свой запутанный вопрос… (Кстати, я использую get_or_create, но внутри формы, чтобы преобразовать пользовательский ввод в новую или существующую сущность).