Django教程
Python是我學習的第一門編程語言,這兩天剛剛學完python的WEB-django框架,參考其他書友的教程,結合自己的理解,對其進行簡單的歸納總結。
一.搭建虛擬環境。
1.為什么使用虛擬環境?
一臺電腦上可能有多個項目,項目之間所使用的Django版本可能不同,這時就需要使用虛擬環境來創建想對獨立的python環境
virtualenv和virtualenvwrapper都可以用來創建虛擬環境,只是由于virtualenv用起來有點麻煩,所以wrapper對它進行了封裝,讓它更好用,最終我們使用wrapper提供的命令,但是實際工作都是virtualenv做的。
virtualenvwrapper的好處是,把虛擬環境全局管理起來了,不用針對每個項目建立。同一類項目(使用的django版本相同)可以建立同樣的虛擬環境,也不用管它在哪,直接一個workon就可以。
2.如何安裝配置虛擬環境?
Window 10平臺
需要安裝兩個python模塊
pip install virtualenv
pip install virtualenvwrapper-win
需要配置環境變量(默認虛擬環境會建立在系統c盤,不推薦)
實質為配置虛擬環境生成的位置
配置環境變量:
此電腦-》右鍵屬性-》高級設置-》高級-》環境變量
點擊系統變量下方的新建按鈕,打開創建窗口
變量名:WORKON_HOME
變量值:虛擬環境存放路徑(創建的用來作虛擬環境的空文件夾命名必須是英文,不能出現任何中文,最好是創建在一個磁盤的根路徑下)
運行管理員窗口:
常用命令:
創建虛擬環境:mkvirtualenv環境名
切換虛擬環境: ???workon 環境名
查看所有虛擬環境: ?lsvirtualenv
刪除虛擬環境: ?rmvirtualenv?環境名
退出虛擬環境:deactivate
3.django安裝(在虛擬環境下)
一般來說,選擇長期支持版本比較好。
pip install django==1.8.2
pip install Django==2.0.3
pip install django
檢查是否安裝成功
進入python環境,運行如下代碼:
import django
django.get_version()
二.Django開發流程
1.新建項目 :
django-admin startproject 項目名 這樣會在當前目錄新建一個目錄,里面已經有一些基本的配置文件:
目錄說明
manage.py:一個命令行工具,可以使你用多種方式對Django項目進行交互
內層的目錄:項目的真正的Python包
_init _.py:一個空文件,它告訴Python這個目錄應該被看做一個Python包
settings.py:項目的配置文件(如配置數據庫)
urls.py:項目的URL聲明
wsgi.py:項目與WSGI兼容的Web服務器入口
2.新建APP:
?django-admin startapp APP名稱 如果是搭建一個非常簡單的應用,那么不使用APP也行,只需要吧路由指向目標view就可以了,但是如果要搭建復雜的應用并且需要良好的隔離性,那最好使用APP。同樣,使用該命令也會在當前目錄下新建一個目錄,里面已經包含一些配置文件:
創建APP后,需要在主配置文件settings.py里面的INSTALLED_APPS里面添加該APP的名稱
3.Pycharm使用指定的虛擬環境打開上述項目
選中導航欄中的File右鍵單擊打開選擇Settings-->Project-->project interpreter-->設置按鈕——》打開Add python interpreter窗口——》選擇System interpreter--》在右邊的Base interpreter:選項中點擊右邊的三個點打開找到虛擬環境的文件位置,找到python.exe選中
4.數據庫
Django同很多框架一樣使用了ORM(Object Relational Mapping,對象關系映射)的方式,每個model類代表一張數據庫的表,每一個屬性代表其一個字段(這種特性的實現依賴于python的元類)。
數據表定義
在APP(應用)配置文件models.py中新建模型類),如:定義一張商品表
當建立好models過后,執行如下遷移命令就可以在數據庫中新建或更新數據表了:
生成遷移文件:根據模型類生成sql語句
python manage.py makemigrations
執行遷移:執行sql語句生成數據表
python manage.py migrate
注:在已經遷移的數據模型中添加字段,再次進行遷移,那么新添加的數據必須要允許null或者設置默認值,否則會報錯,這其實是為了保護已經存在了的數據,當然在添加完該字段后把null去掉再更新數據庫就可以了。
字段類型
注:Django默認為每張表設置了一個int(11)的自增主鍵(即id),不需要自己去定義了。
常用類型
# 數字類型:
AutoField:一個根據實際ID自動增長的IntegerField,通常不指定;如果不指定,一個主鍵字段將自動添加到模型中
IntegerField? ? (默認長度為11)的整數
PositiveIntegerField:
SmallIntegerField
PositiveSmallIntegerField
BigIntegerField:
BinaryField:
BooleanField:true/false 字段,此字段的默認表單控制是CheckboxInput
NullBooleanField:支持null、true、false三種值
DecimalField(max_digits=None, decimal_places=None):使用python的Decimal實例表示的十進制浮點數;DecimalField.max_digits:位數總數 ;DecimalField.decimal_places:小數點后的數字位數
FloatField:用Python的float實例來表示的浮點數
# 字符類型
CharField(max_length=字符長度):字符串,默認的表單樣式是 TextInput,
只需要指定枚舉枚舉元組即可,例如type = models.CharField('類型', choices=CONTENT_TYPE),其中CONTENT_TYPE=(('a', 'abc'))
TextField:text類型,大文本字段,一般超過4000使用,默認的表單控件是Textarea
CommaSeparatedIntegerField:用逗號分隔的整數,我擦,這有用
# 時間類型
DateField[auto_now=False, auto_now_add=False]):使用Python的datetime.date實例表示的日期(參數DateField.auto_now:每次保存對象時,自動設置該字段為當前時間,用于"最后一次修改"的時間戳,它總是使用當前日期,默認為false;
參數DateField.auto_now_add:當對象第一次被創建時自動設置當前時間,用于創建的時間戳,它總是使用當前日期,默認為false
該字段默認對應的表單控件是一個TextInput. 在管理員站點添加了一個JavaScript寫的日歷控件,和一個“Today"的快捷按鈕,包含了一個額外的invalid_date錯誤消息鍵
auto_now_add, auto_now, and default 這些設置是相互排斥的,他們之間的任何組合將會發生錯誤的結果
)
TimeField:使用Python的datetime.time實例表示的時間,參數同DateField
DateTimeField() # DATETIME類型,包括了日期和時間,需要注意的是Django默認的TIME_ZONE是UTC;在初始化的時候,格式如"2015-04-27T15:01:00Z",它屬于python里面的datetime.datetime類型,可分別用year/month/day等獲取時間。另外Django如果要實用MySQL里面的TIMESTAMP類型也是用該字段表示,并且在插入的時候不能直接插入一個整數,依然只能插入一個datetime.datetime對象,用時間戳的時候USE_TZ必須為False
FileField:一個上傳文件的字段
ImageField:繼承了FileField的所有屬性和方法,但對上傳的對象進行校驗,確保它是個有效的image
其它很有用的類型:
EmailField:Email郵箱類型FileField:文件類型,不過不能設置為primary_key和unique,要使用該字段還有很多需要注意的地方,具體的見官方文檔
FilePathField:同上ImageFieldIPAddressField:從1.7開始已經不建議使用了,應該使用下面這個GenericIPAddressField:
URLField
UUIDField
字段通用參數
primary_key:若為 True, 則該字段會成為模型的主鍵字段
null:如果為True,Django 將空值以NULL 存儲到數據庫中,默認值是 False
blank:如果為True,則該字段允許為空白,默認值是 False
null和blank對比:null是數據庫范疇的概念,blank是表單驗證證范疇的
max_length = 3? ? ? ? ? ?最大長度,對整型無效
default = ''? ? ? ? ? ? ? 設置默認值
verbose_name =? ? ? ? ?相當于備注,如果沒給出那么就是該字段,當然,要指定的話,可以直接第一個參數一個字符串就可以指定了
editable = False/True? ? ? # 是否可編輯
unique:如果為 True, 這個字段在表中必須有唯一值
auto_now = False/True? ? ? # 用于時間,每次更新記錄的時候更新該字段
auto_now_add = False/True? # 用于時間,創建新紀錄的時候自動更新該字段
db_column:字段的名稱,如果未指定,則使用屬性的名稱
db_index:若值為 True, 則在表中會為此字段創建索引
help_text:會在form表單控件中顯示help文本
choices # 很實用的一個功能,相當于存儲一個枚舉列表,其中左邊的key是實際存儲在數據庫中的值,例如,可以這樣定義一個字段:YEAR_IN_SCHOOL_CHOICES= (
????????('FR', 'Freshman'),
? ? ? ? ('SO', 'Sophomore'),
? ? ? ? ('JR', 'Junior'),
? ? ? ? ('SR', 'Senior'),
?)? ? ? ??
然后在定義字段的時候給個參數choices=YEAR_IN_SCHOOL_CHOICES,在插入字段的時候,使用'RF'這樣的,在獲取字段值的時候這樣:p.get_year_in_school_display()即可顯示'Freshman'
verbose_name? ? ? ? # 定義字段的注釋
關系的類型包括
ForeignKey:一對多,將字段定義在多的一端中
ManyToManyField:多對多,將字段定義在兩端中
OneToOneField:一對一,將字段定義在任意一端中
5.配置項
全局配置
DEBUG =True? ? ? # DEBUG模式? ;項目在開發過程中 需要設置Debug為False 上線部署之后關閉調試模式
TEMPLATE_DEBUG =True# TEMPLATE的DEBUG模式
ALLOWED_HOSTS = []# 設置哪些域名可以訪問,當debug為false時必須為其指定一個值,['*']表示允許所有的訪問
INSTALLED_APPS = [默認APP+自己的APP]
MIDDLEWARE_CLASSES = [中間件]
ROOT_URLCONF ='admin.urls'# 讀取的默認的url文件
TEMPLATES =[ {? 'DIRS': [os.path.join(BASE_DIR,"templates")],? ? }]?配置templates(模塊,即HTML前端頁面)
# Database 數據庫的配置:(默認自帶sqlite3數據庫)
LANGUAGE_CODE ='en-us'? ? ? ? ? ?# 語言,中文可用zh-Hans、zh-CN,完整列表見:http://www.i18nguy.com/unicode/language-identifiers.html
TIME_ZONE ='Asia/Chongqing'# 時區
USE_TZ =False# 數據庫中要使用時間戳就應該關閉這個
# Static files (CSS, JavaScript, Images) 靜態文件目錄
?STATIC_URL ='/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR,'static')]?配置自己創建的靜態文件(即js/css/img)
STATIC_ROOT = os.path.join(BASE_DIR,'static')# 這個選項默認是沒有的,在編碼時將靜態文件放在APP中的static目錄下,部署時用python manage.py collectstatic就可以把靜態文件收集到STATIDC_ROOT目錄
# 配置 存儲session使用redis數據庫
# SESSION_ENGINE = 'redis_sessions.session'
# SESSION_REDIS_HOST = 'localhost'
# SESSION_REDIS_PORT = 6379
# SESSION_REDIS_DB = 0
# SESSION_REDIS_PASSWORD = ''
# SESSION_REDIS_PREFIX = 'session'
發送郵件配置
EMAIL_BACKEND ='django.core.mail.backends.smtp.EmailBackend'
EMAIL_USE_TLS =True #是否使用TLS安全傳輸協議(用于在兩個通信應用程序之間提供保密性和數據完整性。)
EMAIL_USE_SSL =False #是否使用SSL加密,qq企業郵箱要求使用
EMAIL_HOST ='smtp.163.com' #發送郵件的郵箱 的 SMTP服務器,這里用了163郵箱
EMAIL_PORT =25 #發件箱的SMTP服務器端口
EMAIL_HOST_USER ='18137128152@163.com' #發送郵件的郵箱地址
EMAIL_HOST_PASSWORD ='qikuedu'
DEFAULT_FROM_EMAIL ='zzyblog <18137128152@163.com>'? ? ?(發件人)
請求與響應
HttpReqeust對象
服務器接收到http協議的請求后,會根據報文創建HttpRequest對象
視圖函數的第一個參數是HttpRequest對象
在django.http模塊中定義了HttpRequest對象的API
屬性
下面除非特別說明,屬性都是只讀的
path:一個字符串,表示請求的頁面的完整路徑,不包含域名
method:一個字符串,表示請求使用的HTTP方法,常用值包括:'GET'、'POST'
encoding:一個字符串,表示提交的數據的編碼方式
如果為None則表示使用瀏覽器的默認設置,一般為utf-8
這個屬性是可寫的,可以通過修改它來修改訪問表單數據使用的編碼,接下來對屬性的任何訪問將使用新的encoding值
GET:一個類似于字典的對象,包含get請求方式的所有參數
POST:一個類似于字典的對象,包含post請求方式的所有參數
FILES:一個類似于字典的對象,包含所有的上傳文件
COOKIES:一個標準的Python字典,包含所有的cookie,鍵和值都為字符串
session:一個既可讀又可寫的類似于字典的對象,表示當前的會話,只有當Django 啟用會話的支持時才可用,詳細內容見“狀態保持”
方法
is_ajax():如果請求是通過XMLHttpRequest發起的,則返回True
HttpResponse對象
在django.http模塊中定義了HttpResponse對象的API
HttpRequest對象由Django自動創建,HttpResponse對象由程序員創建
不調用模板,直接返回數據
from django.http import HttpResponse
def index(request):
return HttpResponse('你好')
調用模板
from django.http import HttpResponse
from django.template import RequestContext, loader
def index(request):
????????t1 = loader.get_template('polls/index.html')
????????context = RequestContext(request, {'h1': 'hello'})
????????return HttpResponse(t1.render(context))
屬性
content:表示返回的內容,字符串類型
charset:表示response采用的編碼字符集,字符串類型
status_code:響應的HTTP響應狀態碼
content-type:指定輸出的MIME類型
方法
init :使用頁內容實例化HttpResponse對象
write(content):以文件的方式寫
flush():以文件的方式輸出緩存區
set_cookie(key, value='', max_age=None, expires=None):設置Cookie
key、value都是字符串類型
max_age是一個整數,表示在指定秒數后過期
expires是一個datetime或timedelta對象,會話將在這個指定的日期/時間過期,注意datetime和timedelta值只有在使用PickleSerializer
時才可序列化
max_age與expires二選一
如果不指定過期時間,則兩個星期后過期
from django.http import HttpResponse
from datetime import *
def index(request):
????????response = HttpResponse()
????????if request.COOKIES.has_key('h1'):
????????response.write('
????????' + request.COOKIES['h1'] + '
????????')
????????response.set_cookie('h1', '你好', 120)
????????# response.set_cookie('h1', '你好', None, datetime(2016, 10, 31))
????????return response
delete_cookie(key):刪除指定的key的Cookie,如果key不存在則什么也不發生
子類HttpResponseRedirect
重定向,服務器端跳轉
構造函數的第一個參數用來指定重定向的地址
from django.http import HttpResponse,HttpResponseRedirect
def index2(request,id):
????????print(id,type(id))
? ? ? ?return HttpResponseRedirect("/redirecttest")
簡寫函數
render
render(request, template_name[, context])
結合一個給定的模板和一個給定的上下文字典,并返回一個渲染后的HttpResponse對象
request:該request用于生成response
template_name:要使用的模板的完整名稱
context:添加到模板上下文的一個字典,視圖將在渲染模板之前調用它
from django.shortcuts import render
def index(req):
????????return render(req, 'booktest/index.html', {'h1': 'hello'})
重定向
redirect(to)
為傳遞進來的參數返回HttpResponseRedirect
to推薦使用反向解析
from django.shortcuts import redirect
from django.core.urlresolvers import reverse
def index(req):
????????return redirect(reverse('booktest:index2'))
6.路由與視圖
url: web訪問請求的入口(相當于Laravel里的路由)
view:應用的邏輯部分,從客戶端接收請求,處理并返回數據,一般返回到template模板進行渲染(相當于Laravel里的控制器)
將/list定位到booktest這個APP里面的views里面的list視圖方法來處理的形式
app_name ="booktest"
urlpatterns = [
url(r'^list/$',list,name="list"),
給url命名可以方便我們進行統一修改url樣式,比如之前用list的url可以訪問到list這個方法,但現在如果想改成ls的方式來訪問,那么由于后端的模板渲染等都是用的其命名list,就無需修改后端邏輯了
路由按照app分組
首先主urls.py里面使用include包含應用下的urls.py文件
from django.conf.urls import include
urlpatterns = [
? ? ????url(r'^app1', include('app1.urls',namespace='app1')),
]
然后在app1下的urls.py文件里面,進行如下設置:
from django.conf.urls import url
from . import views
app_name ="app1"
urlpatterns = [
? ? url(r'^/(\d+)$', views.hello,,name="index"), #一個參數對應一個分組。
]
7.ORM增刪改查
ORM代替SQL語句實現
進入shell命令行:? python?manage.py shell
引入所需的模型類?from APP(應用名).models import? ?模型類
查詢記錄
Blog.objects.all()# 獲取該表的所有記錄,返回的是記錄對象組成的列表
Blog.objects.get(pk=1)# 根據主鍵獲取數據
Blog.objects.get(name="")# 只會找到第一個匹配的數據
Blog.objects.filter(name="")# 這個就會找到匹配的多個數據
Blog.objects.filter(name__contains="")# 模糊查找name字段的值,返回列表Blog.objects.order_by("字段1","字段2")# 排序,order_by不加任何參數表示不需要排序(字段前'+'代表升序,'-'代表降序。)
Blog.objects.all().order_by("字段")
Blog.objects.count()# 返回記錄總數
Blog.objects.values('id','name')? # 相當于select id name from Blog,返回的是一個字典Blog.objects.values('name').distinct()? # distinct在django的mysql引擎中無法對field進行distinct操作,所以需要這樣做Blog.objects.values_list('id', flat=True)# 查詢該字段的所有值并且返回的是id的列表,而不是包括了名字的字典
Blog.objects.all().defer('title')# 僅僅取某個字段,這里返回是一個model對象Blog.objects.all().only('title')# 僅僅取某個字段,也是返回一個model對戲那個Blog.objects.all().values_list('title')# 僅僅取某個字段,這里返回一個數組
Blog.objects.latest('id')# 根據某個字段查找其最后一條記錄,返回的是一個對戲那個,不是id
Blog.objects.filter(time__gte ='2015-07-23', time__lte ='2015-07-24')# 大于等于并且小于等于,不加e表示不能等于
Blog.objects.filter(time__isnull =True)# 判斷某個字段是否為空
Blog.objects.all().exclude(id=7)# 排除,即不等于Blog.objects.filter('time__year':'2015','time__month':'08','time__day':'17'):按年月日查詢日期,可僅查詢其中某一個條件
增加記錄:
book= BookInfo()
book.title = “神雕俠侶”
book.pub_date = “1998-01-01”
book.save()
修改記錄
修改書標題
book.title = “神雕俠侶續集”
book.save()
刪除記錄
刪除shan圖書
book.delete()
關聯查詢
數據庫中存儲外鍵為整形
ORM中外鍵為對象類型
1.一對一(關聯關系雙方可隨意定義):
外鍵創建方法:models.OneToOneField()
關聯方(關聯關系所在方)查找非關聯方:關聯方對象.關聯關系名
非關聯方查找關聯方:非關聯方對象.關聯方類名(小寫)
2.多對多(關聯關系雙方隨意定義):
外鍵創建方法:models.ManyToManyField()
關聯方(關聯關系所在方)查找非關聯方:關聯方對象.關聯關系名
非關聯方查找關聯方:非關聯方對象.關聯方類名(小寫)_set.all()
3.一對多(關聯關系定義在多方):
外鍵創建方法:models.Foreignkey()
關聯方(關聯關系所在方)查找非關聯方:關聯方對象.關聯關系名
非關聯方查找關聯方:非關聯方對象.關聯方類名小寫_set.all()