Python自動化開發學習24-Django(ModelForm)
接下來要使用的表結構如下:
# models.py 文件 class UserType(models.Model): caption = models.CharField(max_length=32) class UserInfo(models.Model): username = models.CharField(max_length=32) email = models.EmailField() user_type = models.ForeignKey(to=‘UserType‘, on_delete=models.CASCADE)
表結構寫好之後,生成數據庫:
···
python manage.py makemigrations
python manage.py migrate
···
ModelForm
上節就說過,ModelForm很簡單,所以就下面幾行,沒太多內容:
# forms.py 文件
class UserInfo(forms.ModelForm):
class Meta:
model = models.UserInfo
fields = ‘__all__‘
處理函數
# views.py 文件 def user_info(request): if request.method == ‘GET‘: obj = forms.UserInfo() return render(request, ‘user_info.html‘, {‘obj‘: obj}) elif request.method == ‘POST‘: obj = forms.UserInfo(request.POST) return render(request, ‘user_info.html‘, {‘obj‘: obj})
HTML
最後再頁面上顯示出來
<form action="." method="POST">
{% csrf_token %}
{{ obj.as_p }}
<input type="submit" value="提交">
</form>
最後打開頁面查看一下,也是可以自動生成html標簽的,並且效果上和之前用的Form基本沒什麽區別。
自定義label
上面在頁面中顯示的名稱是默認的變量名,如果要顯示中文,需要在models裏定一個變量 verbose_name。
之前在 Python自動化開發學習19-Django 裏講過models的參數。verbose_name :Admin中顯示的字段名稱,默認顯示為變量名。我們用ModelForm也是一樣的,因為Admin裏用的就是ModelForm。
顯示選項的內容
因為現在usertype表裏是空的,所以select下拉列表裏沒有其他選項。添加幾條數據後,頁面上會有相應的選項了,但是顯示的內容是對象。為了讓他顯示內容,還要在類裏定一個 __str__
方法。
連同上面顯示中文標簽一起,修改為下面的樣子:
# modelspy 文件
class UserType(models.Model):
caption = models.CharField(max_length=32)
def __str__(self):
return self.caption
class UserInfo(models.Model):
username = models.CharField(verbose_name="用戶名", max_length=32)
email = models.EmailField(verbose_name="電子郵件")
user_type = models.ForeignKey(verbose_name="用戶類型", to=‘UserType‘, on_delete=models.CASCADE)
定制頁面顯示的字段
上面的ModelForm裏面的元類的fields變量,設置的是顯示所有的字段,也可以傳入一個列表,只顯示要求的那些字段。或者是使用exclude,表示排除哪些字段:
# fields = ‘__all__‘
# fields = [‘username‘, ‘user_type‘]
exclude = [‘email‘]
ModelForm 中 Form 的功能
先了解一下ModelForm和Form的關系。
之前學習使用的Form,繼承的是BaseForm。我這裏用的ModelForm,父類是BaseModelForm,再網上找繼承的還是BaseForm。
之前學習Form的時候,講到Form的2個功能,驗證和生成html標簽。全部都是在BaseForm這個類裏實現的。所以這些功能在ModelForm裏一樣都有,並且用起來和Form幾乎也是一樣的。
元類裏的參數
講師的博客地址:http://www.cnblogs.com/wupeiqi/articles/6229414.html
在上面的例子中,已經用的了3個參數了,model、fields、exclude。下面看見一共有哪些常用的參數:
model
:對應models的哪張表fields
:顯示的字段,__all__
表示全部字段exclude
:排除的自動labels
:自定義標簽名,字典類型labels = {‘username‘: "名字", ‘email‘: "郵箱", ‘user_type‘: "類型"}
對應上面的例子。如何還在models裏設置了verbose_name,還是以這裏的labels為準。help_texts
:提示信息,顯示在輸入框後面。字典類型和上面一樣。widgets
:自定義插件,用的還是form的插件,如果直接導入會重名,要加別名from django.forms import widgets as my_widgets
。用法舉例:widgets = {‘username‘: my_widgets.Textarea(attrs={‘class‘: ‘c1‘})}
error_messages
:自定義錯誤信息,整體錯誤信息的key是from django.core.exceptions import NON_FIELD_ERRORS
也就是‘__all__‘
field_classes
:自定義Form驗證的類。默認models裏是CharField,那麽對於Form的類也是CharField。這個設置可以改掉實現自定義。用法舉例:field_classes = {‘username‘: forms.fields.EmailField}
。如果直接導入fields依然會有重名的問題,用as改掉localized_fields
:本地化,根據不同時區顯示數據。參數是需要本地化的字段名的元祖,比如:localized_fields=(‘create_time‘,)
元類裏的很多字段設置都和Form裏的用法是一樣的。但是Form裏是一個字段一個字段設置的,而ModelForm是整張表設置的。所以這裏的設置傳入的都是字典,key就是字段名,value就是和Form裏設置的值一樣了。
ModelForm 中 Model 的功能
這裏主要就是數據的增刪改查了
添加數據
直接獲取到對象,用is_valid()方法驗證通過後,直接對對象用一個save()方法就能完成數據的添加。下面是可以完成數據添加的處理函數:
# views.py 文件
def user_info(request):
if request.method == ‘GET‘:
obj = forms.UserInfo()
return render(request, ‘user_info.html‘, {‘obj‘: obj})
elif request.method == ‘POST‘:
obj = forms.UserInfo(request.POST)
if obj.is_valid():
obj.save()
return render(request, ‘user_info.html‘, {‘obj‘: obj})
多對多的情況
例子就不寫了。如果是有多對多的關聯,默認也是會更新多對多關聯的第三張表的數據的。
實際上save()方法內部是拆分成2步執行的,先操作當前的這張表,然後去操作多對多關聯的第三張表。save()方法有個默認參數 def save(self, commit=True):
默認設置就是上面那樣執行的。如果參數是False,就是不幫我們自動更新第三張表。如果要用False參數具體用法如下:
instance = obj.save(False) # 不在任何操作
instance.save() # 保存當前的表的數據
obj.save_m2m() # 保存第三張表的數據
填入默認值
要在生成html的時候,在頁面內填入默認值。首先要做一步model操作,去數據庫裏獲取一條數據對象,然後把這個對象作為ModelForm的instance參數傳入。代碼如下:
if request.method == ‘GET‘:
user_obj = models.UserInfo.objects.filter(id=1).first()
obj = forms.UserInfo(instance=user_obj)
return render(request, ‘user_info.html‘, {‘obj‘: obj})
更新數據
上面填入默認值,在做修改的時候經常會用到。修改完成後提交到後臺,就要進行數據更新了。這裏不能用直接save()方法,因為這樣會變成新建。數據更新用的還是save()方法,但是要再傳入一個參數,告訴系統要把新的數據更新到表的哪一條,否則就是新建。具體的做法如下:
elif request.method == ‘POST‘:
user_obj = models.UserInfo.objects.filter(id=1).first()
obj = forms.UserInfo(request.POST, instance=user_obj)
if obj.is_valid():
obj.save()
return render(request, ‘user_info.html‘, {‘obj‘: obj})
這裏和上面填入默認值的做法差不多,只不過這裏把需要更新的數據也傳遞進來了。
添加額外的字段
比如一個login登錄的應用場景。頁面上除了有用戶名和密碼以外,還可以加一個單選框“記住我”。這個額外的字段是不記錄到數據庫裏的,而是會寫到cookie或者session裏。這種情況,可以把這個字段定義在ModelForm類裏作為公有屬性(靜態屬性),定義的時候完全和定義Form的字段是一樣的:
# forms.py 文件
class UserInfo(forms.ModelForm):
is_remembered = forms.fields.CharField(
widget=my_widgets.CheckboxInput(),
label="記住我",
)
class Meta:
# 元類裏的內容就略了
這樣這個額外的字段在頁面裏會顯示在最後面,有Form的全部功能,驗證和生成html。但是不會有model操作。
Python自動化開發學習24-Django(ModelForm)