django - template - from.models import post
Django內聯表單與自定義表單 (2)
您好我有一個域模型,用於Django應用程序,我想在一個表單上。 我用自定義的ModelForms創建了我的應用程序(沒有太多的變化,一些領域排除等)。 該模型的依賴關係如下所示:
Complaint
\
.--- CarInfo
.--- Customer
我的看法功能如下所示:
def make(request):
if request.method == 'POST':
parameters = copy.copy(request.POST)
complaint = Complaint()
carInfo = CarInfo()
customer = Customer()
customer_form = CustomerForm(parameters, instance=customer)
carInfo_form = CarInfoForm(parameters, instance=carInfo)
parameters['complaint_date'] = get_current_date()
parameters['customer'] = 1 # dummy value to allow validation success
parameters['car_info'] = 1 # dummy value to allow validation success
form = ComplaintForm(parameters, instance=complaint)
if form.is_valid() and customer_form.is_valid() and carInfo_form.is_valid():
carInfo_form.save()
customer_form.save()
parameters['customer'] = customer.id
parameters['car_info'] = carInfo.id
form = ComplaintForm(parameters, instance=complaint)
form.save()
return index(request)
else:
form = ComplaintForm()
carInfo_form = CarInfoForm()
customer_form = CustomerForm()
return render_to_response('complaints/make_complaint.html', {'complaint_form' : form, 'customer_form' : customer_form, 'carInfo' : carInfo_form})
我不太喜歡這個方法,而且它在所有的環境下都不起作用 - 我沒有找到它不工作的原因。 我一直在尋找修復這個代碼,找到像內聯formset (http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#inline-formsets)。 這個解決方案似乎沒問題,但是因為我的表單是自定義的,我可以使用它。
也許有人可以就如何妥善解決這種情況提供一些建議。 清潔解決方案非常感謝。
編輯有一種情況下,我這個解決方案不起作用。 儘管在外鍵上設置了虛擬值,當我調用is_valid()時,我得到FALSE,錯誤消息說這些字段沒有設置。 我正在用django 1.2.5觀察這個問題 - 它發生在服務器上,我打算運行這個應用程序,但是我的筆記本電腦(也是django 1.2.5)沒有這個問題。
可能formset工廠和內聯formset應該解決您的問題...您可以修改或重寫從模型創建的表單域,對於子模型,您可以使用內聯formset ...
可能的解決方案:
在你的表單定義中:
class CarInfoFrm(forms.ModelForm):
class Meta:
model = CarInfo
fields = (....)
carInfoForm = inlineformset_factory(Complaint, CarInfo, form=carInfoFrm,)
CustomerForm = inlineformset_factory(Complaint, Customer, form=carInfoFrm,)
在你看來:
complaint = Complaint()
carInfo = CarInfo()
customer = Customer()
cus_form = CustomerForm(parameters, instance=complaint)
car_form = CarInfoForm(parameters, instance=complaint)
comp_form = ComplaintForm(parameters, instance=complaint)
if cus_form.is_valid() and ...... :
comp = comp_form.save(commit=False)#do not save it yet
comp.<attr> = "some_value" #you can edit your data before save...
comp.save()
car = car_form(commit=False)
# do as complaint form... edit and save...
編輯:我在定義實例參數,同時保存內聯格式時做一個misteke。 所以我糾正它...
當你更新現有的記錄時,你不會有問題,但最好是像這樣使用它:
if comp_form.is_valid():
comp = comp_form.save(commit=False)
comp.<attr> = "some_value"
comp.save()
if car_form.is_valid():
# edit if neccessary then save...
if cust_form.is_Valid():
# edit if neccessary then save...
更簡單的是,當你定義你的表單時,你通過一個外鍵來設置一個父表單
carInfoForm = inlineformset_factory(Complaint, CarInfo, form=carInfoFrm,)
而當你使用內聯表單進行更新時,你用你的父Compalaint記錄進行初始化,
car_form = CarInfoForm(parameters, instance=complaint)
所以,car_form不接受一個carInfo實例,而是一個投訴實例(這是我的第一個答案中的錯誤,所以我糾正了它)。 如果它創建一個新的記錄,它會自動綁定到相關的投訴記錄。 如果是更新,則只更新所需的字段。
對我來說,iti最好是使用框架的moehods,而不是寫你的擁有者。 通過這樣做,你將保證所有的驗證檢查由django進行。
您可以將您的投訴模式的投訴日期更改為這樣的
complaint_date = models.DateField(default=datetime.date.today())
這樣你可以擺脫
parameters['complaint_date'] = get_current_date()
至於你的多表單視圖,你可以使用一個未綁定的表單來達到你想要的行為。
通過在投訴表格中將fk排除在汽車和客戶之外,表格應該被驗證。 同時檢查所有3個表單的.is_valid(),然後保存你的投訴對象所依賴的2個表單,用commit提交到數據庫(commit = False)創建投訴對象,添加客戶的id和車到那個對象,然後保存。
在你看來。
def make(request):
if request.method == 'POST':
customer_form = CustomerForm(request.POST)
carInfo_form = CarInfoForm(request.POST)
form = ComplaintForm(request.POST)
if form.is_valid() and customer_form.is_valid() and carInfo_form.is_valid():
car_instance = carInfo_form.save()
customer_instance = customer_form.save()
complaint_instance = form.save(commit=False)
complaint_instance.car_info = car_instance
complaint_instance.customer_info = customer_instance
complaint_instance.save()
return index(request)
else:
form = ComplaintForm()
carInfo_form = CarInfoForm()
customer_form = CustomerForm()
context = { 'complaint_form' : form,
'customer_form' : customer_form,
'carInfo' : carInfo_form,
}
return render_to_response('complaints/make_complaint.html', context, context_instance=RequestContext(request))
編輯:
模型看起來像這樣:
class CarInfo(models.Model):
some_car_info = models.CharField()
class Customer(models.Model):
some_customer_info = models.CharField()
class Complaint(models.Model):
car_info = models.ForeignKey(CarInfo)
customer_info = models.ForeignKey(Customer)
some_complaint_info = models.CharField()
forms.py應該看起來像這樣:
class CarInfoForm(forms.ModelForm):
class Meta:
model = CarInfo
class CustomerForm(forms.ModelForm):
class Meta:
model = Customer
class ComplaintForm(forms.ModelForm):
class Meta:
model = Complaint
exclude = ('car_info', 'customer_info',) # or include = ('some_complaint_info',)
讓我們一起來看看我上面寫的觀點: form in view docs
第一遍,沒有request.method,所以我們創建3個未綁定的表單。
else: form = ComplaintForm() carInfo_form = CarInfoForm() customer_form = CustomerForm()
這些表單被傳遞給模板並呈現。
當再次調用request.method ==“POST”來評估視圖的時候,我們使用request.POST中的數據創建3個綁定的表單實例。
if request.method == 'POST': customer_form = CustomerForm(request.POST) carInfo_form = CarInfoForm(request.POST) form = ComplaintForm(request.POST)
接下來我們在每個表單上調用.is_valid()方法。 在我們的示例中,因為我們在投訴模型表單中排除了“customer_info”和“car_info”外鍵字段,所以每個表單都只檢查字符輸入字段是否有效。
如果驗證全部通過,那麼我們可以開始將我們的表單保存到模型中,並且在這裡我們需要小心地填充我們的投訴所需的fk:
if form.is_valid() and customer_form.is_valid() and carInfo_form.is_valid(): car_instance = carInfo_form.save() customer_instance = customer_form.save()
通過這兩種形式,我們可以像往常一樣調用.save()。 然而,我們將返回值分配給car_instance和customer_instance。 這些將包含我們剛在表單上使用.save()方法創建的CarInfo和Customer模型的實例。
接下來,在.save()方法中使用
commit=False
參數,我們可以從綁定的表單(包含request.POST數據)創建一個對象,而不是將其保存到數據庫中。complaint_instance = form.save(commit=False) complaint_instance.car_info = car_instance complaint_instance.customer_info = customer_instance complaint_instance.save()
為了使這個更清楚,你也可以創建一個像這樣的新的Complaint對象:
complaint_info = form.cleaned_data.get('some_complaint_info') complaint_instance = Complaint(car_info=car_instance, customer_info=customer_instance, some_complaint_info=some_complaint_info) complaint_instance.save()
給予