2009-08-21 2 views
18

У меня есть модельный набор, который мне нужно передать ключевому слову initial in to (чтобы иметь некоторые начальные значения в наборе форм, например дата, установленная сегодня). Насколько я могу судить, аргумент queryset (который по умолчанию относится к MyModel.objects.all()) переопределяет эту способность для создания пустых форм. Я задал запрос как: YourModel.objects.none(), который не позволяет ему заполнить набор форм записями из базы данных, но я до сих пор не могу понять, как эффективно проходить исходный код. Мне нужно подклассифицировать метод из ModelForm?Передача начального значения в ModelFormSet Django

+1

Вы хотите изменить конкретный экземпляр модели, но не хотите отображать существующие значения и вместо этого отображать разные начальные значения? –

ответ

0

Простым решением может быть то, что вы передаете форму, которая расширяет форму модели() до набора форм (а не modelformset).

Таким образом, вы можете установить начальные значения в форме.

+1

Можете ли вы рассказать об этом? Я не уверен, что понимаю, что вы имеете в виду. – Vince

0

Я думаю, что вы можете использовать первоначальный аргумент, так как с регулярным FormSets http://docs.djangoproject.com/en/dev/topics/forms/formsets/#using-initial-data-with-a-formset

+0

Да, если это был обычный набор форм, это возможно. Однако этот набор форм был сгенерирован с помощью modelformset_factory(). – Vince

2

Это еще можно пройти начальные к ModelFormSet.

from django.forms.models import modelformset_factory 
from example.models import ExampleModel 

ExampleModelFormSet = modelformset_factory(ExampleModel) 
formset = ExampleModelFormSet(initial=[{'name': 'Some Name'}, 
             {'name': 'Another Name'}]) 

Если это не то, что вы после, можете ли вы объяснить свой вопрос больше.

EDIT:

ExampleModelFormSet = modelformset_factory(ExampleModel, extra=2) 
formset = ExampleModelFormSet(queryset=ExampleModel.objects.none(), 
           initial=[{'name': 'Some Name'}, 
             {'name': 'Another Name'}]) 
+0

По умолчанию набор форм Django заполняет себя результатами вашего файла .mode.objects.all(). Это можно изменить с помощью queryset = yourmodel.objects.none(), но это все еще не позволяет использовать начальные значения. Что-то в том, что набор запросов и исходных ключевых слов делает это неработоспособным. – Vince

+0

Как это не работает, что он не делает? Используя обновленный код, я получаю набор форм из пустого набора запросов и начальных значений, заполненных. – Gerry

+0

Да, это путь. Согласен. – simplyharsh

8

Вы передаете пустой QuerySet в ModelFormset.

ExampleModelFormSet = modelformset_factory(ExampleModel, extra=2) 
formset = ExampleModelFormSet(queryset=ExampleModel.objects.none(), 
          initial=[{'name': 'Some Name'}, 
            {'name': 'Another Name'}]) 

, который действительно является способом достижения желаемого. Имеет смысл передать пустой запрос, иначе начальные значения переопределяют значение базы данных модели.

И если я полагаю, вы передаете непустой запрос, и все же хотите, чтобы ваши дополнительные формы были заполнены, будут начальные значения, вы можете переопределить Formset.

from django.forms.models import modelformset_factory 
ExampleFormset = modelformset_factory(OpenIDProfile, extra=3) 

class myFormset(ExampleFormset): 

    def _construct_form(self, i, **kwargs): 
     """ 
     Instantiates and returns the i-th form instance in a formset. 
     """ 
     if self.is_bound and i < self.initial_form_count(): 
      pk_key = "%s-%s" % (self.add_prefix(i), self.model._meta.pk.name) 
      pk = self.data[pk_key] 
      pk_field = self.model._meta.pk 
      pk = pk_field.get_db_prep_lookup('exact', pk) 
      if isinstance(pk, list): 
       pk = pk[0] 
      kwargs['instance'] = self._existing_object(pk) 
     if i < self.initial_form_count() and not kwargs.get('instance'): 
      kwargs['instance'] = self.get_queryset()[i] 

     defaults = {'auto_id': self.auto_id, 'prefix': self.add_prefix(i)} 
     if self.data or self.files: 
      defaults['data'] = self.data 
      defaults['files'] = self.files 
     # Check to confirm we are not overwriting the database value. 
     if not i in range(self.initial_form_count()) and self.initial: 
      try: 
       defaults['initial'] = self.initial[i - self.initial_form_count()] 
      except IndexError: 
       pass 
     # Allow extra forms to be empty. 
     if i >= self.initial_form_count(): 
      defaults['empty_permitted'] = True 
     defaults.update(kwargs) 
     form = self.form(**defaults) 
     self.add_fields(form, i)   
     return form 

