То, что часто упускается из виду, это commit=False
и возможность обрабатывать более одной формы или набора форм в одном представлении. Таким образом, вы можете иметь набор форм для поездок, а также форму для загрузки и обрабатывать информацию, создавая все объекты после проверки всех форм.
Вот схема с реструктурированным представлением, которую я использую для обработки нескольких форм (не редактировал имена, указанные в приложении c, не хочу вводить ошибки):
def receive_uncoated( request): #Function based view
# let's put form instantiation in one place not two, and reverse the usual test. This
# makes for a much nicer layout with actions not sandwiched by "boilerplate"
# note any([ ]) forces invocation of both .is_valid() methods
# so errors in second form get shown even in presence of errors in first
args = [request.POST, ] if request.method == "POST" else []
batchform = CreateUncWaferBatchForm( *args )
po_form = CreateUncWaferPOForm( *args, prefix='po')
if request.method != "POST" or any(
[ not batchform.is_valid(), not po_form.is_valid() ]):
return render(request, 'wafers/receive_uncoated.html', # can get this out of the way at the top
{'batchform': batchform,
'po_form': po_form,
})
#POST, everything is valid, do the work
# create and save some objects based on the validated forms ...
return redirect( 'wafers:ok' )
NB использование any
жизненно важно. Это позволяет избежать Python краткой оценки условного выражения и, следовательно, делает все ошибки во второй и последующих формах доступными для пользователя, даже если первая форма не прошла проверку.
Вернемся к этому вопросу: вы бы заменили batch_form на trip_form и po_form с ModelFormset для загрузки. После проверки формы и набора форм вы создадите все запрошенные объекты, используя
trip = trip_form.save( commit=False)
load_list = loads_formset.save( commit = False)
# fill in some related object in trip then save trip
foo = Foo.objects.get( ...)
trip.foo = foo
trip.save()
# link loads to trip and save them
for load in load_list:
load.trip = trip
load.save()
Возможно, вы захотите выполнить это в транзакции, чтобы в случае сбоя (DatabaseError
) сохранить один из загружается, вы не получаете частичную trip
, хранящуюся в базе данных, а скорее получаете все обратно.