Передача начального в Django ModelFormSet - PullRequest
21 голосов
/ 22 августа 2009

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

Ответы [ 10 ]

9 голосов
/ 29 мая 2012

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

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

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

9 голосов
/ 31 августа 2009

Вы передаете пустой набор запросов в 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 - список диктовок. Желательно, чтобы в списке были элементы, в точности равные количеству лишних.

4 голосов
/ 11 июня 2016

Лучший способ сделать это - вручную настроить атрибут «extra» объекта 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)

Надеюсь, это поможет.

2 голосов
/ 26 августа 2009

Все еще возможно передать начальный в 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'}])
1 голос
/ 27 августа 2012

В Django 1.4 правило изменилось: количество отображаемых инициалов соответствует «дополнительному» параметру. 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

1 голос
/ 22 ноября 2010

Вы можете впоследствии изменить исходные данные.

Например:

# 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 голосов
/ 25 октября 2015

Аффтер через два дня нашел это: 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()
0 голосов
/ 19 августа 2013

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

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

Использование в просмотрах:

initial=[{'name': 'Some Name'},{'name': 'Another Name'}
formset = MyModelFormSet(queryset=MyModel.objects.none(), initial, extra=len(initial))})
0 голосов
/ 26 августа 2009

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

0 голосов
/ 23 августа 2009

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...