[python] Django가 사용자 정의 양식 매개 변수를 Formset에 전달
이것은 Django 1.9에서 form_kwargs 로 수정되었습니다 .
다음과 같은 장고 양식이 있습니다.
class ServiceForm(forms.Form):
option = forms.ModelChoiceField(queryset=ServiceOption.objects.none())
rate = forms.DecimalField(widget=custom_widgets.SmallField())
units = forms.IntegerField(min_value=1, widget=custom_widgets.SmallField())
def __init__(self, *args, **kwargs):
affiliate = kwargs.pop('affiliate')
super(ServiceForm, self).__init__(*args, **kwargs)
self.fields["option"].queryset = ServiceOption.objects.filter(affiliate=affiliate)
이 양식을 다음과 같이 부릅니다.
form = ServiceForm(affiliate=request.affiliate)
request.affiliate
로그인 한 사용자는 어디에 있습니까 ? 의도 한대로 작동합니다.
내 문제는 이제이 단일 양식을 양식 세트로 바꾸고 싶다는 것입니다. 내가 알 수없는 것은 양식 세트를 만들 때 가맹 정보를 개별 양식에 전달하는 방법입니다. 이것으로부터 폼셋을 만드는 문서에 따르면 나는 다음과 같이해야합니다.
ServiceFormSet = forms.formsets.formset_factory(ServiceForm, extra=3)
그런 다음 다음과 같이 만들어야합니다.
formset = ServiceFormSet()
이제 이런 식으로 계열사 = request.affiliate를 개별 양식에 어떻게 전달할 수 있습니까?
답변
내가 사용하는 것이 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에 영향을 미치지 않습니다 (즉, 서브 클래스 화를 어렵게 함).
답변
공식 문서 방법
장고 2.0 :
ArticleFormSet = formset_factory(MyArticleForm)
formset = ArticleFormSet(form_kwargs={'user': request.user})
답변
함수에서 폼 클래스를 동적으로 작성하여 클로저를 통해 가맹점에 액세스 할 수 있습니다.
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
보너스로 옵션 필드에서 쿼리 세트를 다시 작성할 필요가 없습니다. 단점은 서브 클래 싱이 약간 펑키하다는 것입니다. (하위 클래스는 비슷한 방식으로 만들어야합니다.)
편집하다:
주석에 대한 응답으로 클래스 이름을 사용할 장소에 대해이 함수를 호출 할 수 있습니다.
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)
...
답변
이것이 장고 1.7에서 나를 위해 일한 것입니다.
from django.utils.functional import curry
lols = {'lols':'lols'}
formset = modelformset_factory(MyModel, form=myForm, extra=0)
formset.form = staticmethod(curry(MyForm, lols=lols))
return formset
#form.py
class MyForm(forms.ModelForm):
def __init__(self, lols, *args, **kwargs):
그것이 누군가를 도울 수 있기를 바랍니다.
답변
나는 “깨끗한”그리고 더 파이썬적인 (따라서 +1 ~ mmarshall 답변) 클로저 솔루션을 좋아하지만 Django 폼에는 폼 세트에서 쿼리 세트를 필터링하는 데 사용할 수있는 콜백 메커니즘이 있습니다.
또한 장고 개발자가 좋아하지 않을만한 지표라고 생각합니다.
따라서 기본적으로 폼셋을 동일하게 만들지 만 콜백을 추가하십시오.
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
이것은 일반적인 아이디어를 제공해야합니다. 콜백을 이와 같은 객체 메소드로 만드는 것은 조금 더 복잡하지만 간단한 함수 콜백을 수행하는 것과는 달리 약간의 유연성을 제공합니다.
답변
나는 이것을 Carl Meyers 답변에 대한 의견으로 배치하고 싶었지만 포인트가 필요하기 때문에 여기에 배치했습니다. 알아내는 데 2 시간이 걸렸으므로 누군가에게 도움이되기를 바랍니다.
inlineformset_factory 사용에 대한 참고 사항입니다.
나는 그 솔루션을 내 자신으로 사용했으며 inlineformset_factory로 시도 할 때까지 완벽하게 작동했습니다. Django 1.0.2를 실행 중이며 이상한 KeyError 예외가 발생했습니다. 최신 트렁크로 업그레이드했으며 직접 작동했습니다.
이제 다음과 비슷한 것을 사용할 수 있습니다.
BookFormSet = inlineformset_factory(Author, Book, form=BookForm)
BookFormSet.form = staticmethod(curry(BookForm, user=request.user))
답변
커밋 e091c18f50266097f648efc7cac2503968e9d217 8 월 14 일 23:44:46 2012 +0200에 접수 된 솔루션은 더 이상 작동하지 않습니다.
django.forms.models.modelform_factory () 함수의 현재 버전은 “유형 생성 기술”을 사용하여 전달 된 폼에서 type () 함수를 호출하여 메타 클래스 유형을 가져온 다음 결과를 사용하여 클래스 객체를 생성합니다. 즉석에서 입력 ::
# Instatiate type(form) in order to use the same metaclass as form.
return type(form)(class_name, (form,), form_class_attrs)
이것은 양식 대신에 curry
ed 나 partial
객체 라도 “오리가 당신을 물게 만든다”는 말을 의미합니다. ModelFormClass
객체 의 구성 매개 변수를 가진 함수를 호출하고 다음과 같은 오류 메시지를 반환합니다.
function() argument 1 must be code, not str
이 문제를 해결하기 위해 클로저를 사용하여 첫 번째 매개 변수로 지정된 클래스의 하위 클래스를 반환하는 생성기 함수를 작성했습니다. 그런 다음 생성기 함수의 호출에 제공된 클래스로 kwargs 를 호출 super.__init__
한 후 호출 update
합니다.
def class_gen_with_kwarg(cls, **additionalkwargs):
"""class generator for subclasses with additional 'stored' parameters (in a closure)
This is required to use a formset_factory with a form that need additional
initialization parameters (see http://stackoverflow.com/questions/622982/django-passing-custom-form-parameters-to-formset)
"""
class ClassWithKwargs(cls):
def __init__(self, *args, **kwargs):
kwargs.update(additionalkwargs)
super(ClassWithKwargs, self).__init__(*args, **kwargs)
return ClassWithKwargs
그런 다음 코드에서 폼 팩토리를 다음과 같이 호출합니다.
MyFormSet = inlineformset_factory(ParentModel, Model,form = class_gen_with_kwarg(MyForm, user=self.request.user))
경고 :
- 최소한 지금은 거의 테스트를받지 못했습니다.
- 제공된 매개 변수는 생성자가 반환 한 개체를 사용하는 코드에서 사용하는 매개 변수를 충돌 및 덮어 쓸 수 있습니다.