Похоже, никто не говорил об этом варианте использования Pivot в добавлении к MapReduce. Существует хорошая статья, которая может быть вашим ответом здесь http://cookbook.mongodb.org/patterns/pivot/ Надеюсь, это поможет вам в ваших проектах
Я использовал бы functools.partial и functools.wraps:
from functools import partial, wraps
from django.forms.formsets import formset_factory
ServiceFormSet = formset_factory(wraps(ServiceForm)(partial(ServiceForm, affiliate=request.affiliate)), extra=3)
я думаю, что это - самый чистый подход и не влияет на ServiceForm всегда (т.е. мешая разделять на подклассы).
Мне нравится решение для закрытия за то, что оно было "инструментом для очистки" и большим количеством Pythonic (так +1 к ответу mmarshall), но формы Django также имеют механизм обратного вызова, который можно использовать для фильтрации querysets в formsets.
Это также не документируется, который я думаю, индикатор, Django devs не мог бы понравиться он так же.
, Таким образом, Вы в основном создаете свой formset то же, но добавляете обратный вызов:
ServiceFormSet = forms.formsets.formset_factory(
ServiceForm, extra=3, formfield_callback=Callback('option', affiliate).cb)
Это создает экземпляр класса, который похож на это:
class Callback(object):
def __init__(self, field_name, aff):
self._field_name = field_name
self._aff = aff
def cb(self, field, **kwargs):
nf = field.formfield(**kwargs)
if field.name == self._field_name: # this is 'options' field
nf.queryset = ServiceOption.objects.filter(affiliate=self._aff)
return nf
Это должно дать Вам общее представление. Это - немного более сложное создание обратного вызова метод объекта как это, но дает Вам немного больше гибкости в противоположность выполнению простого функционального обратного вызова.
Я создал бы класс формы динамично в функции, так, чтобы он имел доступ к филиалу через закрытие:
def make_service_form(affiliate):
class ServiceForm(forms.Form):
option = forms.ModelChoiceField(
queryset=ServiceOption.objects.filter(affiliate=affiliate))
rate = forms.DecimalField(widget=custom_widgets.SmallField())
units = forms.IntegerField(min_value=1,
widget=custom_widgets.SmallField())
return ServiceForm
В качестве награды, Вы не должны переписывать queryset в поле опции. Оборотная сторона - то, что разделение на подклассы немного броско. (Любой подкласс должен быть сделан похожим способом.)
редактирование:
В ответ на комментарий, можно вызвать эту функцию о любом месте, Вы использовали бы имя класса:
def view(request):
affiliate = get_object_or_404(id=request.GET.get('id'))
formset_cls = formset_factory(make_service_form(affiliate))
formset = formset_cls(request.POST)
...
I wanted to place this as a comment to Carl Meyers answer, but since that requires points I just placed it here. This took me 2 hours to figure out so I hope it will help someone.
A note about using the inlineformset_factory.
I used that solution my self and it worked perfect, until I tried it with the inlineformset_factory. I was running Django 1.0.2 and got some strange KeyError exception. I upgraded to latest trunk and it worked direct.
I can now use it similar to this:
BookFormSet = inlineformset_factory(Author, Book, form=BookForm)
BookFormSet.form = staticmethod(curry(BookForm, user=request.user))
Я потратил некоторое время, пытаясь выяснить эту проблему, прежде чем увидел эту публикацию.
Решение, которое я придумал, было решением для закрытия (и это решение, которое я использовал раньше с модельными формами Django).
Я попробовал метод curry (), как описано выше, но мне просто не удалось заставить его работать с Django 1.0, поэтому в конце концов я вернулся к методу закрытия.
Метод закрытия очень аккуратно, и единственная небольшая странность заключается в том, что определение класса вложено в представление или другую функцию. Я думаю, что тот факт, что мне это кажется странным, является зависанием от моего предыдущего опыта программирования, и я думаю, что кто-то с опытом работы с более динамичными языками не моргнет глазом!