Я потратил немало времени, пытаясь найти решение, которое я мог бы повторно использовать на разных сайтах. Пост Джеймса содержал ключевую мудрость в расширении BaseInlineFormSet
, но в стратегическом плане призывы против BaseFormSet
.
Решение, приведенное ниже, разбито на две части: a AdminInline
и a BaseInlineFormSet
.
-
InlineAdmin
динамически генерирует начальное значение на основе выставленного объекта запроса.
- Он использует каррирование для предоставления начальных значений пользовательскому
BaseInlineFormSet
через аргументы ключевых слов, передаваемые в конструктор.
- Конструктор
BaseInlineFormSet
извлекает начальные значения из списка аргументов ключевого слова и обычно конструирует.
- Последняя часть переопределяет процесс создания формы, изменяя максимальное общее количество форм и используя методы
BaseFormSet._construct_form
и BaseFormSet._construct_forms
Вот некоторые конкретные фрагменты, использующие классы ОП. Я проверил это против Django 1.2.3. Я настоятельно рекомендую при разработке разрабатывать документацию formset и admin .
admin.py
from django.utils.functional import curry
from django.contrib import admin
from example_app.forms import *
from example_app.models import *
class AttendanceInline(admin.TabularInline):
model = Attendance
formset = AttendanceFormSet
extra = 5
def get_formset(self, request, obj=None, **kwargs):
"""
Pre-populating formset using GET params
"""
initial = []
if request.method == "GET":
#
# Populate initial based on request
#
initial.append({
'foo': 'bar',
})
formset = super(AttendanceInline, self).get_formset(request, obj, **kwargs)
formset.__init__ = curry(formset.__init__, initial=initial)
return formset
forms.py
from django.forms import formsets
from django.forms.models import BaseInlineFormSet
class BaseAttendanceFormSet(BaseInlineFormSet):
def __init__(self, *args, **kwargs):
"""
Grabs the curried initial values and stores them into a 'private'
variable. Note: the use of self.__initial is important, using
self.initial or self._initial will be erased by a parent class
"""
self.__initial = kwargs.pop('initial', [])
super(BaseAttendanceFormSet, self).__init__(*args, **kwargs)
def total_form_count(self):
return len(self.__initial) + self.extra
def _construct_forms(self):
return formsets.BaseFormSet._construct_forms(self)
def _construct_form(self, i, **kwargs):
if self.__initial:
try:
kwargs['initial'] = self.__initial[i]
except IndexError:
pass
return formsets.BaseFormSet._construct_form(self, i, **kwargs)
AttendanceFormSet = formsets.formset_factory(AttendanceForm, formset=BaseAttendanceFormSet)