2010-01-02 36 views
22

一個formset:Django的:初始化的自定義表單與考慮下面的模型的實例

class Graph(models.Model): 
    owner = models.ForeignKey(User) 

    def __unicode__(self): 
     return u'%d' % self.id 

class Point(models.Model): 
    graph = models.ForeignKey(Graph) 
    date = models.DateField(primary_key = True) 
    abs = models.FloatField(null = True) 
    avg = models.FloatField(null = True) 

    def __unicode__(self): 
     return u'%s' % self.date 

我想創造點的編輯列表的形式。 HTML輸入標籤需要進行設置附加屬性,所以我用下面的自定義窗體:

class PointForm(forms.ModelForm): 
    graph = forms.ModelChoiceField(queryset = Graph.objects.all(), 
            widget = forms.HiddenInput()) 
    date = forms.DateField(widget = forms.HiddenInput(), label = 'date') 
    abs = forms.FloatField(widget = forms.TextInput(
             attrs = {'class': 'abs-field'}), 
          required = False) 

    class Meta: 
     model = Point 
     fields = ('graph', 'date', 'abs') # Other fields are not edited. 

    def pretty_date(self): 
     return self.data.strftime('%B') 

在這一點上,我不知道該怎麼Point類的實例傳遞到表單集中:

def edit(request): 
    PointFormSet = forms.formsets.formset_factory(PointForm, extra = 0) 
    if request.method == 'POST': 
     return 

    # Receive 3 points to edit from the database. 
    graph, res = Graph.objects.get_or_create(id = 1) 
    one_day = datetime.timedelta(days = 1) 
    today  = datetime.date.today() 
    do_edit = [] 
    for date in [today - (x * one_day) for x in range(3)]: 
     point, res = Point.objects.get_or_create(graph = graph, date = date) 
     do_edit.append(point) 

    formset = PointFormSet(????) # How is this initialized with the points? 

我發現一個黑客工具,有些工作,但試圖處理所產生的POST數據時,它會導致錯誤以後:

do_edit = [] 
for date in [today - (x * one_day) for x in range(3)]: 
    point, res = Point.objects.get_or_create(graph = graph, date = date) 
    data   = point.__dict__.copy() 
    data['graph'] = graph 
    do_edit.append(data) 

formset = PointFormSet(initial = do_edit) 

這是如何正確地做了什麼?

對於參考,我的模板看起來是這樣的:

<form action="" method="post"> 
{{ formset.management_form }} 
<table> 
    <tbody> 
    {% for form in formset.forms %} 
     <tr> 
      <td>{{ form.graph }} {{ form.date }} {{ form.pretty_date }}:</td> 
      <td width="100%">{{ form.abs }}</td> 
     </tr> 
    {% endfor %} 
    </tbody> 
</table> 
</form> 

回答

23

訣竅是使用「ModelFormset」,而不僅僅是一個formset,因爲它們允許初始化一個查詢集。該文檔是here,當您實例化formset時,您在創建模型formset和queryset = *時提供了form = *。 form = *參數沒有很好的記錄(不得不在代碼中仔細研究一下,以確保它實際存在)。

def edit(request): 
    PointFormSet = modelformset_factory(Point, form = PointForm) 
    qset = Point.objects.all() #or however your getting your Points to modify 
    formset = PointFormset(queryset = qset) 
    if request.method == 'POST': 
     #deal with posting the data 
     formset = PointFormset(request.POST) 
     if formset.is_valid(): 
      #if it is not valid then the "errors" will fall through and be returned 
      formset.save() 
     return #to your redirect 

    context_dict = {'formset':formset, 
        #other context info 
        } 

    return render_to_response('your_template.html', context_dict) 

所以代碼很容易通過。如果請求是GET,則實例化的表單將返回給用戶。如果請求是POST並且表單是not .is_valid(),那麼錯誤「經過」並返回到相同的模板中。如果請求是POST並且數據有效,則表單集被保存。

希望有所幫助。

- 將會

+1

Ahhhh,非常感謝你,它的作品非常漂亮。小修正:在驗證POST數據時,初始化如下所示:「PointFormset(request.POST,queryset = qset)」。否則你會得到這個錯誤:「與這個日期點已經存在」。 – knipknap 2010-01-02 20:16:33

+0

doh ...好的......我忘記了在使用model_formset和提供的數據時你需要給查詢集......我從來沒有真正使用過這種用例。 – JudoWill 2010-01-03 00:05:16

0

如果你只有要設置一個可能的值,或者是一個封閉的值,可以使用用戶的帖子後,將它們的數據到服務器commit=False

請考慮以下代碼:

class UserReferralView(View): 
    ReferralFormSet = modelformset_factory(ReferralCode, 
              form=ReferralTokenForm, extra=1) 

    def get(self, request): 
     pass 

    def post(self, request): 
     referral_formset = UserUpdateView.ReferralFormSet(request.POST) 

     if referral_formset.is_valid(): 
      instances = referral_formset.save(commit=False) 
      for instance in instances: 
       instance.user = request.user 
       instance.save() 
      return redirect(reverse('referrals.success_view')) 
     else: 
      return redirect(reverse('referrals.failure_view')) 
相關問題