本章內容:css
環境搭建及基礎配置html
URL設置前端
Django快速Web開發——模型(基礎)python
Django快速Web開發——管理後臺jquery
Django中文文檔nginx
參考文檔git
Django的安裝會涉及一下多個軟件,部署的參考文檔會有不少,遇到的報錯也會不少,百度、goole 可解決github
系統字符集:
#echo $LANG en_us.UTF-8
yum源設置:
mirrors.aliyun.com/help/centos or wget -O /etc/yum.repos.d/CentOs-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo
時區設置:
ntpdate time.windows.com
python 相關包安裝:
依賴的包: yum -y install openssl-devel readline-devel gcc gcc-c++ pypi setuptools 包,注意回退一個版本比較穩定
Wget -S https://pypi.python.org/packages/dc/8c/7c9869454bdc53e72fb87ace63eac39336879eef6f2bf96e946edbf03e90/setuptools-33.1.1.zip#md5=7963d41d97b94e450e3f8a217be06ffe unzip setuptools-33.1.1.zip cd setuptools-33.1.1 /usr/local/python27/bin/python setup.py install python-2.7.13 版本
wget -S https://www.python.org/ftp/python/2.7.13/Python-2.7.13.tgz ./configure --prefix=/usr/locl/python27 make && make intall pip 安裝 /usr/local/python27/bin/easy_install pip vim /etc/pip.conf [global] trusted-host = pypi.douban.com index-url = http://pypi.douban.com/simple [list] format=colums
virtualenv 環境安裝
/usr/local/python27/bin/pip install virtualenv cd data/ /usr/local/python27/bin/virtualenv ./python27env source /data/python27/env/bin/activate pip install ipython pip install mysql-python #deactiveate ,退出虛擬環境
django 安裝:
pip install "django>=1.8,<1.9" #安裝1.8版本 ipython 中 django.get_version() #查看版本
mysql 安裝
5.6版本比較穩定 rpm -ivh https://dev.mysql.com/get/mysql-community-release-el6-5.noarch.rpm sudo yum -y install mysql mysql-server mysql-devel zlib-devel
django-admin startproject opsweb #生成opswed項目
項目目錄結構:
運行第一個小實例:
須要提早在settings.py裏修改這一行: ALLOWED_HOSTS = ["*"]
python manage.py runserver 0.0.0.0:33333
這裏運行的時候遇到一個報錯:
ImportError: No module named security
這個是因爲我在virtualenv環境下建立的這個項目,執行的時候卻退出了,須要進入後再執行。
python manage.py startapp dashboard
生成的目錄結構:
目錄文件說明:
配置app
把app的名字寫入:
opsweb/settings.py
再對url進行配置:
添加到opsweb/urls.py中
能夠理解爲處理dashboard目錄,交給後面的函數來處理
配置視圖:
配置dashboard中的url:
梳理下流程:
如:發起url請求:http://59.110.12.72:33333/dashboard/hello/
首先匹配到dashboard 這個app,而後又在python27env/reboot/opsweb/opsweb/urls.py中匹配到了 url(r'^dashboard/', include("dashboard.urls")),而後就會去dashboard中查找urls.py. 在其中發現url(r'hello/$',views.hello), 而後就會執行views視圖中的hello函數。
視圖函數中的request是由Django建立的
def index(request): pass
request屬性
HttpRequest.scheme
HttpRequest.body
HttpRequest.path
HttpRequest.path_info
HttpRequest.method
HttpRequest.encoding
HttpRequest.GET
HttpRequest.POST
HttpRequest.META
HttpRequest.user
request方法
HttpRequest.get_host()
HttpRequest.get_full_path()
HttpRequest.build_absoulute_uri(location)
HttpRequest.get_signed_cookie()
HttpRequest.is_secure()
HttpRequest.is_ajax()
傳遞一個字符串做爲頁面的內容到HttpResponse構造函數
from django.http import HttpResponse return HttpResponse('Here is the text of hte web page')
return HttpResponse('Test',content_type="text/plain")
reponse屬性
HttpResponse.content
HttpResponse.charset
HttpResponse.status_code
HttpResponse.reason_phrase
reponse方法
HttpResponse.__init__(content=」, content_type=None, status=200, reason=None, charset=None)
如何用呢?待了解
django 中 return HttpResponse('內容'),這個內容只能是string格式的,因此須要 json.dumps(res) 下這個res結果
加入這個res是字典,後端已經序列化了,傳遞給前端後,須要把這個字符串轉化爲對象, var obj = JSON.parse(data)
前端對象轉換爲字符串 :
那爲題來了,ajax 請求中只能 return HttpResponse 嗎?最好是這樣,但能夠用 render,不過這個返回的是一個渲染好的html頁面,處理是個問題,redirect這個是不能用的!
支持傳遞list,dict
return JsonResponse([1,2,3], safe = False)
In [1]: from django.http import QueryDict In [2]: Get = QueryDict('a=1&b=2&c=3')
QueryDict的方法:
QueryDict.get(key, default=None)
QueryDict.setdefault(key, default=None)[source]
QueryDict.update(other_dict) QueryDict.items() QueryDict.values() QueryDict.copy() QueryDict.getlist(key, default=None)
QueryDict.setlist(key, list_)[source]
QueryDict.appendlist(key, item)
QueryDict.setlistdefault(key, default_list=None)
QueryDict.lists() QueryDict.pop(key) QueryDict.popitem() QueryDict.dict() QueryDict.urlencode(safe=None)
這種方法相比render較不適用,建議使用render,學習一下
與flask類似,須要創建一個templates文件夾,把html文件放到這裏,而後再渲染
視圖中添加:
urls中添加:
html文件:
後端驗證登陸
request.GET
request.POST
request.FILES #上傳文件
request.getlist() #checkbox 等多選的內容
1 def login(request): 2 print request 3 if request.method == "GET": 4 print 'username from get -->',request.GET.get('username') 5 print 'password from get-->',request.GET.get('password') 6 template = loader.get_template('login.html') 7 context = Context({"title":"reboot 運維平臺"}) 8 return HttpResponse(template.render(context)) 9 10 elif request.method == 'POST': 11 print 'username from get -->',request.POST.get('username') 12 print 'password from get-->',request.POST.get('password') 13 username = request.POST.get('username') 14 password = request.POST.get('password') 15 return HttpResponse('login ok!')
<html> <head> <title> {{title}} </title> <script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script> </head> <body> <h1>用戶登陸</h1> <ul> <form action="/dashboard/login/" method="post"> <li><input type="text" name="username" id="username" /></li> <li><input type="text" name="password" id="password" /></li> <li><input type="submit" value="login" id="form_submit" /></li> </form> </ul> <script> $(function(){ $('#form_submit').click(function(){ var username = $('#username').val(); var password = $('#password').val(); $.post("/dashboard/login/",{username:username,password:password},function(res){ alert(res) }) return false; #若是不return false的話,就會按照默認的請求走了 }) }) </script> </body> </html>
又名靜態文件配置
添加static目錄,須要添加setting裏面的
STATIC_URL = '/static/' STATICFILES_DIRS = ( os.path.join(BASE_DIR, "static"), )
這樣,就能夠在templates目錄下的html文件中引用這個url了
項目下的urls.py的配置
一、/index/
二、/index/(\d+)
三、/index/(?P<nid>\d+)
正則(?P<year>[0-9]{4})用法
至關於定義了一個year變量,在後邊匹配到條件,就把取到值複製給year
四、/index/(?P<nid>\d+) name='root'
reverse()
{% url 'root' 1 %}
五、include
當有N個app時,url的編寫都在項目的usls.py下就會有點亂,能夠把這個文件轉移到各個app下的urls.py下,須要在項目urls.py下作以下操做
from django.conf.urls import url, include
urlpatterns = [
url(r'^cmdb/', include('app01.urls'))
url(r'^monitor/', include('app02.urls'))
]
六、默認值(傳遞參數)
/index/ {'web':'root'}
def func(request, web):
return ......
例子:
url(r'^index/', views.index, {'name':'root'})
def index(request, name):
print(name)
return HttpResponse('ok')
這時候回多傳遞後面的字典給後端,而瀏覽器的格式不變。這個字典的變量能夠是動態的,如,動態獲取了客戶的信息,而後傳遞給後端。這是後再view中定義的函數,也須要傳遞這個字典的key,否則會報確實參數的錯。
七、name
對URL路由關係進行命名, ==> 之後能夠根據此名稱生成本身想要的URL
url(r'abcdefg', views.index, name='i1') url(r'bbbbbb/(\d+)/(\d+)', views.index, name='i2') url(r'dddddd/(?P<pid>\d+)/(?P<nid>\d+)/', views.index, name='i3')
def func(request, *args, **kwargs): from django.urls import reverse url1 = reverse('i1') #生成的url abcdefg url2 = reverse('i2', args = (1,2,)) #bbbbbb/1/2/ url3 = reverse('i3' , kwargs = {'pid':1, "nid":9}) #dddddd/1/9
action = {% url "i1" %}
{% url "i3" 1 2 %}
{% url 'i3' pid=1 nid = 9%}
視圖獲取用戶相關請求信息,以及請求頭。
print(tpye(request)) #查看類類型
from django.core.handlers.wsgi import WAGIRequest #能夠查看到全部的請求頭都是包含在environ 方法中的
print(request.environ)
for k,v in request.environ.items(): #去查看請求頭過來的全部信息
def login_view(request): if request.method == "GET": return render(request, "public/login.html") else: username = request.POST.get("username", "") userpass = request.POST.get("password", "") user = authenticate(username=username, password=userpass) ret = {"status":0, "errmsg":""} if user: login(request, user) ret['next_url'] = request.GET.get("next") if request.GET.get("next", None) else "/" else: ret['status'] = 1 ret['errmsg'] = "用戶名或密碼錯誤,請聯繫管理員" return JsonResponse(ret)
模板繼承:有時候許多頁面有許多類似之處,爲了書寫簡單就能夠用到末班繼承,
被繼承文件 layer.html ,寫好公共的內容, {% block content %} {% endblock %} 這個裏面是繼承的頁面中須要本身書寫的東西
繼承的文件 a.html {% extends 'layer.hmlt' %} #說明下這個內容是從哪裏繼承的
{% block content %} 書寫本身的代碼 {% endblock %} ,固然能夠寫多塊內容
模板導入:別人寫好的代碼塊,咱這個頁面上面須要導入,好比淘寶上面的每一個產品的塊
a.html b.html 這些都是一個個小的產品,這時候須要在主頁面導入
{% include 「a.html」 %}
{% include "b.html" %}
Simple_tag寫法
一、首先要在app的目錄下建立一個templatetags(名字不能變)目錄,app須要添加到setting裏面就沒必要多說了
二、穿件一個任意名稱的python文件,如xxoo.py
三、xxoo.py 代碼
from django import template register = template.Library() #register名字不能變 @register.simplt_tag def zidingyi(a,b): #能夠添加參數 return a + b
四、配置html文件
{% load xxoo %} //首先須要在html文件的頂部load這個python文件
{% zidingyi 2 5 %} //而後下面能夠引用這個函數了
優勢:能夠傳遞多個參數
缺點:不能做爲if條件
Filter
用法基本相同
from django import template register = template.Library() #register名字不能變 @register.filter def zidingyi(a,b): #能夠添加參數,最多隻容許兩個參數 return a + b
html文件
{% load xxoo %} //首先須要在html文件的頂部load這個python文件
{% ‘第一個參數’|zidingyi:「第二個參數」 %} //注意中間不能有空格
cookie:以鍵對的方式存儲在客戶端
django設置cookie: rep.set_cookie(key,value,參數)
def login(request): user_info = { 'dachengzi':{'pwd':'123'}, 'kangbazi':{'pwd':'123'} } if request.method == 'GET': print('I am here') return render(request, 'login.html') elif request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') print(username,password) res = user_info.get(username) if not res: return render(request, 'login.html') if res['pwd'] == password: print('I am coming to denglu') res = redirect('/denglu/') #能夠這種寫法 res.set_cookie('username111',username) return res else: return render(request,'login.html') def denglu(request): v = request.COOKIES.get('username111') #提取登陸的username if not v: return redirect('/login/') return render(request, 'denglu.html', {'current_user':v}) #在前端顯示登陸的user
參數:
key, 鍵
value
=
'', 值
max_age
=
None
, 超時時間
expires
=
None
, 超時時間(IE requires expires, so
set
it
if
hasn't been already.)
path
=
'/'
, Cookie生效的路徑,
/
表示根路徑,特殊的:跟路徑的cookie能夠被任何url的頁面訪問
domain
=
None
, Cookie生效的域名
secure
=
False
, https傳輸
httponly
=
False
只能http協議傳輸,沒法被JavaScript獲取(不是絕對,底層抓包能夠獲取到也能夠被覆蓋)
例:
current_date = datetime.datetime.utcnow()
current_date = current_date + datetime.timedelta(seconds=5)
response.set_cookie('username111', u, expires=current_data)
httponly=False 這隻後只有http能獲取到cookie,js獲取不到
<select onchange="changePageSize()"> <option value="10">10</option> <option value="30">30</option> <option value="50">50</option> <option value="100">100</option> </select> <script src="jquery.js"></script> <script src="jquery.cookie.js"></script> //cookie是基於juery的,對cookie進行操做 <script> function changePageSize(ths){ var v = $(ths).val() $.cookie('per_page_count', v) } </script>
cookie 加salt
obj = HttpResponse('s')
obj.set_signed_cookie('username', "kangbazi", salt='abcdefg') #加鹽加密
request.get_signed_cookie('username', salt='abcdefg') #用鹽解密
django實現session功能十分簡單,在視圖函數中添加以下,
request.session['username'] = username
看似簡單,其實django幫咱們作了許多事情
一、生成隨機字符串
二、寫到瀏覽器的cookie中,(sessionid的形式)
三、保存在服務器端的session中,(保存在了數據庫中django_session表中)
四、固然這個服務器端存session的字典中也能夠保存一些其餘的客戶的信息,來更好的識別客戶
待session設置完畢後須要
python manage.py makemigrations
python manage.py migrate
來使之生效
django的session的緩存時間默認是2周,能夠人爲設置
request.session.set_expiry(10s) 設置10s過時
還能夠在setting裏添加一些默認的設置
SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默認) SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在瀏覽器上時的key,即:sessionid=隨機字符串(默認) SESSION_COOKIE_PATH = "/" # Session的cookie保存的路徑(默認) SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默認) SESSION_COOKIE_SECURE = False # 是否Https傳輸cookie(默認) SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http傳輸(默認) SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默認) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否關閉瀏覽器使得Session過時(默認) SESSION_SAVE_EVERY_REQUEST = False # 是否每次請求都保存Session,默認修改以後才保存(默認)
setting的配置中
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'wang.....',
'USER':'#####',
'PASSWORD':'123456',
'HOST':'59.110.12.72',
'PORT':3306
}
}
測試連接數據是否成功:
python manage.py syncdb
須要注意的是,Django默認使用的是MySQLdb模塊連接MYSQL,python3中須要修改成pymysql,在project 同名文件夾下的__init__文件中添加以下代碼便可:
import pymysql
pymysql.install_as_MYSQLdb()
連接數據庫建立普通用戶:
python manage.py shell
from django.contrib.auth.models import User
user = User.objects.create_user('rock','rock@51reboot.com','123456')
建立管理員用戶,命令行模式下:
python manage.py createsuperuser --username=reboot --email=reboot@51reboot.com
修改密碼:
python manage.py shell
from django.contrib.auth.models import User
user = User.objects.get(username='rock')
user.set_password('rock')
user.save()
用戶登陸和退出驗證:
from django.contrib.auth import authenticate,login,logout def login_view(request): print request if request.method == "GET": template = loader.get_template('login.html') context = Context({"title":"reboot 運維平臺"}) return HttpResponse(template.render(context)) elif request.method == 'POST': print 'username from get -->',request.POST.get('username') print 'password from get-->',request.POST.get('password') username = request.POST.get('username') password = request.POST.get('password') user = authenticate(username=username,password=password) if user: login(request,user) return HttpResponse('login ok!') else: return HttpResponse('login fail') def logout_view(request): logout(request) return HttpResponse('logout success!!')
from django.views import view
class Home(view): #繼承view方法 ''' 執行get、post方法以前都會先執行dispatch方法 ''' def dispatch(self, request, *args, **kwargs): #代用父類中的dispatch print('before') result = super(Home, self).dispatch(request, *args, **kwargs) print('after') def get(self, request): print(request.method) return render(request, 'home.html') def post(self, request): print(request.method, 'POST') return render(request, 'home.html')
兩種架構:
MVC
即將程序分爲三個組成部分, model(模型)、view(視圖)、controller(控制器)
M 管理應用程序的狀態,
C 接受外部用戶的操做,根據操做訪問模型獲取數據
V 負責把數據格式化後呈獻給用戶
django 也是MVC的框架,可是在Django中,控制器接受用戶輸入的部分由框架自行處理,因此Django裏更關注的是模型(Model),模塊(Template)和視圖(Views),成爲MTV模式:
M 表明模型(Model) ,即數據存取層,該層處理與數據相關的全部事物:如何存取、如何驗證有效性、包含哪些行爲以及數據之間的關係等。
T 表明模板(Template), 即表現層,該層處理與表現相關的決定:如何在頁面或者其餘類型文檔中進行顯示
V 表明視圖(View), 即業務邏輯層,蓋層包含存取模型及調取恰當模塊的相關邏輯,你能夠把它看作模型與模塊之間的橋樑。
小例,經過django orm 添加表,而後admin展現:
首先在dashboard這個app下的models.py添加表
from django.db import models # Create your models here. class Publisher(models.Model): name = models.CharField(max_length=30) address = models.CharField(max_length=50) city = models.CharField(max_length=60) state_province = models.CharField(max_length=30) country = models.CharField(max_length=50) website = models.URLField() def __unicode__(self): #這兩行是爲了在後臺中以名字展示,否則不會顯示建立的名稱 return "<%s>"%(self.name) class Author(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=40) email = models.EmailField() def __unicode__(self): return "<%s,%s>"%(self.first_name,self.last_name) class Book(models.Model): title = models.CharField(max_length=100) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publication_date = models.DateField() def __unicode__(self): return "<%s>"%(self.title)
表格建立完畢後須要在數據苦衷生成了
python manage.py makemigrations
python manage.py migrate
這樣數據庫中就會生成對應的表:
表建立完畢了,就須要在app下的admin.py中導入表的信息
from django.contrib import admin # Register your models here. import models admin.site.register(models.Author) admin.site.register(models.Book) admin.site.register(models.Publisher)
python manay.py createsuperuser ,建立可登陸admin後臺的超級管理員用戶
這樣在訪問http://59.110.12.72:33333/admin/ ,就能夠在裏面作一些對標的增、刪、改、查 了
Django 數據庫支持的字段類型:
詳見:https://docs.djangoproject.com/en/1.9/ref/models/fields/
Django 中若是想要表格能夠輸入爲空:
null = True 控制的是數據庫能夠爲空
blank = True 告訴Django表格能夠爲空
而後再發布配置:
使標題顯示中文
ORM對數據庫進行操做
表中插入數據
python manage.py shell
>>> from dashboard.models import Publisher
>>> p1 = Publisher(name='Apress',address='USA',city='MHD',state_province='..',country='USA',website='www.baidu.com')
>>> p1.save() #這種方法,須要save()後纔會添加到數據庫
#下面這種方法,能夠直接在添加到數據庫
>>> p1 = Publisher.objects.create(name='laoboy',address='USA',city='MHD',state_province='..',country='USA',website='www.baidu.com')
這套命令對應這數據庫操做的 insert
若是要改變其中某個字段的值,須要怎麼操做呢?
p1.name = 'balabala'
p1.save()
這裏保存的時候,是又從新把整個表保存了一遍。
查找對象
>>> Publisher.objects.all()
[<Publisher: <快網出版社>>, <Publisher: <Apress>>, <Publisher: <oldboy>>]
注意到Django在選擇全部數據時並無使用 SELECT* ,而是顯式列出了全部字段。 設計的時候就是這樣:SELECT* 會更慢
>>> Publisher.objects.filter(name='oldboy')
[<Publisher: <oldboy>>]
一樣,也支持,多條件過濾
>>> Publisher.objects.filter(name='oldboy',country='USA')
[<Publisher: <oldboy>>]
模糊查詢
>>> Publisher.objects.filter(name__contains="boy") #中間是雙橫槓
[<Publisher: <oldboy>>]
獲取單個對象並對齊修改
>>> Publisher.objects.get(name='oldboy')
<Publisher: <oldboy>>
>>> a = Publisher.objects.get(name='oldboy')
>>> a.name = 'oldboy2'
>>> a.save()
獲取對象後進行排序
>>> Publisher.objects.order_by(
"name"
) #按照name來排序
>>> Publisher.objects.order_by(
"state_province"
,
"address"
) #第一項同樣的,按照第二項來排序
>>> Publisher.objects.order_by(
"-name"
) #倒敘
排來排去有點麻煩,能夠用meta來進行全局的排序
連鎖查詢
>>> Publisher.objects.
filter
(country
=
"U.S.A."
).order_by(
"-name"
)
[<Publisher: O'Reilly>, <Publisher: Apress>]
>>> Publisher.objects.order_by(
'name'
)[
0
] #指向要帥選出來的第一條數據
<Publisher: Apress>
篩選到數據並修改:
刪除對象
shell 中修改密碼:
from django.contrib.auth.models import User u = User.objects.get(username='admin') #獲得admin用戶的對象 u.set_password('123') #設置密碼 u.password #查看的密碼就是加密後的 #添加新用戶 u2 = User() u2.username = 'u2' u2.set_password('123') u2.save() #設置is_staff後即可以登陸後臺系統了 u2.is_staff = True #django user登陸鑑權 from django.contrib.auth import authenticate test = authenticate(username='u2', password='123') #若是有值則存在,None則不存在
用戶驗證登陸的時候若是沒有驗證成功,django會有一個本身的rewritelogin的地址若是想要更改這個login的得知的話,則須要在settings配置文件中添加以下一行
LOGIN_URL = ‘/login’
django自帶方法
一、login
from django.contrib.auth import login, authenticate user = authenticate(username='u2', password='123') login(request, user) #登陸
二、login_required
from django.contrib.auth.decorators import login_required @login_required def index(request): #裝飾到函數前面 pass
xss: django爲了安全機制,默認傳遞的都是字符串,好比來自瀏覽客戶的評論,若是給寫了個js腳本,抱歉那是不會執行的,只是按照字符串來對待
肯定安全的狀況下,那如何讓其對這字符串作解釋呢?
方法:
一、前端 {{ page_str |safe}} //對後端傳遞過來的字符串做解釋
二、後端 from django.utils.safestring import mark_safe
page_str = mark_safe(page) #對html的字符串作mark_safe後,再傳遞
手寫一個分頁:
def user_list(request): current_page = request.GET.get('p',1) #獲取參數p,沒有就默認爲1 start = (current_page-1) * 10 end = current_page * 10 data = LIST[start:end] #LIST 想象爲數據庫獲取的數據 all_count = len(LIST) count, yushu = divmod(all_count, 10) if y: count += 1 page_list = [] for i in range(1, count+1): temp = '<a href="/user_list/?p=%s>%s</a>"' %(i,i) page_list.append(temp) page_str = "".join(page_list) page_str = mark_safe(page_str) return render(request, 'user_list.html' , {'li': data, 'page_str': page_str})
CSRF, Cross Site Request Forgery, 跨站點僞造請求。舉例來說,某個惡意的網站上有一個指向你的網站的連接,若是某個用戶已經登陸到你的網站上了,那麼當這個用戶點擊這個惡意網站上的那個連接時,就會向你的網站發來一個請求,你的網站會覺得這個請求是用戶本身發來的,其實呢,這個請求是那個惡意網站僞造的。具體的細節及其危害見 wikipedia
機制:django 第一次響應來自某個客戶端的請求時,會在服務器端隨機生成一個 token,把這個 token 放在 cookie 裏。而後每次 POST 請求都會帶上這個 token,這樣就能避免被 CSRF 攻擊。
setting中開啓csrf功能後,在沒有作特殊處理的狀況下會遇到下面的報錯:
那如何解決這個問題呢?
一、form 表單提交的的時候須要添加上{% csrf_token %}
<form action="/cref/" method="post"> {% csrf_token %} <div> 用戶名:<input type="text" name="username"> </div> <div> 密碼:<input type="text" name="password"> </div> <div> <input type="submit" value="提交"> </div> </form>
二、若是是ajax請求呢?那就須要在請求的時候,在header中添加這麼一行,headers:{'X-CSRFtoken':csrf_token},
<script> $(function () { $('#btn').click(function () { var csrf_token = $.cookie('csrftoken') $.ajax({ url:'/cref/', type:"POST", headers:{'X-CSRFtoken':csrf_token}, data : {'username':'admin','password':'123'}, success:function(){ } }) }) }) </script>
若是你的ajax不少,總是添加這麼一行,那豈不是很麻煩呢?那隻須要在開頭添加一個ajaxSetup便可
$(function () {
$.ajaxSetup({
beforeSend:function (xhr,settings) {
xhr.setRequestHeader('X-CSRFtoken',$.cookie('csrftoken'))
}
});
$('#btn').click(function () {
var csrf_token = $.cookie('csrftoken')
$.ajax({
url:'/cref/',
type:"POST",
//headers:{'X-CSRFtoken':csrf_token},
data : {'username':'admin','password':'123'},
success:function(){
}
})
})
})
另外想一個問題,若是有100個views,只有其中 兩個須要加這個需求,另外的都不加,再若是有兩個加,其餘的都不加呢?這裏就涉及到全局和局部使之生效的問題
全局:
中間件 django.middleware.csrfViewMiddleware
局部:
使用runserver可使咱們的django項目很便捷的在本地運行起來,但這隻能在局域網內訪問,若是在生產環境部署django,就要多考慮一些問題了。好比靜態文件處理,安全,效率等等,本篇文章總結概括了一下基於uwsgi+Nginx下django項目生產環境的部署
準備知識:
Django:一個基於python的開源web框架
uwsgi:一個基於自由uwagi協議、wsgi協議和http服務協議的web網關
nginx:經常使用的高性能代理服務器
wsgi.py : django項目攜帶的一個wsgi接口文件
項目流程
一、首先客戶端請求服務資源,
二、nginx做爲直接對外的服務接口,接收到客戶端發送過來的http請求,會解包、分析,
三、若是是靜態文件請求就根據nginx配置的靜態文件目錄,返回請求的資源,
四、若是是動態的請求,nginx就經過配置文件,將請求傳遞給uWSGI;uWSGI 將接收到的包進行處理,並轉發給wsgi,
五、wsgi根據請求調用django工程的某個文件或函數,處理完後django將返回值交給wsgi,
六、wsgi將返回值進行打包,轉發給uWSGI, uWSGI接收後轉發給nginx,nginx最終將返回值返回給客戶端(如瀏覽器)。 *
注:不一樣的組件之間傳遞信息涉及到數據格式和協議的轉換
軟件安裝:
1.yum -y install gcc openssl openssl-devel
2.install python3
./configure --prefix=/usr/local --with-ssl
make && make install
3. istall pip3
url:https://github.com/pypa/pip/archive/1.5.5.tar.gz
python3 setup.py install
/usr/local/python3/bin pip 安裝的命令都放到這個目錄下
4.pip3 install uwsgi
5. install nginx
tar 包安裝的ngin,須要本身添加快速啓動腳本到 /etc/init.d/下
#!/bin/sh # # nginx - this script starts and stops the nginx daemon # # chkconfig: - 85 15 # description: Nginx is an HTTP(S) server, HTTP(S) reverse \ # proxy and IMAP/POP3 proxy server # processname: nginx # config: /etc/nginx/nginx.conf # config: /etc/sysconfig/nginx # pidfile: /var/run/nginx.pid # Source function library. . /etc/rc.d/init.d/functions # Source networking configuration. . /etc/sysconfig/network # Check that networking is up. [ "$NETWORKING" = "no" ] && exit 0 nginx="/usr/local/nginx/sbin/nginx" prog=$(basename $nginx) NGINX_CONF_FILE="/usr/local/nginx/conf/nginx.conf" [ -f /etc/sysconfig/nginx ] && . /etc/sysconfig/nginx lockfile=/var/lock/subsys/nginx start() { [ -x $nginx ] || exit 5 [ -f $NGINX_CONF_FILE ] || exit 6 echo -n $"Starting $prog: " daemon $nginx -c $NGINX_CONF_FILE retval=$? echo [ $retval -eq 0 ] && touch $lockfile return $retval } stop() { echo -n $"Stopping $prog: " killproc $prog -QUIT retval=$? echo [ $retval -eq 0 ] && rm -f $lockfile return $retval killall -9 nginx } restart() { configtest || return $? stop sleep 1 start } reload() { configtest || return $? echo -n $"Reloading $prog: " killproc $nginx -HUP RETVAL=$? echo } force_reload() { restart } configtest() { $nginx -t -c $NGINX_CONF_FILE } rh_status() { status $prog } rh_status_q() { rh_status >/dev/null 2>&1 } case "$1" in start) rh_status_q && exit 0 $1 ;; stop) rh_status_q || exit 0 $1 ;; restart|configtest) $1 ;; reload) rh_status_q || exit 7 $1 ;; force-reload) force_reload ;; status) rh_status ;; condrestart|try-restart) rh_status_q || exit 0 ;; *) echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}" exit 2 esac
下面配置uwsgi.ini 文件
# hello_uwsgi.ini file [uwsgi] # Django-related settings socket = :9999 #這裏須要配置的socket,若是是http的話,會有錯誤 #http = :9999 # the base directory (full path) chdir = /home/right/cache_check # Django s wsgi file module = cache_check.wsgi # process-related settings # master master = true # maximum number of worker processes processes = 4 #logto = /var/log/uwsgi/%n.log daemonize = /var/log/uwsgi/dango_uwsgi.log # ... with appropriate permissions - may be needed # chmod-socket = 664 # clear environment on exit vacuum = true plugin = python #harakiri = 12
添加uwsgi快速啓動腳本
#!/bin/sh NAME="dango" if [ ! -n "$NAME" ];then echo "no arguments" exit; fi echo $NAME ID=`ps -ef | grep "$NAME" | grep -v "$0" | grep -v "grep" | awk '{print $2}'` echo $ID echo "################################################" for id in $ID do kill -9 $id echo "kill $id" done echo "################################################" uwsgi --ini /home/right/cache_check/dango_uwsgi.ini
添加nginx的配置
location / { include uwsgi_params; uwsgi_pass 127.0.0.1:9999; uwsgi_send_timeout 1600; # 指定鏈接到後端uWSGI的超時時間。 uwsgi_connect_timeout 1600; # 指定向uWSGI傳送請求的超時時間,完成握手後向uWSGI傳送請求的超時時間。 uwsgi_read_timeout 1600; # 指定接收uWSGI應答的超時時間,完成握手後接收uWSGI應答的超時時間。 #root html; #index index.html index.htm; #uwsgi_param SCRIPT_NAME; }
到這裏配置完畢,能夠運行了
能夠添加新書,並顯示
1 from django.db import models 2 3 # Create your models here. 4 5 class Publisher(models.Model): 6 name = models.CharField(max_length=30) 7 address = models.CharField(max_length=50) 8 city = models.CharField(max_length=60) 9 state_province = models.CharField(max_length=30) 10 country = models.CharField(max_length=50,null=True) 11 website = models.URLField() 12 def __unicode__(self): 13 return "<%s>"%(self.name) 14 15 class Author(models.Model): 16 first_name = models.CharField(max_length=30) 17 last_name = models.CharField(max_length=40) 18 email = models.EmailField() 19 def __unicode__(self): 20 return "<%s,%s>"%(self.first_name,self.last_name) 21 22 class Book(models.Model): 23 title = models.CharField(max_length=100) 24 authors = models.ManyToManyField(Author) 25 publisher = models.ForeignKey(Publisher) 26 publication_date = models.DateField() 27 def __unicode__(self): 28 return "<%s>"%(self.title)
#!/usr/bin/python #coding:utf-8 from django.shortcuts import render from django.http import HttpResponse from django.template import Context,loader from django.contrib.auth import authenticate,login,logout import models # Create your views here. def booklist(request): if request.method == 'POST': book_name = request.POST.get('name') publisher_id = request.POST.get('publisher_id') author_ids = request.POST.get('author_ids') print 'books`s name from post -->',request.POST.get('name') print 'publisher_id from post-->',request.POST.get('publisher_id') print 'author_ids from post-->',request.POST.get('author_ids') new_book = models.Book( title = book_name, publisher_id = publisher_id, publication_date = '2016-05-22' ) new_book.save() new_book.authors.add(*author_ids) #表中多對多,須要另外插入 books = models.Book.objects.all() publisherlist = models.Publisher.objects.all() authorlist = models.Author.objects.all() return render(request, 'books.html',{'books':books,'publisher':publisherlist,'authorlist':authorlist} )
1 <!DOCTYPE html> 2 <html lang="en" xmlns="http://www.w3.org/1999/html"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>booklist</title> 6 <style books_name></style> 7 <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" > 8 <style> 9 .book_form{margin-top:10px;} 10 </style> 11 </head> 12 <body> 13 <div class="container"> 14 </br> 15 <ul> 16 {% for book in books %} 17 <li>{{book.title}}</li> 18 19 {% endfor%} 20 </ul> 21 22 </br> 23 <form method='post' action='/dashboard/books/'> 24 <div class="col-xs-4"> 25 輸入書名<input type="text" class=" input-sm form-control" name='name' > 26 </div> 27 </br> 28 <div class="col-xs-2"> 29 <select class="input-sm form-control" name="publisher_id"> 30 <option >請選擇出版社</option> 31 {% for banshe in publisher%} 32 <option value='{{banshe.id}}'>{{banshe.name}}</option> 33 {% endfor%} 34 35 </select> 36 37 </div> 38 <div class="col-xs-4"> 39 <select multiple class="form-control" name='author_ids'> 40 {% for auth in authorlist%} 41 <option value='{{auth.id}}'>{{auth.first_name}}</option> 42 {% endfor %} 43 </select> 44 </div> 45 46 <input type="submit" value="建立新書"> 47 </form> 48 </div> 49 </body> 50 </html>
總結一
用戶登陸,前端用戶ajax請求登陸,後端驗證,翻過json給前端,前端經過狀態碼來判斷作什麼操做
涉及的內容:django login, authenticate, login_required , ajax請求, from表單
from django.http import HttpResponse, JsonResponse from django.http.response import JsonResponse from django.shortcuts import render, redirect from django.contrib.auth import authenticate, login from django.contrib.auth.decorators import login_required @login_required def index(request): return render(request, 'index.html') def mylogin(request): user_info = { 'dachengzi':{'pwd':'123'}, 'kangbazi':{'pwd':'123'} } if request.method == 'GET': print('I am here') return render(request, 'pages/examples/login.html') elif request.method == 'POST': print('I am post request!') username = request.POST.get('username') password = request.POST.get('password') print(username,password) res = authenticate(username=username, password=password) res_json = {} if res is not None: login(request,res) res_json['status'] = 0 else: res_json['status'] = 1 return JsonResponse(res_json)
<form action="#" > //防止from自動get請求,這裏填入# <div class="form-group has-feedback"> <input id="username" class="form-control" placeholder="Email"> <span class="glyphicon glyphicon-envelope form-control-feedback"></span> </div> <div class="form-group has-feedback"> <input id="password" type="password" class="form-control" placeholder="Password"> <span class="glyphicon glyphicon-lock form-control-feedback"></span> </div> <div class="row"> <div class="col-xs-8"> <div class="checkbox icheck"> <label> <input type="checkbox"> Remember Me </label> </div> </div> <!-- /.col --> <div class="col-xs-4"> <button id="submit" type="submit" class="btn btn-primary btn-block btn-flat">Sign In</button> </div> <!-- /.col --> </div> </form> <script> $('#submit').click(function () { username = $('#username').val() password = $('#password').val() $.ajax({ type:"POST", url:"/login/", data:{username:username, password:password}, dataTpye:"json", success:function (data1) { status = data1.status if(status ==0){ location.href='/' }else{ console.log('error') } } }) }) </script>