2009-08-21 13 views
18

Mam model formase, że muszę przekazać inicjał słowa kluczowego do (aby mieć pewne wartości początkowe w zestawie, takie jak data ustawiona na dziś). O ile mogę powiedzieć, argument queryset (domyślnie YourModel.objects.all()) zastępuje tę możliwość początkowych pustych formularzy do utworzenia. Podałem zestaw zapytań jako: YourModel.objects.none(), który uniemożliwia mu wypełnienie zestawu z wpisami z bazy danych, ale nadal nie mogę wymyślić, jak skutecznie przekazać inicjał. Czy muszę podklasować metodę z ModelForm?Przekazywanie początkowe do ModelFormSet Django

+1

Chcesz zmienić konkretną instancję modelu, ale nie chcesz wyświetlać jej istniejących wartości i wyświetlać różne wartości początkowe? –

Odpowiedz

0

Prostym rozwiązaniem może być przekazanie formularza, który rozszerza formułę modelu() na formset (a nie modelformset).

W ten sposób można ustawić wartości początkowe w formularzu.

+1

Czy możesz rozwinąć ten temat? Nie jestem pewien, czy rozumiem, co masz na myśli. – Vince

2

Jest jeszcze możliwość, aby przejść do ModelFormSet początkowy.

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'}]) 

Jeśli to nie jest twój po, możesz wyjaśnić swoje pytanie bardziej.

EDIT:

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

Domyślnie modele formularzy Django wypełniają się wynikami funkcji yourmodel.objects.all(). Można to odwrócić za pomocą queryset = yourmodel.objects.none(), ale to nadal nie pozwala na wartości początkowe. Coś związanego z ustawieniem zestawu zapytań i początkowych słów kluczowych sprawia, że ​​to nie działa. – Vince

+0

Jak to nie działa, a co nie? Korzystając ze zaktualizowanego kodu, otrzymuję zestaw z pustego zestawu zapytań i wypełnionych wartości początkowych. – Gerry

+0

Tak, to jest droga. Zgadzam się. – simplyharsh

8

są przechodzącą pusty queryset do ModelFormset.

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

który jest rzeczywiście sposobem na osiągnięcie tego, co chcesz. Ma sens przekazanie pustego zestawu zapytań, inaczej wartości początkowe zastąpią wartość bazy danych modelu.

Jeśli przypuszczam, że przekazujesz niepuste zapytanie, a chcesz, aby dodatkowe formularze były wypełnione, to wartości początkowe, możesz zastąpić 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 

Uwaga: initial to lista dykt. Pożądane jest, aby pozycje na liście były dokładnie równe liczbie dodatkowych.

+1

Jedna sztuczka, która mnie tu sprowadziła, polega na tym, że musisz ustawić dodatkowe większe lub równe liczbie elementów w początkowych danych. Wiem, że jest to w twojej odpowiedzi, ale pomyślałem, że warto to podkreślić. – Bacon

1

Możesz później zmienić początkowe dane.

Na przykład:

# 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

Kiedy próbuję tego (z formset_factory), otrzymuję obiekt 'str 'nie ma atrybutu" initial "' Co mogłem robić źle? – LukasKawerau

+0

@LukasKawerau: sprawdź, co zwraca 'form.fields'. Ten kod może wymagać korekty. – vdboor

+0

@LukasKawerau, w python 2.7 (przynajmniej) iterowanie w słowniku jest tylko kluczem nie dane – maazza

1

W Django 1.4 zmieniono regułę: liczba wyświetlanych inicjałów odpowiada parametrowi "ekstra". https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#providing-initial-values

W moim przypadku liczba początkowych parametrów zmienia się dynamicznie, więc znalazłem następujący sposób:

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) 

warunkiem, ExampleModelFormSet opiera się na MyBaseFormSet

0

prosty sposób jak przejść początkowe dane z taką samą liczbą dodatkowych formularzy:

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

Użycie i n odsłony:

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

affter znaleziono dwa dni to: 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

Najlepszym sposobem znalazłem się to zrobić, to po prostu ręcznie wyregulować „ekstra” atrybut obiektu formset po inicjalizacji. Zostało to przetestowane i działa w Django 1.9.

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

To wypluje 3 formularze (2 wstępnie wypełnione i 1 puste).

Jeśli chcesz coś bardziej dynamicznego (np initial jest obliczana var gdzieś indziej), można zrobić coś takiego:

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

nadzieję, że pomoże.

Powiązane problemy