Примечание: initial - это список диктов. Желательно иметь элементы в списке, в точности равные количеству дополнительных.

+1

Один трюк, который достал меня здесь, заключается в том, что вы должны установить больше, чем или равное количеству элементов в ваших исходных данных. Я знаю, что это в вашем ответе, но я подумал, что это стоит выделить. – Bacon

1

После этого вы можете изменить исходные данные.

Например:

# Construct the FormSet class 
ExampleFormSet = modelformset_factory(ParentModel, ChildModel) 

# Set the initial data 
initial_data = {'field1': 1} 
for form in ExampleFormSet.extra_forms: 
    for field in form.fields: 
     field.initial = initial_data[field.name] 
+0

Когда я пытаюсь это сделать (с formet_factory), я получаю объект ''str' не имеет атрибута 'initial'' Что я могу делать неправильно? – LukasKawerau

+0

@LukasKawerau: проверьте, что возвращает 'form.fields'. Этот код может потребовать исправления. – vdboor

+0

@LukasKawerau, в python 2.7 (по крайней мере) итерация по словарю gies только ключи не данные – maazza

9

Новый в Django 1.4 ... если вы установите начальными на modelformset теперь применяется только к «дополнительным» формам, а не тем, которые связан с экземплярами из QuerySet:

https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#providing-initial-values

Таким образом, новые хаки больше не нужны, и использование начального ответа является ответом.

1

В Django 1.4 правило изменилось: количество инициалов, которые должны отображаться, соответствует параметру «extra». https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#providing-initial-values

В моем случае подсчет начальных параметров изменяется динамически, поэтому я нашел следующий способ:

initial=[{'name': 'Some Name'},{'name': 'Another Name'}] 
formset = ExampleModelFormSet(queryset=ExampleModel.objects.none(), 
         initial=initial, extra=len(initial)) 


class MyBaseFormSet(BaseModelFormSet): 
    def __init__(self, *args, **kwargs): 
     self.extra = kwargs.pop('extra', self.extra) 
     super(MyBaseFormSet, self).__init__(*args, **kwargs) 

при условии, ExampleModelFormSet основан на MyBaseFormSet

0

Простого способом, как пройти начальным данные с тем же количеством дополнительных форм:

MyModelFormSet = lambda *a, **kw: modelformset_factory(MyModel, extra=kw.pop('extra', 1))(*a, **kw) 

Использование в vi овости:

initial=[{'name': 'Some Name'},{'name': 'Another Name'} 
formset = MyModelFormSet(queryset=MyModel.objects.none(), initial, extra=len(initial))}) 
0

Affter два дня нашел это: http://streamhacker.com/2010/03/01/django-model-formsets/

def custom_field_callback(field): 
    return field.formfield(required=False) 

FormSet = modelformset_factory(model, formfield_callback=custom_field_callback) 

def custom_field_callback(field): 
    if field.name == 'optional': 
     return field.formfield(required=False) 
    elif field.name == 'text': 
     return field.formfield(widget=Textarea) 
    elif field.name == 'integer': 
     return IntegerField() 
    else: 
     return field.formfield() 
5

Лучший способом я нашел, чтобы сделать это просто вручную настроить «лишний» атрибут объекта formset после инициализации. Это было протестировано и работает в Django 1.9.

ExampleModelFormSet = modelformset_factory(ExampleModel, extra=1) 
formset = ExampleModelFormSet(initial=[{'name': 'Some Name'}, 
             {'name': 'Another Name'}]) 
formset.extra = 3 

Это будет выплеснуть 3 формы (2 предварительно заполненных и 1 пробел).

Если вы хотите что-то более динамичное (например initial является вар рассчитывается где-то еще), вы можете сделать что-то вроде этого:

ExampleModelFormSet = modelformset_factory(ExampleModel, extra=1) 
formset = ExampleModelFormSet(initial=initial) 
formset.extra += len(initial) 

Надежда, что помогает.

Смежные вопросы