python Django後臺開發筆記11
轉載來自2014-12-01 21:35:59http://www.cnblogs.com/wupeiqi/p/4133236.html
1、回顧上週WSGI流程
看HttpServer的程式碼,畫一個流程圖
為什麼開發時,我們不用這個框架呢?因為太單薄了,一切功能都需要自己去實現,所有的開發人員為了不讓自己太疲憊,就轉投使用一些web框架,也就是他們寫圖上的功能。好,既然說使用框架比我們自己寫要方便,就來看看到方便在那裡。
2、對比於自己的框架,我們來看一下Django框架是怎麼會做和用的!
先畫一個流程圖
注意,我們的框架是 Application類的Runserver方法接收到wsgi的請求資訊,然後返回了資料。
即然,之前一直說我們的框架和Django的框架本質上一樣的,對不對,那麼他肯定也有一個方法來接受 wsgi 的請求,然後再去執行一列後面的方法,然後給返回資料。這個方法就是 WSGIHandler 的 __call__ 方法,就是由它觸發的整個執行過程。這裡就是開始處理的源頭。也就是,每次請求到來的時候,就會從這裡開始去處理。
我們框架的起始點和Django的起始點都有,我們的框架是直接返回了資料,而Django又執行了一系列地方,再返回資料。我們就來看看這一列的方法中,都有那些功能,然後我們在一步步學習它。
一、路由系統
就是在Django裡,根據 url中的 模版去指定那個方法去處理請求。那Django是怎麼找的呢?
開始寫,登入:
幾個重要的配置:
TEMPLATE_DIRS = (
os.path.join(BASE_DIR,'Templates'),
)
STATICFILES_DIRS =(
os.path.join(BASE_DIR,'Statics'),
)
- 普通URL,每個路由指定一個函式。如果新建一個函式,那就再建立URL進行指定。那麼問題來了,我想要一個動態引數,建立一個程式,總不可能是1、2、3、4==》動態欄位
- URL裡動態引數,利用正則表示式,(\w*),這樣是不是就可以根據引數值,然後動態的去取資料了,那麼問題又來了,如果我想要為我的引數設定一個預設值呢?
- 正則表示式的模版,(?P<name>\w*),在引數後面,針對name設定預設值
- 當你的App多了之後,URL的區分是不是很麻煩了,需要匯入很多包,為了避免麻煩呢,我們使用 pattern 字首來解決這個問題。
- 最後一個就是 include,就是把這個url字首的所有東西,都交給另外一個url檔案。
url(r'^first/hello/(\w*)/(\d*)',FirstView.Hello),
url(r'^first/helloo/(?P<name>\w*)/(?P<id>\d*)',FirstView.Helloo),
url(r'^first/helloo/(?P<name>\w*)',FirstView.Helloo,{'id':333}),
from django.conf.urls import patterns, include, url
urlpatterns = patterns('',
url(r'^admin/',include('AdminApp.urls')),
url(r'^web/',include('WebApp.urls')),
)
from django.conf.urls import patterns, include, url
from AdminApp.Views.FirstView import Hello1
urlpatterns = patterns(
'',
url(r'^hello/$', Hello1),
)
還有一種想法就是動態建立模組和執行方法
例子:根據id的不同,去獲取不同的資料
經過以上的路由系統,就可以把請求轉反給我們指定view中的函式去執行。也就是開始了MTV框架中的V來執行。那我們知道,V其實就是業務處理單元,所有的處理都離不開資料,v 通過 m 從資料庫中獲取資料,然後再巢狀到 t 中,最後返回給使用者。
二、模型
- 一般情況下,我們使用 MySQLdb 來連線資料庫,首先我們需要建立資料庫,然後設計表結構,表機構設計好之後,在程式中些sql語句,然後對資料進行操作。
- 對於Django來說,他沒有什麼特別的,其實最終他也是通過SQL和資料打交道,不同的是什麼呢?就是Django在這裡為我們做了一些事情,讓我們操作比較便捷。
一般設計:
1、建立資料庫,設計表結構和欄位
2、編寫資料訪問層,對資料庫進行操作。
3、業務邏輯層去呼叫並返回資料即可。
而對於Djanog呢,他為我們提供了一種關係物件對映,也叫 ORM,Hibernate 、activerecord,EF。他是個什麼東西呢?
首先說,他是個什麼? 他規定專案中的類對應資料庫中的表,並且可以根據類去生成資料庫表和欄位,也稱為code first
Django也為我提供這種功能,利用這個功能我們可以省去一般設計中的前兩步,也就是表的設計和資料庫訪問層的建立。
一般的:
import MySQLdb
def GetList(sql):
db = MySQLdb.connect(user='root', db='wupeiqidb', passwd='1234', host='localhost')
cursor = db.cursor()
cursor.execute(sql)
data = cursor.fetchall()
db.close()
return data
def GetSingle(sql):
db = MySQLdb.connect(user='root', db='wupeiqidb', passwd='1234', host='localhost')
cursor = db.cursor()
cursor.execute(sql)
data = cursor.fetchone()
db.close()
return data
Django:建立類,然後只需要去繼承 django.db.models.Model 類就可以了,我們在建立資料庫的表的時候,是不會有一些一個數據型別、長度、能否為空、預設值、主鍵、外來鍵需要我們去設定啊,Django的ORM需要代替我們去設定這些內容。想要在程式碼中建立不是一件很難的事情,只要讓django程式碼和sql一一對應就好了。。。、
1、建立資料庫結構:
1、models.AutoField 自增列 = int(11) 如果沒有的話,預設會生成一個名稱為 id 的列,如果要顯示的自定義一個自增列,必須將給列設定為主鍵 primary_key=True。 2、models.CharField 字串欄位 必須 max_length 引數 3、models.BooleanField 布林型別=tinyint(1) 不能為空,Blank=True 4、models.ComaSeparatedIntegerField 用逗號分割的數字=varchar 繼承CharField,所以必須 max_lenght 引數 5、models.DateField 日期型別 date 對於引數,auto_now = True 則每次更新都會更新這個時間;auto_now_add 則只是第一次建立新增,之後的更新不再改變。 6、models.DateTimeField 日期型別 datetime 同DateField的引數 7、models.Decimal 十進位制小數型別 = decimal 必須指定整數位max_digits和小數位decimal_places 8、models.EmailField 字串型別(正則表示式郵箱) =varchar 對字串進行正則表示式 9、models.FloatField 浮點型別 = double 10、models.IntegerField 整形 11、models.BigIntegerField 長整形 integer_field_ranges = { 'SmallIntegerField': (-32768, 32767), 'IntegerField': (-2147483648, 2147483647), 'BigIntegerField': (-9223372036854775808, 9223372036854775807), 'PositiveSmallIntegerField': (0, 32767), 'PositiveIntegerField': (0, 2147483647), } 12、models.IPAddressField 字串型別(ip4正則表示式) 13、models.GenericIPAddressField 字串型別(ip4和ip6是可選的) 引數protocol可以是:both、ipv4、ipv6 驗證時,會根據設定報錯 14、models.NullBooleanField 允許為空的布林型別 15、models.PositiveIntegerFiel 正Integer 16、models.PositiveSmallIntegerField 正smallInteger 17、models.SlugField 減號、下劃線、字母、數字 18、models.SmallIntegerField 數字 資料庫中的欄位有:tinyint、smallint、int、bigint 19、models.TextField 字串=longtext 20、models.TimeField 時間 HH:MM[:ss[.uuuuuu]] 21、models.URLField 字串,地址正則表示式 22、models.BinaryField 二進位制 23、models.ImageField 圖片 24、models.FilePathField 檔案
外來鍵: Color = models.ForeignKey(ColorDic)一對一: authors = models.OneToOneField(OneModel)
多對多:authors = models.ManyToManyField(Author)
def __unicode__(self):
return self.name
引數
1.null=True
資料庫中欄位是否可以為空
2.blank=True
django的admin中新增資料時候是否可以為空
3、primary_key=False
主鍵,對AutoField設定主鍵後就會太低原來自增的ID列
4.auto_now和auto_now_add
auto_now 自動建立----無論新增或者修改,都是當前操作時間
auto_now_add 自動建立----永遠是建立時的時間
5.choices
GENDER_CHOICE=(
(u'M',u'Male'),
(u'F',u'Female'),
)
6.max_length
7.default 預設值
8.verbose_name Admin中欄位的顯示名稱
9.name|db_column 資料庫中欄位的名稱
10.unique=True 不允許重複
11.db_index=True 資料庫索引
12.editable=True 在Admin裡是否可編輯
13.error_messages=None提示錯誤
14.auto_created=False 自動建立
15.help_text 在admin中提示幫助資訊
16.validators=[]
17.upload-to
2、執行SQL
增加:建立例項,並呼叫save
更新:a.獲取例項,再sava;b.update(指定列)
刪除:a. filter().delete(); b.all().delete()
獲取:a. 單個=get(id=1) ;b. 所有 = all()
過濾:filter(name='xxx');filter(name__contains='');(id__in = [1,2,3]) ; icontains (大小寫無關的 LIKE ), startswith 和 endswith , 還有 range (SQL BETWEEN 查詢)
'gt', 'in', 'isnull', 'endswith', 'contains', 'lt', 'startswith', 'iendswith', 'icontains','range', 'istartswith'
排序:order_by("name") =asc ;order_by("-name")=desc
預設排序:class Meta: ordering = ['name']
返回第n-m條:第n條[0];前兩條[0:2]
指定對映:values
數量:count()
聚合:from django.db.models import Min,Max,Sum objects.all().aggregate(Max('guest_id'))
原始SQL:
cursor = connection.cursor()
cursor.execute('''SELECT DISTINCT first_name ROM people_person WHERE last_name = %s""", ['Lennon'])
row = cursor.fetchone()
三、模版
1、模版的建立過程,對於模版,其實就是讀取模版(其中巢狀著模版標籤),然後將 Model 中獲取的資料插入到模版中,最後將資訊返回給使用者。
1
2
3
4
5
注意:當資料POST的時候,Django做了跨站請求偽造
2、模版語言:
- {{ person_name }}
- {{ ship_date|date:"F j, Y" }} 不建議
{{ bio|truncatewords:"30" }}
{{ my_list|first|upper }}
{{ name|lower }}
- {% for item in item_list %} <li>{{ item }}</li> {% endfor %}
forloop.counter0
forloop.revcounter
forloop.revcounter0
forloop.first
forloop.last
forloop.parentloop - {% if ordered_warranty %}
{% if not ordered_warranty %} - {% include 'includes/nav.html' %} 包含標籤
- {% block title %}{% endblock %} {% extends "base.html" %} 模板
- {# this is not a comment #} {% comment %}{% endcomment %}
- {% ifequal user currentuser %} {% endifequal %}
3、Form
class ALogin(forms.Form):
username = forms.CharField()
email = forms.EmailField(required=True)
ip = forms.IPAddressField()
def Login(request):
if request.method == 'POST':
form = ALogin(request.POST)
if form.is_valid():
data = form.cleaned_data
return HttpResponse("<h1>OK</h1>");
form = ALogin()
#form = AccountForm(initial={'name': 'I love your site!'})
return render_to_response('Form/Login.html',{'form': form},context_instance=RequestContext(request))
當執行is_valid()方法的時候,會根據定義的正則表示式,去匹配傳入的值。
對於 form.as_table ,看一下原始碼,就知道他也很一般。我們自己也可以些一個。
擴充套件:根據自己的需求去定製html控制元件,如:分頁。
四、Admin
需要建立超級使用者:python manage.py createsuperuser
在模型部分已經有涉及到Admin方面的知識,Admin是一個Django提供給我們管理資料的頁面,不用再去費勁的去寫SQL語句,最開始建立的那些表,也是用於Admin的。
對於創站初期,admin還是很有用處的,每個App都有 admin.py 檔案,這個檔案連線了 APP 和 Admin
1、把模型註冊到admin裡才能使用: admin.site.register(Publisher)
2、Admin中表中每列的顯示都是預設object,只有設定了 __unnicode__ 方法之後,即顯示該返回值。
3、List中顯示多列
class AuthorAdmin(admin.ModelAdmin):
list_display = ('id','name',)
def name(self, obj):
return obj.Name
admin.site.register(DateTimeArg,AuthorAdmin)
list_display = ('id','Name',) --列表中顯示的列
search_fields = ('id', 'Name') --搜尋框
list_filter = ('Name',) --側邊過濾器
date_hierarchy = 'DataTime3' --時間下拉
ordering = ('-DataTime3',) --列表中的排序
fields = ('Name','DataTime1') --詳細頁面欄位順序
filter_horizontal = ('Name',) --顯示多對多的關係
raw_id_fields = ('publisher',) --顯示外來鍵的資料
五、中介軟體
http://www.cnblogs.com/wupeiqi/diary/2014/11/10/4087669.html
六、裝飾器的應用
@Filter(AccountFilter.Before, AccountFilter.After)
def Index(request,kargs):
def Filter(before_func,after_func):
def outer(main_func):
def wrapper(request,kargs):
before_result = before_func(request,kargs)
if(before_result != None):
return before_result;
main_result = main_func(request,kargs)
if(main_result != None):
return main_result;
after_result = after_func(request,kargs)
if(after_result != None):
return after_result;
return wrapper
return outer
def Before(request,kargs):
host = request.META
if host == '127.0.0.1':
return None
else:
#return redirect('http://www.baidu.com')
return None
def After(request,kargs):
pass
七、動態路由的實現
#coding:utf-8
import string
def Activator(request,controllerfile,controller,action,arg):
namespace = __import__(controllerfile);
model = getattr(namespace.Controllers, controller)
func = getattr(model, action)
result = func(request,arg);
return result;
def Execute(request,**arg):
controller = string.capwords(arg['controller']) + 'Controller';
action = string.capwords(arg['action']);
controllerfile = 'cmdbapp.Controllers.'+controller;
return Activator(request,controllerfile,controller,action,arg);
八、開發注意
不能讓使用者看見錯誤