جانغو تمرير النموذج المخصص المعلمات Formset
-
05-07-2019 - |
سؤال
تم إصلاح هذا في جانغو 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
هو تسجيل الدخول المستخدم.هذا يعمل على النحو المنشود.
مشكلتي هي أنني الآن تريد أن تتحول إلى هذا الشكل الوحيد في formset.ما لا أستطيع فهمه هو كيف يمكن تمرير المعلومات التابعة لها إلى النماذج الفردية عند إنشاء formset.وفقا مستندات لجعل formset من هذا أريد أن أفعل شيئا مثل هذا:
ServiceFormSet = forms.formsets.formset_factory(ServiceForm, extra=3)
ثم كنت بحاجة إلى إنشاء مثل هذا:
formset = ServiceFormSet()
الآن كيف يمكنني تمرير التابعة لها=الطلب.انضم إلى النماذج الفردية من هذا الطريق ؟
المحلول
وأود أن استخدام functools.partial و <أ href ل = "http://docs.python.org/2/library/functools.html#functools.wraps" يختلط = "noreferrer"> 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
على سبيل المكافأة, لم يكن لديك إلى إعادة كتابة queryset في مجال الاختيار.الجانب السلبي هو أن subclassing هو قليلا غير تقليدي.(أي فئة فرعية ينبغي أن يتم بطريقة مماثلة.)
تحرير:
ردا على تعليق, يمكنك استدعاء هذه الدالة في أي مكان كنت تستخدم اسم الفئة:
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):
ونأمل أن يساعد شخص ما، أخذ مني وقتا طويلا بما فيه الكفاية لمعرفة ذلك.)
وأنا أحب الحل إغلاق لكونها "نظافة" وأكثر Pythonic (ما +1 لmmarshall الجواب)، ولكن أشكال جانغو دينا أيضا آلية الاستدعاء يمكنك استخدامها للمجموعات طلبات الترشيح في formsets.
وأيضا يتم توثيقها و، وهو ما أعتقد أنه مؤشر على المشروعات الإنمائية جانغو قد لا ترغب في ذلك قدر.
وهكذا كنت في الأساس إنشاء 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
وهذا يجب أن تعطيك فكرة عامة. انها قليلا أكثر تعقيدا مما يجعل رد أسلوب كائن مثل هذا، ولكن يمنحك مزيدا من المرونة قليلا بدلا من القيام دالة رد بسيط.
وكنت أرغب في وضع هذا بمثابة تعليق على كارل مايرز الجواب، ولكن منذ ذلك يتطلب نقاط أنا فقط وضعها هنا. هذا وقد كلفني 2 ساعة لمعرفة ذلك آمل أن يساعد شخص ما.
ملاحظة حول استخدام inlineformset_factory.
ولقد استخدمت هذا الحل نفسي وعملت الكمال، حتى حاولت ذلك مع inlineformset_factory. لقد تم تشغيل جانغو 1.0.2 وحصلت على بعض استثناء KeyError غريب. I ترقية إلى أحدث الجذع وعملت مباشرة.
وأستطيع الآن استخدامها مشابهة لهذه:
BookFormSet = inlineformset_factory(Author, Book, form=BookForm)
BookFormSet.form = staticmethod(curry(BookForm, user=request.user))
كما من ارتكاب e091c18f50266097f648efc7cac2503968e9d217 في الثلاثاء أغسطس 14 23:44:46 2012 +0200 الحل المقبول لا يمكن أن تعمل بعد الآن.
الإصدار الحالي من جانغو.أشكال.نماذج.modelform_factory() وظيفة يستخدم "نوع تقنية البناء" ، داعيا نوع() الدالة على تمرير النموذج للحصول على metaclass نوع ، ثم باستخدام يؤدي إلى بناء فئة الكائن من نوعه على الطاير::
# Instatiate type(form) in order to use the same metaclass as form.
return type(form)(class_name, (form,), form_class_attrs)
هذا يعني حتى curry
اد أو partial
يمر الجسم بدلا من نموذج "أسباب البطة إلى لدغة لك" إذا جاز التعبير:سوف استدعاء دالة البناء المعلمات ModelFormClass
كائن إرجاع رسالة الخطأ::
function() argument 1 must be code, not str
كمحاولة للتغلب على هذه كتبت وظيفة مولد يستخدم إغلاق للعودة فئة فرعية من أي فئة محددة كما المعلمة الأولى, ثم يدعو super.__init__
بعد update
جي kwargs مع تلك المتوفرة على وظيفة مولد دعوة::
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))
المحاذير:
- هذا تلقى القليل جدا من الاختبار ، على الأقل حتى الآن
- تزويد المعلمات يمكن أن الصدام و الكتابة تلك المستخدمة من قبل أيا كان الرمز استخدام كائن إرجاعها من قبل منشئ
وحل كارل ماير تبدو أنيقة جدا. حاولت تنفيذها لmodelformsets. كنت تحت انطباع بأنني لا يمكن أن نطلق staticmethods ضمن فئة، ولكن ما يلي يعمل لسبب غير مفهوم:
class MyModel(models.Model):
myField = models.CharField(max_length=10)
class MyForm(ModelForm):
_request = None
class Meta:
model = MyModel
def __init__(self,*args,**kwargs):
self._request = kwargs.pop('request', None)
super(MyForm,self).__init__(*args,**kwargs)
class MyFormsetBase(BaseModelFormSet):
_request = None
def __init__(self,*args,**kwargs):
self._request = kwargs.pop('request', None)
subFormClass = self.form
self.form = curry(subFormClass,request=self._request)
super(MyFormsetBase,self).__init__(*args,**kwargs)
MyFormset = modelformset_factory(MyModel,formset=MyFormsetBase,extra=1,max_num=10,can_delete=True)
MyFormset.form = staticmethod(curry(MyForm,request=MyFormsetBase._request))
في رأيي، إذا كنت تفعل شيئا من هذا القبيل:
formset = MyFormset(request.POST,queryset=MyModel.objects.all(),request=request)
وبعد ذلك يحصل نشر على "طلب" الكلمة الرئيسية لجميع أشكال عضوا في بلدي formset. يسعدني، ولكن ليس لدي فكرة لماذا يعمل هذا - على ما يبدو خاطئا. أي اقتراحات؟
وقضيت بعض الوقت في محاولة لمعرفة هذه المشكلة قبل أن أرى هذا النشر.
وكان الحل خطرت لي الحل إغلاق (وهذا هو الحل لقد استعملت من قبل مع استمارات نموذجية جانغو).
وحاولت طريقة الكاري () كما هو موضح أعلاه، ولكن أنا فقط لا يمكن الحصول عليها للعمل مع جانغو 1.0 وذلك في نهاية I عادت إلى أسلوب الإغلاق.
وأسلوب الإغلاق هو أنيق جدا والغرابة طفيفة فقط هو أن تعريف فئة غير متداخلة داخل طريقة العرض أو وظيفة أخرى. أعتقد أن هذا يبدو غريبا بالنسبة لي هو اغلاق الخط من تجربتي البرمجة السابقة، وأعتقد أن أي شخص لديه خلفية في لغات أكثر ديناميكية لن الخفافيش له جفن!
وكان علي أن أفعل شيئا مماثلا. هذا هو مماثل لحل curry
:
def form_with_my_variable(myvar):
class MyForm(ServiceForm):
def __init__(self, myvar=myvar, *args, **kwargs):
super(SeriveForm, self).__init__(myvar=myvar, *args, **kwargs)
return MyForm
factory = inlineformset_factory(..., form=form_with_my_variable(myvar), ... )
وأنا مبتدئ هنا لذلك لا أستطيع إضافة تعليق. آمل أن هذا الرمز يعمل أيضا:
ServiceFormSet = formset_factory(ServiceForm, extra=3)
ServiceFormSet.formset = staticmethod(curry(ServiceForm, affiliate=request.affiliate))
وكما لإضافة معلمات إضافية إلى BaseFormSet
في formset بدلا من النموذج.
هذه الإجابة وجدت مزيد من حل واضح:
class ServiceForm(forms.Form):
option = forms.ModelChoiceField(
queryset=ServiceOption.objects.filter(affiliate=self.affiliate))
rate = forms.DecimalField(widget=custom_widgets.SmallField())
units = forms.IntegerField(min_value=1,
widget=custom_widgets.SmallField())
@staticmethod
def make_service_form(affiliate):
self.affiliate = affiliate
return ServiceForm
وتشغيله في عرض مثل
formset_factory(form=ServiceForm.make_service_form(affiliate))