Django個人部落格開發之高階優化表單、模型
表單自定義校驗
之前的學習過程當中講解了form表單的定義,首先,我們來回顧一下form表單的定義和使用的流程
以文章的評論為案例。
1、定義form.py檔案,在form檔案當中定義表單校驗類
2、在檢視當中呼叫form表單類
3、前端渲染表單類
總的看起來,學習的過程當中要注意以下幾點
- 表單定義
\OurBlog\Article\forms.py
#coding:utf-8 from django import forms from ckeditor_uploader.fields import RichTextUploadingFormField class CommentForm(forms.Form): """ 自定義form表單,完成評論表單 """ content = RichTextUploadingFormField(label = "評論內容") #建立一個文字標籤元素 from Article.models import Comment class CommentForm_about_model(forms.ModelForm): """ 按照資料庫模型進行表單的定義 """ class Meta: model = Comment #建立表單對應的資料模型的類 fields = ["content"] #要建立的欄位 labels = { "content": "評論內容" #設定content欄位的label標籤 } # fields 要展示的欄位,接收的是一個列表,如果不寫預設是models的所有欄位(__all__) # exclude 不要展示的欄位,接收的是一個列表,排除的欄位,預設沒有 # widgets 是一個模型欄位的名稱對應的樣式的字典 # labels 是一個模型欄位的名稱對應的標籤的字典 # help_texts 是一個模型欄位的名稱對應的幫助文件的字典 # error_messages是一個模型欄位的名稱對應的錯誤提示的字典,這個將在後面學習開發CMDB的時候使用者註冊用的比較頻繁
- 在檢視當中呼叫form表單類
在檢視檔案匯入表單類,並且例項化
\OurBlog\Article\views.py
from Article.forms import CommentForm_about_model
def Article(request):
form = CommentForm_about_model()
return render(request, "article/aboutMe.html",{"form":form})
在前端呼叫和渲染,注意,我們用的是ckeditor外掛,所以需要外掛的樣式,我們需要在{% block style %}模組進行匯入我們的js檔案
<!--......--> {% block style %} <link href="/static/article/css/main.css" rel="stylesheet"> <script src = "/static/article/js/jquery.js"></script> <script src = "/static/ckeditor/ckeditor-init.js"></script> <script src = "/static/ckeditor/ckeditor/ckeditor.js"></script> {% endblock %} <!--......--> <div> {{ form }} </div> <!--......-->
效果如下:
上述的功能足夠90%的需求使用,但是評論的內容限制,(不允許提交html程式碼等),這些完全符合當前業務需求的點是不好設定的,那麼就需要學習如何自定義校驗了。
自定義校驗是在form表單裡面通過"clean_欄位名稱"開頭的類來進行的
在form表單當中,我們進行資料校驗需要三步:
1、 將我們收到的資料傳入表單
2、 進行校驗 is_valid
3、 獲取校驗之後的資料 clean_data
首先views進行表單資料校驗
from Article.forms import CommentForm_about_model
def Article(request):
form = CommentForm_about_model()
if request.method == "POST" and request.POST:
data = CommentForm_about_model(request.POST)
if data.is_valid(): #校驗資料
#……
然後進行自定義校驗
def clean_content(self):
"""
form表單自定義校驗的函式名稱必須是clean_加上欄位名稱
校驗content,函式名稱就叫做clean_content
"""
data = self.cleaned_data.get("content") #獲取提交的值
if "while" in data: #判斷條件
raise forms.ValidationError("don't speek while") #這個錯誤型別是form表單類定義好的,這裡引發的錯誤,會放到errors當中
else:
return data #如果正常,我們需要返回資料
那麼大家可以想一想我們是否可以重寫或者重寫呼叫Django父類當中的方法?
Django資料庫模型物件 queryset
queryset是查詢集,就是傳到伺服器上的url裡面的內容。
Objects就是Django定義好的一個queryset,queryset定義在manager方法當中
Objects常用的方法
All
Filter
Order_by
Limit
Add
Create
Update
delete
對於queryset物件,需要掌握以下幾點:
- Django會對查詢返回的結果集QuerySet進行快取,這裡是為了提高查詢效率。也就是說,在你建立一個QuerySet物件的時候,Django並不會立即向資料庫發出查詢命令,只有在你需要用到這個QuerySet的時候才會去資料庫查詢。
- Objects是django實現的mvc框架中的資料層(model)m,django中的模型類都有一個objects物件,它是一個django中定義的QuerySet型別的物件,它包含了模型物件的例項。簡單的說,objects是單個物件,queryset是多個物件。
- QuerySet 可以被構造,過濾,切片,做為引數傳遞,這些行為都不會對資料庫進行操作。只有查詢的時候才真正的操作資料庫。
1、迴圈(Iteration):QuerySet 是可迭代的,在你遍歷物件時就會執行資料庫操作。
2、切片(Slicing): QuerySet 是可以用 Python 的陣列切片語法完成切片。一般來說對一個未查詢的 QuerySet 切片就返回另一個未查詢的 QuerySet (新 QuerySet 不會被執行)。
切片的step操作會導致結果集進行資料庫查詢, 也就是我們常說的步長
Article.objects.all()[1:10] 不查詢
Article.objects.all()[1:10:2] 查詢
3、repr(). 呼叫 QuerySet 的 repr() 方法時,查詢就會被執行。
4、 len() .呼叫 QuerySet 的 len() 方法,查詢就會被執行
Django 還提供了 count() 方法,他使用了 SQL 的 SELECT COUNT(*) 機制
Django自定義queryset
在上面的案例當中,我們研究QuerySet,但實際工作當中,我們需求的查詢和orm查詢往往有差距,所以我們需要自定義
- 表級的自定義查詢
\OurBlog\Article\models.py
class ArticleManager(models.Manager):
"""
返回文章的總數
定義一個查詢集
"""
def article_conunt(self,keyword = ""): #查詢集的名稱
return self.filter(title__icontains = keyword).count() #__icontains進行資料模糊查詢 類似like
class Article(models.Model):
"""
一篇文章可以有一個作者,一個作者可以有一篇文章,
一篇文章有多條評論
一個文章有多個分類
一個分類有多篇文章
"""
#...... 這裡省略了已經寫好的程式碼
#安裝查詢集
objects = ArticleManager() #安裝查詢集
def __str__(self):
return "文章:%s" % self.title
檢視呼叫
\OurBlog\Article\views.py
def example(request):
all_data = Article.objects.all()
count = Article.objects.article_count("while沒有寫例子") #呼叫自定義的查詢方法
return render(request,"article/example_model.html",locals())
前端呼叫
\OurBlog\Article\templates\article\example_model.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Model Example</title>
</head>
<body>
{% for article in all_data %}
<p>
{{ article.title }}
</p>
{% endfor %}
<p>
{{ count }}
</p>
</body>
</html>
- 行級的自定義查詢
定義自定義查詢類:
class Article(models.Model):
"""
一篇文章可以有一個作者,一個作者可以以有一篇文章,
一篇文章有多條評論
一個文章有多個分類
一個分類有多篇文章
"""
title = models.CharField(max_length = 32,verbose_name = "文章標題")
time = models.DateField(verbose_name = "文章發表日期")
description = RichTextUploadingField(verbose_name = "文章描述")
content = RichTextUploadingField(verbose_name = "文章內容")
picture = models.ImageField(verbose_name = "文章圖片",upload_to = "images/article")
author = models.ForeignKey(Author)
classify = models.ManyToManyField(Classify)
commant = models.ForeignKey(to=Comment, verbose_name="文章評論", blank = True,null = True) #文章可以有評論,也可以沒有,""代表blank,None代表null
def valid_title(self):
"""
定義查詢集
"""
title = self.title #獲取title欄位的內容
if "while" in title: #進行判斷返回指定結果
return "這個文章牛"
else:
return "一般般吧"
前端呼叫:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Model Example</title>
</head>
<body>
{% for article in all_data %}
<p>
{{ article.title }} <!--這裡顯示文章的title-->
{{ article.valid_title }} <!--這裡顯示我們自定義查詢集返回的結果-->
</p>
{% endfor %}
<p>
<!--這裡返回查詢文章的總數-->
{{ count }}
</p>
</body>
</html>
效果如下:
如果你的文章中是不同的title,查詢出來的結果是不一樣的,就不像我這個這麼統一了,我這個是為了偷懶,全是複製貼上新增的一樣的資料,快去試試自己的Blog