django formset實現資料表的批量操作的示例程式碼
什麼是formset
我們知道forms元件是用來做表單驗證,更準確一點說,forms元件是用來做資料庫表中一行記錄的驗證。有forms元件不同,formset是同科同時驗證表中的多行記錄,即formset是做表單批量驗證的元件。
批量新增
首先要例項化formset物件,物件初始化時需要提供操作表的forms表單類,引數extra 用來顯示驗證幾行資料。將例項化的formset物件傳遞給前端頁面,前端模板通過兩層迴圈:第一層迴圈form,第二層迴圈form中的欄位。當GET請求時,直接將例項化的formset物件傳遞給前端。當POST請求時,批量驗證表單,當所有資料都沒有問題時,後臺資料庫儲存資料。
後臺儲存資料時,有兩種方式:第一種方式簡潔,但是無法捕獲欄位唯一約束的錯誤;因此使用formset批量新增資料時最好使用第二中方式,手動捕獲唯一約束錯誤資訊並交給formset送到前端頁面顯示。
models.Permission.objects.create(**row) obj = models.Permission(**row) | obj.save()
唯一約束錯誤資訊捕獲的過程,需要使用obj.validate_unique() 判斷該物件是否滿足唯一約束,如果不滿足則通過異常捕獲操作,捕獲異常資訊。通過formset.errors[i].update(e) 把錯誤資訊放入formset中送到前端頁面顯示。之所以這樣做,是因為通過forms元件的驗證時無法捕獲唯一約束的錯誤。因此這裡通過手動收集錯誤資訊並放入forset中。
此外,如果前端頁面渲染的表單沒有填寫資料,直接提交是不會報錯的。formset預設只要不改動欄位就不會對該行資料做驗證。只要填寫一個欄位,該行資料則會做表單驗證 。
# views.py def multi_add(request): """ 批量新增 :param request: :return: """ formset_class = formset_factory(MultiPermissionForm,extra=2) if request.method == 'GET': formset = formset_class() return render(request,'multi_add.html',{'formset': formset}) formset = formset_class(data=request.POST) if formset.is_valid(): flag = True # 檢查formset中沒有錯誤資訊,則講使用者提交的資料獲取到。 post_row_list = formset.cleaned_data for i in range(0,formset.total_form_count()): row = post_row_list[i] if not row: continue try: obj = models.Permission(**row) obj.validate_unique() # 檢查當前物件在資料庫是否存在唯一的異常。 obj.save() except Exception as e: formset.errors[i].update(e) flag = False if flag: return HttpResponse('提交成功') else: return render(request,{'formset': formset}) return render(request,{'formset': formset})
前端模板通過兩層迴圈:第一層迴圈formset得到每一個form,第二層迴圈form得到每一個欄位。與forms元件使用一樣,需要手動新增form表單和input提交數按鈕及csrf_token跨域偽造請求。此外,使用formset,還需要增加{{ formset.management_form }},使用哪個formset就增加哪個formset.management_form.
# multi_add.html <form method="post"> {% csrf_token %} {{ formset.management_form }} <table border="1"> <thead> <tr> <th>標題</th> <th>URL</th> <th>NAME</th> <th>選單</th> <th>父許可權</th> </tr> </thead> <tbody> {% for form in formset %} <tr> {% for field in form %} <td>{{ field }} <span style="color: red;">{{ field.errors.0 }}</span></td> {% endfor %} </tr> {% endfor %} </tbody> </table> <input type="submit" value="提交"> </form>
批量編輯
批量編輯和批量增加大體是一致的,但是存在不同的使用區別。例項化formset物件時預設extra=1,需要手動修改為extra=0;GET請求,頁面需要顯示預設值,通過引數initial賦值列表內部巢狀字典的資料結構的資料。且需要傳遞每行資料的id,告訴formset需要修改的資料id 。此時使用的forms類相比批量新增使用的類多一個id欄位,id = forms.IntegerField( widget=forms.HiddenInput()) ,預設隱藏的欄位,前端頁面不顯示。
同理也會遇到唯一約束錯誤,使用迴圈和反射為每個欄位做資料更新賦值,然後再提交資料庫儲存。
def multi_edit(request): formset_class = formset_factory(MultiUpdatePermissionForm,extra=0) if request.method == 'GET': formset = formset_class( initial=models.Permission.objects.all().values('id','title','name','url','menu_id','pid_id')) return render(request,'multi_edit.html',{'formset': formset}) formset = formset_class(data=request.POST) if formset.is_valid(): # 檢查formset中沒有錯誤資訊,則講使用者提交的資料獲取到。 post_row_list = formset.cleaned_data flag = True for i in range(0,formset.total_form_count()): row = post_row_list[i] if not row: continue permission_id = row.pop('id') try: permission_object = models.Permission.objects.filter(id=permission_id).first() for key,value in row.items(): setattr(permission_object,key,value) permission_object.validate_unique() permission_object.save() except Exception as e: formset.errors[i].update(e) flag = False if flag: return HttpResponse('提交成功') else: return render(request,{'formset': formset})
前端模板迴圈顯示每個欄位時,要判斷是否是第一個id欄位,如果是第一個就直接{{field}} ,頁面將不會顯示。
<form method="post"> {% csrf_token %} {{ formset.management_form }} <table border="1"> <thead> <tr> <th>標題</th> <th>URL</th> <th>NAME</th> <th>選單</th> <th>父許可權</th> </tr> </thead> <tbody> {% for form in formset %} <tr> {% for field in form %} {% if forloop.first %} {{ field }} {% else %} <td>{{ field }} <span style="color: red;">{{ field.errors.0 }}</span></td> {% endif %} {% endfor %} </tr> {% endfor %} </tbody> </table> <input type="submit" value="提交"> </form>
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。