Django之MTV
返回當前時間
url.py文件內容:
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^timmer/', views.timmer), ]
views.py文件內容:
from django.shortcuts import render,HttpResponse,redirect def timmer(request): import time ctime=time.time() # return HttpResponse (ctime) #只能返回字符串 return render(request,"timmer.html", {"ctime":ctime}) #返回html,這樣就能定義返回的樣式
timmer.html文件內容:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>timmer</title> < style > p{ color: red; } </style> </head> <body> {#雙大括號是模板語法,裏面是變量,接受views.py的參數#} <p>當前時間:{{ ctime }}</p> </body> </html>
二、url控制器
1、url的分組
urls.py文件內容:
from django.conf.urls import url,include from django.contrib import admin from django.shortcuts import HttpResponse from app01.views import * urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^timer/$', timer), # timer(request) #分組 url(r'^books_achrive/(\d+)/$', book_detail), # book_detail(request,3) url(r'^books_achrive/(\d+)/(\d+)/$', books_achrive), # books_achrive(request,2012,12) #有名分組books_achrive後面有一個year組和一個month組 url(r'^books_achrive/(?P<year>\d+)/(?P<month>\d+)/$', books_achrive2), # books_achrive(request,year=2012,month=12) ]
views.py文件內容:
from django.shortcuts import render,HttpResponse,redirect def book_detail(reqeust,id): return HttpResponse(id) def books_achrive(request,year,month): return HttpResponse(year+":"+month) def books_achrive2(request,month,year): return HttpResponse(year+":"+month)
這樣用戶訪問的路徑為/books_achrive/2012/12/時,就會在URL匹配到url(r'^books_achrive/(\d+)/(\d+)/$', books_achrive),然後執行books_achrive函數
2、url的分發
在項目下的urls.py文件裏面定義連接到具體的應用的路徑
url(r'^app01/', include('app01.urls'), ),
然後在具體應用的urls.py文件裏面定義具體的url
from django.conf.urls import url,include from app01.views import * urlpatterns = [ url(r'^timer/$', timer), # timer(request) url(r'^books_achrive/(\d+)/$', book_detail), # book_detail(request,3) url(r'^books_achrive/(?P<year>\d+)/(?P<month>\d+)/$', books_achrive2), # books_achrive(request,year=2012,month=12) ]
3、URL 的反向解析
在使用Django 項目時,一個常見的需求是獲得URL 的最終形式,以用於嵌入到生成的內容中(視圖中和顯示給用戶的URL等)或者用於處理服務器端的導航(重定向等)。
人們強烈希望不要硬編碼這些URL(費力、不可擴展且容易產生錯誤)或者設計一種與URLconf 毫不相關的專門的URL 生成機制,因為這樣容易導致一定程度上產生過期的URL。
換句話講,需要的是一個DRY 機制。除了其它有點,它還允許設計的URL 可以自動更新而不用遍歷項目的源代碼來搜索並替換過期的URL。
在需要URL 的地方,對於不同層級,Django 提供不同的工具用於URL 反查:
(1)在模板中:使用url 模板標簽。
from django.conf.urls import url from . import views urlpatterns = [ url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'), ]
在模板的代碼中使用下面的方法獲得它們:
<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a> <ul> {% for yearvar in year_list %} <li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li> {% endfor %} </ul>
(2)在Python 代碼中:使用django.core.urlresolvers.reverse() 函數。
from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect def redirect_to_year(request): year = 2006. return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))
(3)在更高層的與處理Django 模型實例相關的代碼中:使用get_absolute_url() 方法。
4、反向解析示例:登錄頁面
urls.py文件內容:
from django.conf.urls import url,include from django.contrib import admin from django.shortcuts import render,HttpResponse,redirect from app01.views import * urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^login/', login,name="xxx"), #定義url的別名xxx ]
views.py文件內容:
from django.shortcuts import render,HttpResponse,redirect def login(request): if request.method=="GET": print(request.GET) print(request.POST) print(request.method) print(request.path) print(request.path_info) print(request.body) return render(request, "login.html") else: user=request.POST.get("user") pwd=request.POST.get("pwd") if 1: #用戶輸入的用戶名和密碼與數據庫裏面的做對比,判斷是否一致 return redirect("/app01/timer/")
登錄頁面login.html文件內容:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Title</title> <style> p{ color: red; } </style> </head> <body> <form action="{% url 'xxx' %}" method="post"> {% csrf_token %} #解決出現Forbidden (403)錯誤 <p>用戶名 <input type="text" name="user"></p> <p>密碼 <input type="password" name="pwd"></p> <input type="submit"> </form> </body> </html>
利用反向解析的好處:訪問的時候用url的別名可以避免了隨著url的變化而訪問路徑跟著變化
三、視圖層之視圖函數(views)
1、HttpRequest對象的屬性
(1)HttpRequest.body
一個字符串,代表請求報文的主體。在處理非 HTTP 形式的報文時非常有用,例如:二進制圖片、XML,Json等。
但是,如果要處理表單數據的時候,推薦還是使用 HttpRequest.POST 。
(2)HttpRequest.path
一個字符串,表示請求的路徑組件(不含域名)。
例如:"/music/bands/the_beatles/"
(3)HttpRequest.method
一個字符串,表示請求使用的HTTP方法。必須使用大寫。
例如:"GET"、"POST"
(4)HttpRequest.encoding
一個字符串,表示提交的數據的編碼方式(如果為None則表示使用DEFAULT_CHARSET的設置,默認為'utf-8')。
這個屬性是可寫的,你可以修改它來修改訪問表單數據使用的編碼。
接下來對屬性的任何訪問(例如從GET或POST中讀取數據)將使用新的encoding值。
如果你知道表單數據的編碼不是DEFAULT_CHARSET ,則使用它。
(5)HttpRequest.GET
一個類似於字典的對象,包含HTTP、GET的所有參數。詳情請參考QueryDict對象。
(6)HttpRequest.POST
一個類似於字典的對象,如果請求中包含表單數據,則將這些數據封裝成QueryDict對象。
POST請求可以帶有空的POST字典 —— 如果通過HTTPPOST方法發送一個表單,但是表單中沒有任何的數據,QueryDict對象依然會被建。
因此,不應該使用 if request.POST來檢查使用的是否是POST方法;應該使用 if request.method == "POST"
另外:如果使用POST上傳文件的話,文件信息將包含在FILES屬性中。
(7)HttpRequest.REQUEST
一個類似於字典的對象,它首先搜索POST,然後搜索GET,主要是為了方便。靈感來自於PHP的 $_REQUEST。
例如,如果GET = {"name": "john"}而POST = {"age": '34'} , REQUEST["name"]將等於"john", REQUEST["age"]將等於"34"。
強烈建議使用GET和POST而不要用REQUEST,因為它們更加明確。
(8)HttpRequest.COOKIES
一個標準的Python字典,包含所有的cookie。鍵和值都為字符串。
(9)HttpRequest.FILES
一個類似於字典的對象,包含所有的上傳文件信息。
FILES 中的每個鍵為<input type="file" name="" /> 中的name,值則為對應的數據。
註意,FILES 只有在請求的方法為POST 且提交的<form> 帶有enctype="multipart/form-data" 的情況下才會包含數據。否則,FILES 將為一個空的類似於字典的對象。
(10)HttpRequest.META
一個標準的Python 字典,包含所有的HTTP 首部。具體的頭部信息取決於客戶端和服務器,下面是一些示例:
CONTENT_LENGTH —— 請求的正文的長度(是一個字符串)。
CONTENT_TYPE —— 請求的正文的MIME 類型。
HTTP_ACCEPT —— 響應可接收的Content-Type。
HTTP_ACCEPT_ENCODING —— 響應可接收的編碼。
HTTP_ACCEPT_LANGUAGE —— 響應可接收的語言。
HTTP_HOST —— 客服端發送的HTTP Host 頭部。
HTTP_REFERER —— Referring 頁面。
HTTP_USER_AGENT —— 客戶端的user-agent 字符串。
QUERY_STRING —— 單個字符串形式的查詢字符串(未解析過的形式)。
REMOTE_ADDR —— 客戶端的IP 地址。
REMOTE_HOST —— 客戶端的主機名。
REMOTE_USER —— 服務器認證後的用戶。
REQUEST_METHOD —— 一個字符串,例如"GET" 或"POST"。
SERVER_NAME —— 服務器的主機名。
SERVER_PORT —— 服務器的端口(是一個字符串)。
從上面可以看到,除 CONTENT_LENGTH 和 CONTENT_TYPE 之外,請求中的任何 HTTP 首部轉換為 META 的鍵時,
都會將所有字母大寫並將連接符替換為下劃線最後加上 HTTP_ 前綴。
所以,一個叫做 X-Bender 的頭部將轉換成 META 中的 HTTP_X_BENDER 鍵。
(11)HttpRequest.user
一個AUTH_USER_MODEL類型的對象,表示當前登錄的用戶。
如果用戶當前沒有登錄,user將設置為django.contrib.auth.models.AnonymousUser的一個實例。你可以通過is_authenticated()區分它們。
例如:
if request.user.is_authenticated(): # Do something for logged-in users. else: # Do something for anonymous users.
user 只有當Django啟用AuthenticationMiddleware中間件時才可用。
(12)HttpRequest.session
一個既可讀又可寫的類似於字典的對象,表示當前的會話。只有當Django啟用會話的支持時才可用。
(13)HttpRequest.resolver_match
一個ResolverMatch的實例,表示解析後的URL。這個屬性只有在URL解析方法之後才設置,這意味著它在所有的視圖中可以訪問,
但是在URL解析發生之前執行的中間件方法中不可以訪問(比如process_request,但你可以使用process_view代替)。
四、MTV模型
Django的MTV分別代表:
Model(模型):負責業務對象與數據庫的對象(ORM)
Template(模版):負責如何把頁面展示給用戶
View(視圖):負責業務邏輯,並在適當的時候調用Model和Template
此外,Django還有一個urls分發器,它的作用是將一個個URL的頁面請求分發給不同的view處理,view再調用相應的Model和Template
1、模板層(template)
from django.conf.urls import url,include from django.contrib import admin from django.shortcuts import HttpResponse from app01.views import * urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^template/', temp_func,), ]
views.py文件內容:
def temp_func(request): l=[11,222,333] dic={"name":"yuan","age":23} class Person(object): def __init__(self,name,age): self.name=name self.age=age def learning(self): return "learning" alex=Person("alex",45) egon=Person("egon",36) person_list=[alex,egon] import datetime now=datetime.datetime.now() print(now) file_size=234212123 content="hello yuan world text" s="<a href='http://www.baidu.com'>hello</a>" #return render(request,"temp.html",{"l":l,"dic":dic}) return render(request,"temp.html",locals())
app01應用下創建templatetags模塊(文件夾),裏面創建my_filters_tags.py文件,內容如下:
@register.filter def multi_filter(x,y): return x * y @register.simple_tag def multi_tag(x,y): return x * y
temp.html文件內容:
{% load my_filters_tags %} <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>變量</h3> <p>{{ l }}</p> {# 結果是:[11, 222, 333] #} <p>{{ l.1 }}</p> {# 結果是:222 #} <p>{{ dic }}</p> {# 結果是:{'name': 'yuan', 'age': 23} #} <p>{{ dic.name }}</p> {# 結果是:yuan #} <p>{{ alex.age }}</p> {# 結果是:45 #} <h3>過濾器</h3> {# 語法;{{obj|filter__name:param}} #} <p>{{ l.1|add:100 }}</p> {# 結果是:322 #} <p>{{ now|date:"Y-m-d" }}</p> {# 結果是:2018-04-16 #} <p>{{ file_size|filesizeformat }}</p> {# 結果是:223.4 MB #} <p>{{ content|truncatechars:12 }}</p> {# 結果是:hello yua... 加上點號一共顯示12個字符 #} <p>{{ content|truncatewords:2 }}</p> {# 結果是:hello yuan ... 顯示兩個單詞#} <p>{{ content|slice:"2:-1" }}</p> {# 結果是:llo yuan world tex #} <p>{{ s|safe }}</p> {# 結果是:hello 告訴Django這段代碼是安全的不必轉義#} <h3>標簽</h3> {% for person in person_list %} {# for循環person_list列表 #} <p>{{ forloop.counter0 }} {{ person.name }}:{{ person.age }} --- {{ person.learning }}</p> {% endfor %} {# {{ forloop.counter0 }} 可以取到循環序號 #} {# 如果變量l.0 > 100,就顯示100,否則顯示變量l.0 #} {% if l.0 > 100 %} <p>100</p> {% else %} <p>{{ l.0 }}</p> {% endif %} <h4>自定義過濾器或者標簽</h4> {{ l.0|multi_filter:2 }} {# 結果是:22 #} {% multi_tag l.0|add:12 10 %} {# 結果是:230 #} </body> </html>
五、Django-model基礎
1、在settings.py配置下面內容可以查看翻譯成的sql語句
LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level':'DEBUG', }, } }
2、創建模型
class Author(models.Model): #Author表包含 nid、name、age、 authorDetail字段 nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) age = models.IntegerField() # 與AuthorDetail建立一對一的關系 authorDetail = models.OneToOneField(to="AuthorDetail") class AuthorDetail(models.Model): #AuthorDetail表包含nid、birthday、telephone、addr字段 nid = models.AutoField(primary_key=True) birthday = models.DateField() telephone = models.BigIntegerField() addr = models.CharField(max_length=64) class Publish(models.Model): #Publish表包含nid、name、city、email字段 nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) city = models.CharField(max_length=32) email = models.EmailField() class Book(models.Model): #Book表包含nid、title、publishDate、price、keepNum、publish字段 nid = models.AutoField(primary_key=True) title = models.CharField(max_length=32) publishDate = models.DateField() price = models.DecimalField(max_digits=5, decimal_places=2) keepNum = models.IntegerField() < br > commentNum = models.IntegerField() # 與Publish建立一對多的關系,外鍵字段建立在多的一方 publish = models.ForeignKey(to="Publish", to_field="nid") # 與Author表建立多對多的關系,ManyToManyField可以建在兩個模型中的任意一個,自動創建第三張表 authors = models.ManyToManyField(to='Author')
3、字段選項
(1)null
如果為True,Django將用NULL來在數據庫中存儲空值。 默認值是False.
(2)blank
如果為True,該字段允許不填。默認為False。要註意,這與null不同。null純粹是數據庫範疇的,而blank是數據驗證範疇的。
如果一個字段的blank = True,表單的驗證將允許該字段是空值。如果字段的blank = False,該字段就是必填的。
(3)default
字段的默認值。可以是一個值或者可調用對象。如果可調用 ,每有新對象被創建它都會被調用。
(4)primary_key
如果為True,那麽這個字段就是模型的主鍵。如果你沒有指定任何一個字段的primary_key = True,Django就會自動添加一個IntegerField字段做為主鍵,所以除非你想覆蓋默認的主鍵行為,否則沒必要設置任何一個字段的primary_key = True。
(5)unique
如果該值設置為True, 這個數據字段的值在整張表中必須是唯一的
(6)choices
由二元組組成的一個可叠代對象(例如,列表或元組),用來給字段提供選擇項。 如果設置了choices ,默認的表單將是一個選擇框而不是標準的文本框,而且這個選擇框的選項就是choices 中的選項。
4、添加表記錄
(1)普通字段
#1、方式1 publish_obj = Publish(name="人民出版社", city="北京", email="[email protected]") publish_obj.save() # 將數據保存到數據庫 #2、方式2 < br > 返回值publish_obj是添加的記錄對象 publish_obj = Publish.objects.create(name="人民出版社", city="北京", email="[email protected]") < br > < br > 方式3 < br > 表.objects.create(**request.POST.dict())
(2)外鍵字段
#1、方式1: publish_obj = Publish.objects.get(nid=1) Book.objects.create(title="西遊記", publishDate="2012-12-12", price=665, pageNum=334, publish=publish_obj) #2、方式2: Book.objects.create(title="西遊記", publishDate="2012-12-12", price=665, pageNum=334, publish_id=1)
(3)多對多字段
book_obj = Book.objects.create(title="追風箏的人", publishDate="2012-11-12", price=69, pageNum=314, publish_id=1) author_yuan = Author.objects.create(name="yuan", age=23, authorDetail_id=1) author_egon = Author.objects.create(name="egon", age=32, authorDetail_id=2) book_obj.authors.add(author_egon, author_yuan) # 將某個特定的 model 對象添加到被關聯對象集合中。 ======= book_obj.authors.add(*[]) book_obj.authors.create() # 創建並保存一個新對象,然後將這個對象加被關聯對象的集合中,然後返回這個新對象。 解除關系: book_obj.authors.remove() # 將某個特定的對象從被關聯對象集合中去除。 ====== book_obj.authors.remove(*[]) book_obj.authors.clear() #清空被關聯對象集合。
5、查詢表記錄
(1)查詢相關API
< 1 > all(): 查詢所有結果
< 2 > filter(**kwargs): 它包含了與所給篩選條件相匹配的對象
< 3 > get(**kwargs): 返回與所給篩選條件相匹配的對象,返回結果有且只有一個,如果符合篩選條件的對象超過一個或者沒有都會拋出錯誤。
< 4 > exclude(**kwargs): 它包含了與所給篩選條件不匹配的對象
< 5 > values(*field): 返回一個ValueQuerySet——一個特殊的QuerySet,運行後得到的並不是一系列model的實例化對象,而是一個可叠代的字典序列
< 6 > values_list(*field): 它與values()非常相似,它返回的是一個元組序列,values返回的是一個字典序列
< 7 > order_by(*field): 對查詢結果排序
< 8 > reverse(): 對查詢結果反向排序
< 9 > distinct(): 從返回結果中剔除重復紀錄
< 10 > count(): 返回數據庫中匹配查詢(QuerySet)的對象數量。
< 11 > first(): 返回第一條記錄
< 12 > last(): 返回最後一條記錄
< 13 > exists(): 如果QuerySet包含數據,就返回True,否則返回False
(2)雙下劃線之單表查詢
models.Tb1.objects.filter(id__lt=10, id__gt=1) # 獲取id大於1 且 小於10的值 models.Tb1.objects.filter(id__in=[11, 22, 33]) # 獲取id等於11、22、33的數據 models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in models.Tb1.objects.filter(name__contains="ven") models.Tb1.objects.filter(name__icontains="ven") # icontains大小寫不敏感 models.Tb1.objects.filter(id__range=[1, 2]) # 範圍bettwen and startswith,istartswith, endswith, iendswith
(3)基於對象的跨表查詢
< 1 >一對多查詢(Publish 與 Book)
正向查詢(按字段:publish): # 查詢nid=1的書籍的出版社所在的城市<br> book_obj=Book.objects.get(nid=1)<br>print(book_obj.publish.city) # book_obj.publish 是nid=1的書籍對象關聯的出版社對象 反向查詢(按表名:book_set): # 查詢 人民出版社出版過的所有書籍 publish = Publish.objects.get(name="人民出版社") book_list = publish.book_set.all() # 與人民出版社關聯的所有書籍對象集合 for book_obj in book_list: print(book_obj.title)
< 2 >一對一查詢
正向查詢(按字段:authorDetail): # 查詢egon作者的手機號 author_egon = Author.objects.get(name="egon") print(author_egon.authorDetail.telephone) 反向查詢(按表名:author): # 查詢所有住址在北京的作者的姓名 authorDetail_list = AuthorDetail.objects.filter(addr="beijing") for obj in authorDetail_list: print(obj.author.name)
< 3 >多對多查詢
正向查詢(按字段:authors): book_obj = Book.objects.filter(title="西遊記").first() authors = book_obj.authors.all() for author_obj in authors: print(author_obj.name, author_obj.authorDetail.telephone) 反向查詢(按表名:book_set): # 查詢egon出過的所有書籍的名字 author_obj = Author.objects.get(name="egon") book_list = author_obj.book_set.all() # 與egon作者相關的所有書籍 for book_obj in book_list: print(book_obj.title) #查詢 人民出版社出版過的所有書籍 publish = Publish.objects.get(name="人民出版社") book_list = publish.bookList.all() # 與人民出版社關聯的所有書籍對象集合
(4)基於雙下劃線的跨表查詢
# 練習1: 查詢人民出版社出版過的所有書籍的名字與價格(一對多)
# 正向查詢 按字段:publish queryResult=Book.objects.filter(publish__name="人民出版社").values_list("title","price") # 反向查詢 按表名:book queryResult=Publish.objects.filter(name="人民出版社").values_list("book__title","book__price")
# 練習2: 查詢egon出過的所有書籍的名字(多對多)
# 正向查詢 按字段:authors: queryResult=Book.objects.filter(authors__name="yuan").values_list("title") # 反向查詢 按表名:book queryResult=Author.objects.filter(name="yuan").values_list("book__title","book__price")
# 練習3: 查詢人民出版社出版過的所有書籍的名字以及作者的姓名
# 正向查詢 queryResult=Book.objects.filter(publish__name="人民出版社").values_list("title","authors__name") # 反向查詢 queryResult=Publish.objects.filter(name="人民出版社").values_list("book__title","book__authors__age","book__authors__name")
# 練習4: 手機號以151開頭的作者出版過的所有書籍名稱以及出版社名稱
queryResult=Book.objects.filter(authors__authorDetail__telephone__regex="151").values_list("title","publish__name")
# 練習1: 查詢人民出版社出版過的所有書籍的名字與價格(一對多)
# 反向查詢 不再按表名:book,而是related_name:bookList queryResult = Publish.objects.filter(name="人民出版社").values_list("bookList__title", "bookList__price")
6、修改表記錄
Book.objects.filter(price=123,title="python").update(title="python123")
7、刪除表記錄
Book.objects.filter(price=123,title="python").delete() 你也可以一次性刪除多個對象。每個 QuerySet 都有一個 delete() 方法,它一次性刪除 QuerySet 中所有的對象。 例如,下面的代碼將刪除 pub_date 是2005年的 Entry 對象: Entry.objects.filter(pub_date__year=2005).delete()
要牢記這一點:無論在什麽情況下,QuerySet 中的 delete() 方法都只使用一條 SQL 語句一次性刪除所有對象,而並不是分別刪除每個對象。如果你想使用在 model 中自定義的 delete() 方法,就要自行調用每個對象的delete 方法。(例如,遍歷 QuerySet,在每個對象上調用 delete()方法),而不是使用 QuerySet 中的delete()方法。
在 Django 刪除對象時,會模仿 SQL 約束 ON DELETE CASCADE 的行為,換句話說,刪除一個對象時也會刪除與它相關聯的外鍵對象。 例如: b = Blog.objects.get(pk=1) # This will delete the Blog and all of its Entry objects. b.delete()
Django之MTV