template - python form




Django:使用表單的一個模板中的多個模型 (5)

“我想隱藏一些領域並做一些複雜的驗證。”

我從內置的管理界面開始。

  1. 構建ModelForm以顯示所需的字段。

  2. 使用表單中的驗證規則擴展表單。 通常這是一個clean方法。

    確保這部分工作合理。

一旦完成,您可以離開內置的管理界面。

然後,您可以在單個網頁上混搭多個部分相關的表單。 這是一組模板材料,用於在單個頁面上呈現所有表單。

然後你必須編寫視圖函數來讀取和驗證各種形式的東西,並做各種對象保存()。

“如果我分解並手工編碼一切,這是否是一個設計問題?” 不,這只是很多時間,沒有多少好處。

我正在構建一個支持票據跟踪應用程序,並且我希望從一個頁面創建幾個模型。 門票通過ForeignKey屬於客戶。 Notes也通過ForeignKey屬於Tickets。 我想要選擇一個客戶(這是一個單獨的項目)或創建一個新的客戶,然後創建一個票證,並最終創建一個分配給新票據的票據。

由於我對Django相當陌生,因此我傾向於迭代工作,每次嘗試新功能。 我玩過ModelForms,但我想隱藏一些字段並做一些複雜的驗證。 看起來我正在尋找的控制級別要么需要formset,要么手工完成所有操作,並且完成一個乏味的,手工編碼的模板頁面,我試圖避免。

有一些我失踪的可愛功能嗎? 有人有一個很好的參考或使用formset的例子嗎? 我花了整整一個週末在他們的API文檔,我仍然無能為力。 如果我分解並手工編碼一切,這是否是一個設計問題?


來自django-betterformsMultiModelForm是做Gnudiff答案中描述的方便的包裝器。 它將常規的ModelForm封裝在一個透明的類中(至少對於基本用法)作為單一形式使用。 我從下面的文檔複製了一個示例。

# forms.py
from django import forms
from django.contrib.auth import get_user_model
from betterforms.multiform import MultiModelForm
from .models import UserProfile

User = get_user_model()

class UserEditForm(forms.ModelForm):
    class Meta:
        fields = ('email',)

class UserProfileForm(forms.ModelForm):
    class Meta:
        fields = ('favorite_color',)

class UserEditMultiForm(MultiModelForm):
    form_classes = {
        'user': UserEditForm,
        'profile': UserProfileForm,
    }

# views.py
from django.views.generic import UpdateView
from django.core.urlresolvers import reverse_lazy
from django.shortcuts import redirect
from django.contrib.auth import get_user_model
from .forms import UserEditMultiForm

User = get_user_model()

class UserSignupView(UpdateView):
    model = User
    form_class = UserEditMultiForm
    success_url = reverse_lazy('home')

    def get_form_kwargs(self):
        kwargs = super(UserSignupView, self).get_form_kwargs()
        kwargs.update(instance={
            'user': self.object,
            'profile': self.object.profile,
        })
        return kwargs

我最近遇到了一些問題,只是想出瞭如何做到這一點。 假設你有三個類,Primary,B,C和那個B,C有一個外鍵給主鍵

    class PrimaryForm(ModelForm):
        class Meta:
            model = Primary

    class BForm(ModelForm):
        class Meta:
            model = B
            exclude = ('primary',)

    class CForm(ModelForm):
         class Meta:
            model = C
            exclude = ('primary',)

    def generateView(request):
        if request.method == 'POST': # If the form has been submitted...
            primary_form = PrimaryForm(request.POST, prefix = "primary")
            b_form = BForm(request.POST, prefix = "b")
            c_form = CForm(request.POST, prefix = "c")
            if primary_form.is_valid() and b_form.is_valid() and c_form.is_valid(): # All validation rules pass
                    print "all validation passed"
                    primary = primary_form.save()
                    b_form.cleaned_data["primary"] = primary
                    b = b_form.save()
                    c_form.cleaned_data["primary"] = primary
                    c = c_form.save()
                    return HttpResponseRedirect("/viewer/%s/" % (primary.name))
            else:
                    print "failed"

        else:
            primary_form = PrimaryForm(prefix = "primary")
            b_form = BForm(prefix = "b")
            c_form = Form(prefix = "c")
     return render_to_response('multi_model.html', {
     'primary_form': primary_form,
     'b_form': b_form,
     'c_form': c_form,
      })

這種方法應該允許你做任何需要的驗證,以及在同一頁面上生成所有三個對象。 我也使用JavaScript和隱藏字段來允許在同一頁面上生成多個B,C對象。


我目前有一個解決方法功能(它通過我的單元測試)。 當你只想添加其他模型的有限數量的字段時,這對我的意見來說是一個很好的解決方案。

我在這裡錯過了什麼嗎?

class UserProfileForm(ModelForm):
    def __init__(self, instance=None, *args, **kwargs):
        # Add these fields from the user object
        _fields = ('first_name', 'last_name', 'email',)
        # Retrieve initial (current) data from the user object
        _initial = model_to_dict(instance.user, _fields) if instance is not None else {}
        # Pass the initial data to the base
        super(UserProfileForm, self).__init__(initial=_initial, instance=instance, *args, **kwargs)
        # Retrieve the fields from the user model and update the fields with it
        self.fields.update(fields_for_model(User, _fields))

    class Meta:
        model = UserProfile
        exclude = ('user',)

    def save(self, *args, **kwargs):
        u = self.instance.user
        u.first_name = self.cleaned_data['first_name']
        u.last_name = self.cleaned_data['last_name']
        u.email = self.cleaned_data['email']
        u.save()
        profile = super(UserProfileForm, self).save(*args,**kwargs)
        return profile

這對於使用ModelForms實現並不難。 因此,讓我們說你有表格A,B和C.你打印出每個表格和頁面,現在你需要處理POST。

if request.POST():
    a_valid = formA.is_valid()
    b_valid = formB.is_valid()
    c_valid = formC.is_valid()
    # we do this since 'and' short circuits and we want to check to whole page for form errors
    if a_valid and b_valid and c_valid:
        a = formA.save()
        b = formB.save(commit=False)
        c = formC.save(commit=False)
        b.foreignkeytoA = a
        b.save()
        c.foreignkeytoB = b
        c.save()

Here是自定義驗證的文檔。







django-forms