سؤال

تم إصلاح هذا في جانغو 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})

الشبكي: / /docs.djangoproject.com/en/2.0/topics/forms/formsets/#passing-custom-parameters-to-formset-forms

وأود أن بناء شكل الطبقة حيوي في وظيفة ، حتى أنه لديه حق الوصول إلى التابعة لها عبر إغلاق:

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))
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top