Почему известный действующий экземпляр модели Django завершается ошибкой is_valid () после извлечения из базы данных? - PullRequest
2 голосов
/ 04 марта 2010

У нас есть Django Model, ToolDataset и ModelForm, ToolForm. В модели каждый экземпляр или строка базы данных называется набором данных, а первичный ключ называется dataset_id. Впервые пользователь заполняет несвязанную форму и отправляет ее. Концептуально, это код представления, который используется для проверки, сохранения и анализа набора данных:

if (request.method == 'POST') and (not dataset_id):
    form = ToolForm(request.POST)
    if form.is_valid():
        new_dataset = form.save()
        dataset_id = new_dataset.pk
        results = analyze(form.cleaned_data)
    else:
        <validation error code>

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

Теперь проходит некоторое время, и пользователь хочет вернуться к этому конкретному старому набору данных, возможно, чтобы изменить данные и повторно проанализировать их. Таким образом, любым способом составляется URL, который выглядит как www.finesite.com/Tool/X/, где X - это набор данных, соответствующий определенной строке данных, с которой пользователь хочет работать. Через URLconf вызывается другая ветвь кода представления, которая, по нашему мнению, должна выглядеть следующим образом:

if (request.method != 'POST') and (dataset_id):
    oldset = get_object_or_404(ToolDataset, pk=dataset_id)
    form = ToolForm(instance=oldset)
    if form.is_valid():
        results = analyze(form.cleaned_data)
    else:
        <validation error code that we expected would never run>

Ну, как оказалось, этот набор данных, который был действителен, когда мы его сохранили, сейчас не проверяет, что является сюрпризом. Мы использовали оболочку manage.py, чтобы немного осмотреть форму. Вот что мы нашли:

>>> form.is_valid()
False
>>> form.errors
{}
>>> form.non_field_errors()
[]
>>> form.is_bound
False

Запуск form.as_p() дает то, что кажется полной формой.

Очень способный сотрудник нашел недокументированную API-функцию, известную как model_to_dict () в django / forms / models.py. Он предложил заменить это,

form = BXEEP_L_Form(model_to_dict(oldset), instance=oldset),

для этого

form = BXEEP_L_Form(instance=oldset).

Теперь это работает - форма действительна и привязана, согласно оболочке, - но я полон вопросов. Почему это работает? Почему это необходимо? Есть ли более стандартный способ сделать это? Кажется странным использовать недокументированную внутреннюю функцию для варианта использования, который кажется настолько обычным и несложным.

Ответы [ 3 ]

3 голосов
/ 04 марта 2010

form.is_valid() проверяет form.data dict, который отправляется через конструктор для Form(data=request.POST)

ModelForm.instance связывает данные с определенной строкой таблицы, так что сохранение обязательно выполняет обновление, а не вставку. Это также передается через конструктор.

Оба они, однако, независимы друг от друга. Если вы хотите создать форму с данными старого экземпляра, вы должны сделать следующее:

ToolForm(data=oldinstance.__data__, instance=oldinstance)

Однако, возможно, вы не хотите связывать данные сразу.

ToolForm(instance=oldinstance)

заполняет правильные значения из экземпляра при его отображении в HTML и обновляет запись, только если экземпляр ToolForm is_changed()

1 голос
/ 04 марта 2010

Я, вероятно, что-то неправильно понимаю, но мне кажется, что ваша analyze функция не должна принимать form.cleaned_data в качестве ввода, а скорее dataset_id.

В случае, если пример не завершен - почемувы создаете форму из набора данных для ее анализа?

0 голосов
/ 04 марта 2010

Мы изменили аргумент для функции анализа на экземпляр модели вместо form.cleaned_data. Это отделяет анализ от проверки формы и является гораздо более разумным. Концептуально вторая часть приведенного выше кода теперь выглядит следующим образом:

if (request.method != 'POST') and (dataset_id):
        oldset = get_object_or_404(ToolDataset, pk=dataset_id)
        form = ToolForm(instance=oldset)
        results = analyze(oldset)

Конечно, распаковка данных во главе функции анализа должна была быть несколько переписана.

Теперь все кажется очевидным. Спасибо всем за проявленный интерес!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...