天天看點

Django|第一部

Django

·   Django流程

·   Django url

·   Django view

·   Django form

①:Django流程介紹

MTV模式

  注明的MVC模式:所謂MVC就是把web應用分為模型(M),控制器(C),視圖(V)三層;他們之間以一種插件似的,松耦合的方式連接配接在一起.

  模型負責業務對象與資料庫的對象(ORM),視圖負責與使用者的互動(頁面),控制器(C)接受使用者的輸入調用模型和視圖完成使用者的請求.

注: 什麼是松耦合:簡單的說,松耦合是一個 重要的保證互換性的軟體開發方法.

Django|第一部

Django的MTV模式本質上與MVC模式沒有什麼差别,也是各元件之間為了保持松耦合關系,隻是定義上有些許不同,Django的MTV分别代表:

Model(模型):負責業務對象與資料庫的對象(ORM)

Template(模版):負責如何把頁面展示給使用者

View(視圖):負責業務邏輯,并在适當的時候調用Model和Template

此外,Django還有一個url分發器,它的作用是将一個個URL的頁面請求分發給不同的view處理,view再調用相應的Model和Template

Django|第一部

②:Django URL

URL配置(URLconf)就像Django 所支撐網站的目錄。它的本質是URL模式以及要為該URL模式調用的視圖函數之間的映射表;你就是以這種方式告訴Django,對于這個URL調用這段代碼,對于那個URL調用那段代碼。URL的家在是從配置檔案中開始。

Django|第一部

參數說明:

  ·   一個正規表達式字元串

  ·   一個可調用對象,通常為一個視圖函數或一個指定視圖函數路徑的字元串

  ·   可選的要傳遞給視圖函數的預設參數(字典形式)

  ·   一個可選的name參數

下面是一個示例URLconf:

from django.conf.urls import url
  
from . import views
  
