1. 程式人生 > >python Django後臺開發筆記11

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);

八、開發注意

不能讓使用者看見錯誤