urlpatterns = [
    url(r'^articles/2003/$', views.special_case_2003),
    url(r'^articles/([0-9]{4})/$', views.year_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]
      

注釋:

  ·  To capture a value from the URL, just put parenthesis around it.

   (從URL中捕獲值,隻是把它周圍的括号。)

  • There’s no need to add a leading slash, because every URL has that. For example, it’s 

    ^articles

    , not 

    ^/articles

    .

   (沒有必要添加一個領先的削減,因為每個URL。例如,它的^的文章,而不是^ /文章。)

  · The 'r' in front of each regular expression string is optional but recommended. It tells Python that a string is “raw” – that nothing in the string should be escaped. See Dive Into Python’s explanation.

(每個正規表達式字元串前面的'R'是可選的,但建議。它告訴Python字元串是“原始” - 沒有什麼字元串中應該進行轉義。見深入Python的解釋。)

Example requests:

  · A request to 

/articles/2005/03/

 would match the third entry in the list. Django would call the function

views.month_archive(request, '2005', '03')

(請求/文章/ 2005/03 /比對清單中的第三項,Django的将調用函數views.monthly存檔(要求下,'2005','03')。)

  · /articles/2005/3/ would not match any URL patterns, because the third entry in the list requires two digits for the month.

  (/文章/ 2005/3 /不比對任何URL模式,因為第三個條目清單中需要兩個數字的月. .)

  · 

/articles/2003/

 would match the first pattern in the list, not the second one, because the patterns are tested in order, and the first one is the first test to pass. Feel free to exploit the ordering to insert special cases like this. Here, Django would call the function 

views.special_case_2003(request)

  (/文章/ 2003 /将比對第一個模式清單中,沒有第二個,因為模式是為了進行測試.第一個是第一個測試通過,随時利用順序插入這樣的特殊情況,這裡,Django所說的功能的觀點。特殊情況2003(請求))

  · /articles/2003 would not match any of these patterns, because each pattern requires that the URL end with a slash.

  (/文章/ 2003不比對任何這些模式,因為每個模式要求以斜線結尾的URL。)

/articles/2003/03/03/

 would match the final pattern. Django would call the function

views.article_detail(request, '2003', '03', '03')

  (/文章/ 2003/03/03 /将最終的模式相比對,Django将調用函數views.article細節(的要求,'2003','03','03')。)

Named groups

  · The above example used simple, non-named regular-expression groups (via parenthesis) to capture bits of the URL and pass them as positional arguments to a view. In more advanced usage, it’s possible to use named regular-expression groups to capture URL bits and pass them as keyword arguments to a view.

(上面的例子中使用簡單,non-named正規表達式組(通過括号)捕捉到的URL,将他們作為一個視圖的位置參數。在更進階的用法,可以使用指定的正規表達式組捕獲的URL)

  · In Python regular expressions, the syntax for named regular-expression groups is 

(?P<name>pattern)

, where 

name

 is the name of the group and 

pattern

 is some pattern to match.

(在Python正規表達式,命名正規表達式組的文法是(?P <名>的模式),其中name是組的名稱和模式是某種模式相比對。)

  · Here’s the above example URLconf, rewritten to use named groups:

(下面是上面的例子中的URLconf,改寫使用命名組:)

Django|第一部
Django|第一部
import re

ret=re.search('(?P<id>\d{3})/(?P<name>\w{3})','weeew34ttt123/ooo')

print(ret.group())
print(ret.group('id'))
print(ret.group('name'))      

正則知識

from django.conf.urls import url
  
from . import views
  
urlpatterns = [
    url(r'^articles/2003/$', views.special_case_2003),
    url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
    url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
    url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
]
      

This accomplishes exactly the same thing as the previous example, with one subtle difference: The captured values are passed to view functions as keyword arguments rather than positional arguments. For example:

(這完成了前面的例子一樣,有一個微妙的差異:捕獲的值傳遞給視圖函數作為關鍵字參數而不是位置參數。例如:)  

A request to /articles/2005/03/ would call the function views.month_archive(request, year='2005',month='03'), instead of views.month_archive(request, '2005', '03').

(的請求/用品/ 2005/03/會調用函數views.monthly存檔(要求,今年='2005',一個月='03'),而不是views.monthly存檔(要求下,'2005','03')。)

A request to 

/articles/2003/03/03/

 would call the function 

views.article_detail(request, year='2003',month='03', day='03')

(請求/文章/ 2003/03/03 /将調用該函數的觀點。文章細節(請求,年= ' 2003 ',月=“03”,天=“03”)。)

In practice, this means your URLconfs are slightly more explicit and less prone to argument-order bugs – and you can reorder the arguments in your views’ function definitions. Of course, these benefits come at the cost of brevity; some developers find the named-group syntax ugly and too verbose.

(在實踐中,這意味着你的URLconf稍微更明确,不容易參數順序錯誤 - 你可以在你的意見'函數定義重新排序的參數。當然,這些優點來在簡短的費用;一些開發商找到命名組的文法醜陋,太冗長。)

常見寫法實列:

Django|第一部

Captured arguments are always strings:

Each captured argument is sent to the view as a plain Python string, regardless of what sort of match the regular expression makes. For example, in this URLconf line:

(每個捕獲的參數發送到視圖作為普通的Python字元串,無論什麼樣的比對正規表達式做。例如,在該URL配置行:)

url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),      

...the 

year

 argument passed to 

views.year_archive()

 will be a string,

(…參數傳遞給視圖。年存檔()将是一個字元串,)

not an integer, even though the 

[0-9]{4}

 will only match integer strings.

(不是整數,即使[0-9]{4}将隻比對整數串。)

Including other URLconfs :

At any point, your 

urlpatterns

 can “include” other URLconf modules. This essentially “roots” a set of URLs below other ones.

(在任何時候,您的網址模式可以“包含”其他的URLconf子產品。這實質上是“根”的一套低于其他的網址。)

For example, here’s an excerpt of the URLconf for the 

Django website

 itself. It includes a number of other URLconfs:

(例如,這裡的URL配置為Django的網站本身的摘錄。它包括許多其他URL配置的:)

from django.conf.urls import include, url
  
urlpatterns = [
    # ... snip ...
    url(r'^community/', include('django_website.aggregator.urls')),
    url(r'^contact/', include('django_website.contact.urls')),
    # ... snip ...
]      

 Passing extra options to view functions:

URLconfs have a hook that lets you pass extra arguments to your view functions, as a Python dictionary.

(URLconf中有一個挂鈎,可以傳遞額外的參數給您的視圖功能,作為一個Python字典。)

The 

django.conf.urls.url()

 function can take an optional third argument which should be a dictionary of extra keyword arguments to pass to the view function.

(該django.conf.urls.url()函數可以接受這應該是額外的參數的字典傳遞給視圖功能可選的第三個參數。)

For example:

from django.conf.urls import url
from . import views
  
urlpatterns = [
    url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
]
      

  In this example, for a request to /blog/2005/, Django will call views.year_archive(request, year='2005',foo='bar').

(在本例中,請求/部落格/ 2005 / Django将調用視圖。年存檔(請求,年= ' 2005 ',foo = '參數')。)

This technique is used in the 

syndication framework

 to pass metadata and options to views.

(這種技術用于聚合架構通過中繼資料和視圖選項。)

 Dealing with conflicts

( 應對沖突)

It’s possible to have a URL pattern which captures named keyword arguments, and also passes arguments with the same names in its dictionary of extra arguments. When this happens, the arguments in the dictionary will be used instead of the arguments captured in the URL.

(可以有一個URL模式捕獲關鍵字參數,并通過參數具有相同名字的字典的額外參數。當這種情況發生時,将使用參數在字典裡而不是參數捕獲)

需要注意的是,當你加上參數時,對應函數views.index必須加上一個參數,參數名也必須命名為a,如下:

Django|第一部
Django|第一部
Django|第一部
if  auth():
 
    obj=model.user.filter()
 
{'obj':obj}      

應用

name param

Django|第一部
Django|第一部
urlpatterns = [
    url(r'^index',views.index,name='bieming'),
    url(r'^admin/', admin.site.urls),
    # url(r'^articles/2003/$', views.special_case_2003),
    url(r'^articles/([0-9]{4})/$', views.year_archive),
    # url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
    # url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),

]
###################

def index(req):
    if req.method=='POST':
        username=req.POST.get('username')
        password=req.POST.get('password')
        if username=='alex' and password=='123':
            return HttpResponse("登陸成功")



    return render(req,'index.html')

#####################

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{#     <form action="/index/" method="post">#}
     <form action="{% url 'bieming' %}" method="post">
         使用者名:<input type="text" name="username">
         密碼:<input type="password" name="password">
         <input type="submit" value="submit">
     </form>
</body>
</html>


#######################      

name的應用

 Django views

http請求中産生兩個核心對象:

  • http請求:HttpRequest對象
  • http響應:HttpResponse對象
Django|第一部
Django|第一部
# 擷取送出方式
request.method
if request.method == "POST":
        times = time.time()
        return render(request,'index.html')

# 擷取前端post送出的資料
request.POST.get('username')

# 擷取域名後路徑
get_full_path()   
例:http://127.0.0.1:8000/index33/?name=123 ,req.get_full_path()得到的結果就是/index33/?name=123      

HttpRequest對象

Django|第一部
Django|第一部
def test(request):
    # 往前端寫入字元串
    return HttpResponse("xxx") 
    # 跳轉路徑
    return redirect('/index/')

    # 渲染HTML檔案兩種方式
    return render(reuqest, "test.html") 
    return render_to_response('text.html')
        
    # 可以直接将函數中所有的變量傳給模闆
    return render(reuqest, "test.html",locals()) 

    # 可以根據通過字典的方式往前端傳值,取值輸入key即可
    return render(reuqest, "test.html",{'shijie':'你好'})         

HttpResponse對象

Django|第一部
Django|第一部
Django|第一部
Django|第一部
# path:       請求頁面的全路徑,不包括域名
#
# method:     請求中使用的HTTP方法的字元串表示。全大寫表示。例如
#
#                    if  req.method=="GET":
#
#                              do_something()
#
#                    elseif req.method=="POST":
#
#                              do_something_else()
#
# GET:         包含所有HTTP GET參數的類字典對象
#
# POST:       包含所有HTTP POST參數的類字典對象
#
#              伺服器收到空的POST請求的情況也是可能發生的,也就是說,表單form通過
#              HTTP POST方法送出請求,但是表單中可能沒有資料,是以不能使用
#              if req.POST來判斷是否使用了HTTP POST 方法;應該使用  if req.method=="POST"
#
#
#
# COOKIES:     包含所有cookies的标準Python字典對象;keys和values都是字元串。
#
# FILES:      包含所有上傳檔案的類字典對象;FILES中的每一個Key都是<input type="file" name="" />标簽中                     name屬性的值,FILES中的每一個value同時也是一個标準的python字典對象,包含下面三個Keys:
#
#             filename:      上傳檔案名,用字元串表示
#             content_type:   上傳檔案的Content Type
#             content:       上傳檔案的原始内容
#
#
# user:       是一個django.contrib.auth.models.User對象,代表目前登陸的使用者。如果通路使用者目前
#              沒有登陸,user将被初始化為django.contrib.auth.models.AnonymousUser的執行個體。你
#              可以通過user的is_authenticated()方法來辨識使用者是否登陸:
#              if req.user.is_authenticated();隻有激活Django中的AuthenticationMiddleware
#              時該屬性才可用
#
# session:    唯一可讀寫的屬性,代表目前會話的字典對象;自己有激活Django中的session支援時該屬性才可用。      

參數

Django Form

一、基礎form送出

比如寫一個計算 a和 b 之間的簡單應用,網頁上這麼寫.

Django|第一部
Django|第一部
<!DOCTYPE html>
<html>
<body>
<p>請輸入兩個數字</p>
  
<form action="/add/" method="POST"><input type="text" name="a"> <input type="text" name="b">    
    <input type="submit" value="送出">
</form>
</body>
</html>      

HTML

把這些代碼儲存成一個index.html,放在 templates 檔案夾中。

網頁的值傳到伺服器是通過 <input> 或 <textarea>标簽中的 name 屬性來傳遞的,在伺服器端這麼接收:

Django|第一部
Django|第一部
from django.http import HttpResponse
from django.shortcuts import render
 
def index(request):
    return render(request, 'index.html')
     
def add(request):
    a = request.POST.GET('a')
    b = request.POST.GET('b')
    a = int(a)
    b = int(b)
    return HttpResponse(str(a+b)      

伺服器端

但是,比如使用者輸入的不是數字,而是字母,就出錯了,還有就是送出後再回來已經輸入的資料也會沒了。

那麼,當然如果我們手動将輸入之後的資料在 views 中都擷取到再傳遞到網頁,這樣是可行的,但是很不友善,是以 Django 提供了更簡單易用的 forms 來解決驗證等這一系列的問題。

 二、Django Forms應用

1、簡單案例一

在app01下建立一個檔案forms.py

Django|第一部
Django|第一部
from django import forms
 
class AddForm(forms.Form):
    a = forms.IntegerField()
    b = forms.IntegerField()      

forms.py

(視圖函數) views.py 

Django|第一部
Django|第一部
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from django.shortcuts import render,HttpResponse
from app01.forms import AddForm

def index(request):
    if request.method == 'POST':# 當送出表單時
        # form 包含送出的資料
        form = AddForm(request.POST) 
        # 如果送出的資料合法
        if form.is_valid():
            a = form.cleaned_data['a']
            b = form.cleaned_data['b']
            return HttpResponse(str(int(a) + int(b)))
    # 當正常通路時
    else:
        form = AddForm()
    return render(request, 'index.html', {'form': form})      

views.py

對應的模闆檔案 index.html

Django|第一部
Django|第一部
<form method='post'>
{% csrf_token %}
{{ form }}
<input type="submit" value="送出">
</form>      

index.html

這個簡單的案例,大家不知道有沒有看出其中的蹊跷呢,仔細觀察,form類給我做了驗證,使用者輸入錯了會彈出報錯資訊

2丶簡單案例二

Django|第一部
Django|第一部
from django.db import models

# Create your models here.


class BookType(models.Model):
    caption = models.CharField(max_length=64)   #最大長度

class Book(models.Model):
    name = models.CharField(max_length=64)    #最大長度
    pages = models.IntegerField()     
    price = models.DecimalField(max_digits=10,decimal_places=2)
    pubdate = models.DateField()
    book_type = models.ForeignKey('BookType')


#當然min_length --最小長度      

models.py

Django|第一部
Django|第一部
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from django.shortcuts import render
from app01.forms import Form1

def form1(request):
    if request.method == 'POST':
        # 擷取請求内容做驗證
        f = Form1(request.POST)
        if f.is_valid():
            print(f.cleaned_data)
        else:
            print(type(f.errors),f.errors)
        return render(request,'form1.html',{'error':f.errors,'form':f})
    else:
        f = Form1()
        return render(request,'form1.html',{'form':f})      
Django|第一部
Django|第一部
#!/usr/bin/env python
# -*- coding:utf-8 -*-

from django import forms
from app01 import models

class Form1(forms.Form):
    # 使用者名,給該标簽添加一個class屬性,還有空值的報錯資訊修改
    user = forms.CharField(
        widget=forms.TextInput(attrs={'class': 'c1'}),
        error_messages={'required': '使用者名不能為空'},)
    
    # 密碼定義最大長度和最小長度
    pwd = forms.CharField(max_length=4,min_length=2)
    # 郵箱定義錯誤資訊,required為空值錯誤資訊,invalid為郵箱比對錯誤資訊
    email = forms.EmailField(error_messages={'required': '郵箱不能為空', 'invalid': '郵箱格式錯誤'})
    # 生成多行文本編輯框
    memo = forms.CharField(widget=forms.Textarea())
    
    # 下拉菜單實時更新資料庫
    user_type_choice = models.BookType.objects.values_list('id','caption')
    book_type = forms.CharField(widget=forms.widgets.Select(choices=user_type_choice,attrs={'class': "form-control"}))
    
    def __init__(self,*args, **kwargs):
        super(Form1, self).__init__(*args, **kwargs)
        self.fields['book_type'] =  forms.CharField(
            widget=forms.widgets.Select(choices=models.BookType.objects.values_list('id','caption'),attrs={'class': "form-control"}))      

HTML頁面(form1.html)

Django|第一部
Django|第一部
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .input-group{
            position: relative;
            padding: 20px;
            width: 250px;
        }
        .input-group input{
            width: 200px;
            display: inline-block;
        }
        .input-group span{
            display: inline-block;
            position: absolute;
            height: 12px;
            font-size: 8px;
            border: 1px solid red;
            background-color: darksalmon;
            color: white;
            top: 41px;
            left: 20px;
            width: 202px;
        }
    </style>
</head>
<body>

<form action="/form1/" method="post">

    <div class="input-group">
        {{ form.user }}
        {% if error.user.0 %}
        <span>{{ error.user.0 }}</span>
        {% endif %}
    </div>
    <div class="input-group">
        {{ form.pwd }}
        {% if error.pwd.0 %}
        <span>{{ error.pwd.0 }}</span>
        {% endif %}
    </div>
    <div class="input-group">
        {{ form.email }}
        {% if error.email.0 %}
        <span>{{ error.email.0 }}</span>
        {% endif %}
    </div>
    <div class="input-group">
        {{ form.memo }}
        {% if error.memo.0 %}
        <span>{{ error.memo.0 }}</span>
        {% endif %}
    </div>
    <div class="input-group">
        {{ form.book_type }}
        {% if error.book_type.0 %}
        <span>{{ error.book_type.0 }}</span>
        {% endif %}
    </div>

    <div>
        <input type="submit" value="送出">
    </div>
</form>

</body>
</html>      

form1.html