http://www.cnblogs.com/wupeiqi/articles/5237704.htmljavascript
http://www.cnblogs.com/wupeiqi/articles/5246483.htmlhtml
http://www.cnblogs.com/yuanchenqi/articles/5786089.html前端
django-admin startproject sitenamejava
python manage.py runserver 0.0.0.0
python manage.py startapp appname
python manage.py syncdb
python manage.py makemigrations
python manage.py migratepython
python manage.py createsuperusermysql
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME':'dbname', 'USER': 'root', 'PASSWORD': 'xxx', 'HOST': '', 'PORT': '', } } # 因爲Django內部鏈接MySQL時使用的是MySQLdb模塊,而python3中還無此模塊,因此須要使用pymysql來代替 # 以下設置放置的與project同名的配置的 __init__.py文件中 import pymysql pymysql.install_as_MySQLdb()
TEMPLATE_DIRS = ( os.path.join(BASE_DIR,'templates'), )
'DIRS': [os.path.join(BASE_DIR, 'templates'), ],
STATICFILES_DIRS = ( os.path.join(BASE_DIR,'static'), ) # 特有的靜態文件夾放在app裏面, # 模板裏面使用靜態文件 <script src="/static/jquery-1.12.4.js"></script>
最後記得在setting裏面註冊appjquery
MVC模式:所謂MVC就是把web應用分爲模型(M),控制器(C),視圖(V)三層;他們之間以一種插件似的,鬆耦合的方式鏈接在一塊兒。模型負責業務對象與數據庫的對象(ORM),視圖負責與用戶的交互(頁面),控制器(C)接受用戶的輸入調用模型和視圖完成用戶的請求。git
Django的MTV模式本質上與MVC模式沒有什麼差異,也是各組件之間爲了保持鬆耦合關係,只是定義上有些許不一樣,Django的MTV分別表明:web
Model(模型):負責業務對象與數據庫的對象(ORM)ajax
Template(模版):負責如何把頁面展現給用戶
View(視圖):負責業務邏輯,並在適當的時候調用Model和Template
此外,Django還有一個url分發器,它的做用是將一個個URL的頁面請求分發給不一樣的view處理,view再調用相應的Model和Template
URL模式以及要爲該URL模式調用的視圖函數之間的映射表,每一個路由對應一個view中的函數,對於這個URL調用這段代碼,對於那個URL調用那段代碼
參數說明:
傳遞的參數始終是字符串
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/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive), # 路由分發 url(r'^contact/', include('django_website.contact.urls')), # 傳給視圖的默認參數,對應的視圖函數也必須加上同名的參數 url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}), #name參數 url(r'^index',views.index,name='bieming'), ]
常見寫法實例
urlpatterns = [ url(r'car', views.car, {'name': 'jaon'},), url(r'index', views.index, name='alias_login',), # url(r'index55555', views.index, name='alias_login',), ] def car(request, name): return HttpResponse('car'+name) def index(request,): if request.method == 'POST': username = request.POST.get('username') print(username) if username == 'jason': return HttpResponse('ok') else: return HttpResponse('error') return render(request, 'login.html') <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="{% url 'alias_login' %}" method="post"> <input type="text" name="username"> <input type="submit" value="提交"> </form> </body> </html>
一、HttpRequest對象的屬性:
# 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支持時該屬性纔可用。
HttpRequest對象的方法:get_full_path(), 好比:http://127.0.0.1:8000/index33/?name=123 ,req.get_full_path()獲得的結果就是/index33/?name=123
二、HttpResponse對象:
對於HttpRequest對象來講,是由django自動建立的,可是,HttpResponse對象就必須咱們本身建立。每一個view請求處理方法必須返回一個HttpResponse對象。
HttpResponse類在django.http.HttpResponse
在HttpResponse對象上擴展的經常使用方法:頁面渲染:render,render_to_response,
頁面跳轉:redirect
locals: 能夠直接將函數中全部的變量傳給模板
這裏先建立幾張表,分別是一對多和多對多,其中一對一就是一對多的時候外鍵惟一
from django.db import models # Create your models here. class UserType(models.Model): nid = models.AutoField(primary_key=True) caption = models.CharField(max_length=32) class UserInfo(models.Model): user = models.CharField(max_length=16) pwd = models.CharField(max_length=16) email = models.EmailField() userType = models.ForeignKey(UserType) class Group(models.Model): name = models.CharField(max_length=16) h2g = models.ManyToManyField('Host') class Host(models.Model): hostname = models.CharField(max_length=16) ip = models.CharField(max_length=16)
下面來看一下表的增刪改查的簡單操做
# 第一種方式建立 # usertype = models.UserType(caption='管理員') # usertype.save() # 第二種方式建立 # models.UserType.objects.create(caption='普通用戶') # 第三種 # userTypeDict = {'caption': '協管員'} # models.UserType.objects.create(**userTypeDict) # 帶外鍵添加數據庫 推薦使用 # userInfoDict = { # 'user': 'jason', # 'email': 'jason123@qq.com', # 'pwd': '123', # 'userType_id': 2, # } # userInfoDict = { # 'user': 'jason2', # 'email': 'jason26663@qq.com', # 'pwd': '123', # 'userType': models.UserType.objects.filter(nid=2).first(), # } # models.UserInfo.objects.create(**userInfoDict) # 刪除 # models.UserType.objects.filter(nid=3).delete() # 修改 # models.UserType.objects.filter(nid=1).update(caption='超級管理員') # 查詢 查詢結果是QuerySet # ret = models.UserType.objects.all() # select會獲取全部的映射 # print(type(ret), ret, ret.query) # ret 裏面保存的是對象 # ret = models.UserType.objects.all().values('nid') # 獲取指定映射 # print(type(ret), ret, ret.query) # ret 裏面保存的是字典 # ret = models.UserType.objects.all().values_list('nid') # 獲取指定映射 # print(type(ret), ret, ret.query) # ret 裏面保存的是元祖
再來看一下一對多連表查找操做
# 連表 雙下劃線使用,注意什麼狀況下使用 表名_set 什麼狀況下使用 表名__字段 # (表名_set 獲取QuerySet對象) (表名__字段,查找過濾映射的時候用) # 正向查找,再多的一方查找一的一方 # ret = models.UserInfo.objects.all().values('user', 'userType__caption') # print(ret) # ret = models.UserInfo.objects.filter(userType__caption="普通用戶").values('user', 'userType__caption') # print(ret) # 反向查找 在一的一方查找多的一方 # 在獲取了一對多中一那一方的對象以後,要獲取多的那一方對象使用反向表名_set # ret = models.UserType.objects.filter(caption='普通用戶').first() # print(ret.nid, ret.userinfo_set, ret.userinfo_set.all(), ret.userinfo_set.all()[0].user) # 直接在一對多一那一方使用查找或者過濾映射的時候使用反向表名__字段 # ret = models.UserType.objects.all().values('caption', 'userinfo__user') # print(ret)
最後看一下多對多連表查找操做
''' 建立表: 直接使用m2m 自已定義第三張表 自已定義第三張表 + m2m(through) 能夠經過through參數來指明存在的表 直接使用m2m --- 獲取值 add添加 remove刪除(關係表),filter.delete()(關係表+..) set設置(添加、刪除) get_or_create update_or_create 自已定義第三張表 + m2m + through --關係表只能獲取值 filter,all... 經過第三張表進行操做 ''' ''' # 直接使用 class Host(models.Model): hid = models.AutoField(primary_key=True) hostname = models.CharField(max_length=32) ip = models.CharField(max_length=32) # h2g = models.ManyToManyField('Group') class Group(models.Model): gid = models.AutoField(primary_key=True) name = models.CharField(max_length=16) h2g = models.ManyToManyField('Host') # 自定義第三張表 # class Host(models.Model): # hid = models.AutoField(primary_key=True) # hostname = models.CharField(max_length=32) # ip = models.CharField(max_length=32) # # h2g = models.ManyToManyField('Group', through='HostToGroup') # class Group(models.Model): # gid = models.AutoField(primary_key=True) # name = models.CharField(max_length=16) # # h2g = models.ManyToManyField('Host') # # class HostToGroup(models.Model): # hgid = models.AutoField(primary_key=True) # host_id = models.ForeignKey('Host') # group_id = models.ForeignKey('Group') # status = models.IntegerField() # class Meta: # # index_together = ("host_id",'goup_id') 組合索引 # unique_together = [ # ('host_id', 'group_id'), 組合惟一索引 # ] '''
# 將多臺機器分給一組 正向 # obj = models.Group.objects.get(id=1) # hosts = models.Host.objects.filter(id__gt=2) # obj.h2g.add(*hosts) # host = models.Host.objects.get(id=2) # obj.h2g.add(host) # 給多個組分一臺機器 反向 # h = models.Host.objects.get(id=1) # h.group_set.add(*models.Group.objects.filter(id__gt=2)) # h.group_set.add(2) # 能夠直接添加id或對象 # h.group_set.remove(*models.Group.objects.filter(id__gt=3)) # 只刪除關係表 # h.group_set.filter(id__gt=2).delete() # group_id>2 的關係表刪除了,相應的group表數據也被刪除了 # h.group_set.set(models.Group.objects.filter(id__gt=1), clear=True) #大於1的所有清除在添加 # h.group_set.set(models.Group.objects.filter(id__gt=2)) # 大於2 之前存在的不清除,不存在的添加 # h.group_set.set(models.Group.objects.filter(id__gt=4)) # 小於5的被清除 # r = h.group_set.update_or_create(name='人事部') # 兩張表都不存在,先在group表建立在添加到關係表中去 # print(r) # r = h.group_set.update_or_create(name='pm') # 和上面的效果同樣,爲何 # h.group_set.get_or_create(name='te') # 和上面的效果同樣 具體操做
補充:
一次插入多條數據
author_list = [] for i in range(7): name = 'alex' + str(i) age = i author = models.Author(name=name, age=age) author_list.append(author) models.Author.objects.bulk_create(author_list)
一、models.AutoField 自增列 = int(11) 若是沒有的話,默認會生成一個名稱爲 id 的列,若是要顯示的自定義一個自增列,必須將給列設置爲主鍵 primary_key=True。 二、models.CharField 字符串字段 必須 max_length 參數 三、models.BooleanField 布爾類型=tinyint(1) 不能爲空,Blank=True 四、models.ComaSeparatedIntegerField 用逗號分割的數字=varchar 繼承CharField,因此必須 max_lenght 參數 五、models.DateField 日期類型 date 對於參數,auto_now = True 則每次更新都會更新這個時間;auto_now_add 則只是第一次建立添加,以後的更新再也不改變。 六、models.DateTimeField 日期類型 datetime 同DateField的參數 七、models.Decimal 十進制小數類型 = decimal 必須指定整數位max_digits和小數位decimal_places 八、models.EmailField 字符串類型(正則表達式郵箱) =varchar 對字符串進行正則表達式 九、models.FloatField 浮點類型 = double 十、models.IntegerField 整形 十一、models.BigIntegerField 長整形 integer_field_ranges = { 'SmallIntegerField': (-32768, 32767), 'IntegerField': (-2147483648, 2147483647), 'BigIntegerField': (-9223372036854775808, 9223372036854775807), 'PositiveSmallIntegerField': (0, 32767), 'PositiveIntegerField': (0, 2147483647), } 十二、models.IPAddressField 字符串類型(ip4正則表達式) 1三、models.GenericIPAddressField 字符串類型(ip4和ip6是可選的) 參數protocol能夠是:both、ipv四、ipv6 驗證時,會根據設置報錯 1四、models.NullBooleanField 容許爲空的布爾類型 1五、models.PositiveIntegerFiel 正Integer 1六、models.PositiveSmallIntegerField 正smallInteger 1七、models.SlugField 減號、下劃線、字母、數字 1八、models.SmallIntegerField 數字 數據庫中的字段有:tinyint、smallint、int、bigint 1九、models.TextField 字符串=longtext 20、models.TimeField 時間 HH:MM[:ss[.uuuuuu]] 2一、models.URLField 字符串,地址正則表達式 2二、models.BinaryField 二進制 2三、models.ImageField 圖片 2四、models.FilePathField 文件 更多字段
一、null=True 數據庫中字段是否能夠爲空 二、blank=True django的 Admin 中添加數據時是否可容許空值 三、primary_key = False 主鍵,對AutoField設置主鍵後,就會代替原來的自增 id 列 四、auto_now 和 auto_now_add auto_now 自動建立---不管添加或修改,都是當前操做的時間 auto_now_add 自動建立---永遠是建立時的時間 五、choices GENDER_CHOICE = ( (u'M', u'Male'), (u'F', u'Female'), ) gender = models.CharField(max_length=2,choices = GENDER_CHOICE) 六、max_length 七、default 默認值 八、verbose_name Admin中字段的顯示名稱 九、name|db_column 數據庫中的字段名稱 十、unique=True 不容許重複 十一、db_index = True 數據庫索引 十二、editable=True 在Admin裏是否可編輯 1三、error_messages=None 錯誤提示 1四、auto_created=False 自動建立 1五、help_text 在Admin中提示幫助信息 1六、validators=[] 1七、upload-to 更多參數
# 獲取個數 # # models.Tb1.objects.filter(name='seven').count() # 大於,小於 # # models.Tb1.objects.filter(id__gt=1) # 獲取id大於1的值 # models.Tb1.objects.filter(id__lt=10) # 獲取id小於10的值 # models.Tb1.objects.filter(id__lt=10, id__gt=1) # 獲取id大於1 且 小於10的值 # in # # models.Tb1.objects.filter(id__in=[11, 22, 33]) # 獲取id等於十一、2二、33的數據 # models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in # contains # # models.Tb1.objects.filter(name__contains="ven") # models.Tb1.objects.filter(name__icontains="ven") # icontains大小寫不敏感 # models.Tb1.objects.exclude(name__icontains="ven") # range # # models.Tb1.objects.filter(id__range=[1, 2]) # 範圍bettwen and # 其餘相似 # # startswith,istartswith, endswith, iendswith, # order by # # models.Tb1.objects.filter(name='seven').order_by('id') # asc # models.Tb1.objects.filter(name='seven').order_by('-id') # desc # limit 、offset # # models.Tb1.objects.all()[10:20] # group by from django.db.models import Count, Min, Max, Sum # models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num')) # SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id" 雙下畫線操做
# F 使用查詢條件的值 # # from django.db.models import F # models.Tb1.objects.update(num=F('num')+1) # Q 構建搜索條件 from django.db.models import Q # con = Q() # # q1 = Q() # q1.connector = 'OR' # q1.children.append(('id', 1)) # q1.children.append(('id', 10)) # q1.children.append(('id', 9)) # # q2 = Q() # q2.connector = 'OR' # q2.children.append(('c1', 1)) # q2.children.append(('c1', 10)) # q2.children.append(('c1', 9)) # # con.add(q1, 'AND') # con.add(q2, 'AND') # # models.Tb1.objects.filter(con) # # from django.db import connection # cursor = connection.cursor() # cursor.execute("""SELECT * from tb where name = %s""", ['Lennon']) # row = cursor.fetchone() F和Q
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .left{ float: left; } .clearfix:after{ content: '.'; clear: both; display: block; visibility: hidden; height: 0; } </style> </head> <body> <div class="condition"> <div class="item clearfix"> <div class="icon left" onclick="AddCondition(this);">+</div> <div class="left"> <select onchange="ChangeName(this);"> <option value="name">書名</option> <option value="book_type__caption">圖書類型</option> <option value="price">價格</option> <option value="pages">頁數</option> </select> </div> <div class="left"><input type="text" name="name" /></div> </div> </div> <div> <input type="button" onclick="Search();" value="搜索" /> </div> <div class="container"> </div> <script src="/static/jquery-1.12.4.js"></script> <script> function AddCondition(ths) { var new_tag = $(ths).parent().clone(); new_tag.find('.icon').text('-'); new_tag.find('.icon').attr('onclick', 'RemoveCondition(this);'); $(ths).parent().parent().append(new_tag); } function RemoveCondition(ths) { $(ths).parent().remove(); } function ChangeName(ths) { var v = $(ths).val(); $(ths).parent().next().find('input').attr('name',v); } function Search() { var post_data_dict = {}; // 獲取全部input的內容,提交數據 $('.condition input').each(function () { // console.log($(this)[0]) var n = $(this).attr('name'); var v = $(this).val(); var v_list = v.split(','); post_data_dict[n] = v_list; }); console.log(post_data_dict); var post_data_str = JSON.stringify(post_data_dict); $.ajax({ url: '/index/', type: 'POST', data: { 'post_data': post_data_str}, dataType: 'json', success: function (arg) { // 字符串 "<table>" + if(arg.status){ var table = document.createElement('table'); table.setAttribute('border',1); // [{,name,pubdate,price,caption},] $.each(arg.data, function(k,v){ var tr = document.createElement('tr'); var td1 = document.createElement('td'); td1.innerText = v['name']; var td2 = document.createElement('td'); td2.innerText = v['price']; var td3 = document.createElement('td'); td3.innerText = v['book_type__caption']; var td4 = document.createElement('td'); td4.innerText = v['pubdate']; tr.appendChild(td1); tr.appendChild(td2); tr.appendChild(td3); tr.appendChild(td4); table.appendChild(tr); }); $('.container').empty(); $('.container').append(table); }else{ alert(arg.message); } } }) } </script> </body> </html> 前端index
from django.db import models # Create your models here. class Author(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() class BookType(models.Model): caption = models.CharField(max_length=32) class Book(models.Model): name = models.CharField(max_length=64) price = models.DecimalField(max_digits=10, decimal_places=2) pubdate = models.DateField() authors = models.ManyToManyField(Author) book_type = models.ForeignKey(BookType) 後端models
from django.shortcuts import render,HttpResponse from app01 import models # Create your views here. import json def test(request): # models.BookType.objects.create(caption='技術') # models.BookType.objects.create(caption='文學') # models.BookType.objects.create(caption='動漫') # models.BookType.objects.create(caption='男人裝') # models.Book.objects.create(name='文藝復興',pages='100',price='40',pubdate='1992-11-2',book_type_id='1') # models.Book.objects.create(name='解密',pages='80',price='10', pubdate='2016-6-10',book_type_id='2') # models.Book.objects.create(name='刀鋒',pages='50',price='3', pubdate='2014-02-16',book_type_id='2') # models.Book.objects.create(name='查令十字路84號',pages='260',price='40',pubdate='1999-10-12',book_type_id='3') # models.Book.objects.create(name='紅樓',pages='1000',price='500', pubdate='1760-1-1',book_type_id='3') # models.Book.objects.create(name='將夜',pages='2000',price='300', pubdate='2010-3-3',book_type_id='1') # models.Book.objects.create(name='mysql從刪庫到跑路',pages='20',price='10',pubdate='1998-9-2',book_type_id='4') # models.Book.objects.create(name='馬克思主義',pages='50',price='100',pubdate='1937-3-3',book_type_id='2') return HttpResponse('ok') import json from datetime import date from datetime import datetime from decimal import Decimal class JsonCustomEncoder(json.JSONEncoder): def default(self, field): if isinstance(field, datetime): return field.strftime('%Y-%m-%d %H:%M:%S') elif isinstance(field, date): return field.strftime('%Y-%m-%d') elif isinstance(field, Decimal): return str(field) else: return json.JSONEncoder.default(self, field) def index(request): if request.method == 'POST': ret = {'status': False, 'message': '', 'data':None} try: post_data = request.POST.get('post_data',None) post_data_dict = json.loads(post_data) print(post_data_dict) # {'name': ['11', 'sdf'],'price': ['11', 'sdf']} # 構造搜索條件 from django.db.models import Q con = Q() for k,v in post_data_dict.items(): q = Q() q.connector = 'OR' for item in v: q.children.append((k, item)) con.add(q, 'AND') """ ret = models.Book.objects.filter(con) print(ret) # queryset,[對象] from django.core import serializers data = serializers.serialize("json", ret) # 這種方法獲取到的圖書類型是id不是book_type__caption print(type(data),data) # 字符串 """ """ #ret = models.Book.objects.filter(con).values('name','book_type__caption') ret = models.Book.objects.filter(con).values_list('name', 'book_type__caption') print(ret,type(ret)) li = list(ret) data = json.dumps(li) print(data,type(data)) """ result = models.Book.objects.filter(con).values('name','price','pubdate','book_type__caption') # ret = models.Book.objects.filter(con).values_list('name', 'book_type__caption') li = list(result) ret['status'] = True ret['data'] = li except Exception as e: ret['message'] = str(e) ret_str = json.dumps(ret, cls=JsonCustomEncoder) return HttpResponse(ret_str) return render(request, 'index.html') 後端view
#!/usr/bin/env python # coding=utf-8 from django import forms class Forml(forms.Form): # username = forms.CharField() # pwd = forms.CharField() user = forms.CharField( widget=forms.TextInput(attrs={ 'class': 'c1', }), error_messages={ 'required': '用戶名不能爲空', }, ) pwd = forms.CharField(max_length=4, min_length=2) # email = forms.EmailField( # error_messages={ # 'required': '郵箱不能爲空', # 'invalid': '郵箱格式錯誤', # } # ) email = forms.EmailField( error_messages={ 'required': '郵箱不能爲空', 'invalid': '郵箱格式錯誤' } ) memo = forms.CharField( widget=forms.Textarea() ) # 自定義 user_type_choice = ( (0, '普通用戶'), (1, '高級用戶'), ) # 若是從數據庫查找,則Forml裏面定義的靜態字段只會執行一次 # 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"}, ) ) # 數據庫動態的 # 若是從數據庫查找,則Forml裏面定義的靜態字段只會執行一次,因此須要下面動態的 # def __init__(self, *args, **kwargs): # super(Forml, 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"}, # ) # ) forms
#!/usr/bin/env python # coding=utf-8 from django.shortcuts import render from django.http import HttpResponse from form1.forms import Forml def form1(req): f = Forml() if req.method == 'POST': f = Forml(req.POST) if f.is_valid(): print(f.cleaned_data) else: # print(f.errors.get('user',None)) # print(f.errors['pwd'][0]) # print(type(f.errors),f.errors) # from django.forms.utils import ErrorDict print(type(f.errors), f.errors) return render(req, 'account/form1.html', {'error': f.errors, 'form': f}) return render(req, 'account/form1.html', {'form': f}) Views
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> span{ background-color: darkolivegreen; } </style> </head> <body> <form action="/form1/" method="POST"> <div> <!--<input type="text" name="username">--> {{form.user}} {% if error.user %} <span>{{error.user.0}}</span> {% endif %} </div> <div> {{form.pwd}} <!--<input type="text" name="password">--> {% if error.pwd %} <span>{{error.pwd.0}}</span> {% endif %} </div> <div> {{form.email}} {% if error.email %} <span>{{error.email.0}}</span> {% endif %} </div> <div> {{form.memo}} {% if error.memo %} <span>{{error.memo.0}}</span> {% endif %} </div> <div> {{form.book_type}} {% if error.book_type %} <span>{{error.book_type.0}}</span> {% endif %} </div> <button type="submit">提交</button> <!--<input type="submit" value="提交"/>--> </form> </body> </html> 前端index
除此以外還支持自定義字段,具體用法看下面的使用
import re from django import forms from django.core.exceptions import ValidationError def mobile_validate(value): mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$') if not mobile_re.match(value): raise ValidationError('手機號碼格式錯誤') class PublishForm(forms.Form): # 這裏手機號使用了本身自定義的驗證規則 phone = forms.CharField(validators=[mobile_validate, ], error_messages={'required': u'手機不能爲空'}, widget=forms.TextInput(attrs={'class': "form-control", 'placeholder': u'手機號碼'}))
1 request.COOKIES['key'] 2 request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None) 3 參數: 4 default: 默認值 5 salt: 加密鹽 6 max_age: 後臺控制過時時間 rep = HttpResponse(...) 或 rep = render(request, ...) rep.set_cookie(key,value,...) rep.set_signed_cookie(key,value,salt='加密鹽',...) 參數: 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獲取(不是絕對,底層抓包能夠獲取到也能夠被覆蓋) 設置cookie
a. 配置 settings.py 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,默認修改以後才保存(默認) b. 使用 def index(request): # 獲取、設置、刪除Session中數據 request.session['k1'] request.session.get('k1',None) request.session['k1'] = 123 request.session.setdefault('k1',123) # 存在則不設置 del request.session['k1'] # 全部 鍵、值、鍵值對 request.session.keys() request.session.values() request.session.items() request.session.iterkeys() request.session.itervalues() request.session.iteritems() # 用戶session的隨機字符串 request.session.session_key # 將全部Session失效日期小於當前日期的數據刪除 request.session.clear_expired() # 檢查 用戶session的隨機字符串 在數據庫中是否 request.session.exists("session_key") # 刪除當前用戶的全部Session數據 request.session.delete("session_key") ... 數據庫session
a. 配置 settings.py SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎 SESSION_CACHE_ALIAS = 'default' # 使用的緩存別名(默認內存緩存,也能夠是memcache),此處別名依賴緩存的設置 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,默認修改以後才保存 b. 使用 同上 緩存session a. 配置 settings.py SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎 SESSION_FILE_PATH = None # 緩存文件路徑,若是爲None,則使用tempfile模塊獲取一個臨時地址tempfile.gettempdir() # 如:/var/folders/d3/j9tj0gz93dg06bmwxmhh6_xm0000gn/T 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,默認修改以後才保存 b. 使用 同上 文件session 數據庫用於作持久化,緩存用於提升效率 a. 配置 settings.py SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎 b. 使用 同上 緩存+數據庫session a. 配置 settings.py SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎 b. 使用 同上 備註:保存在客戶端 加密session
def login_auth(func): def wrapper(req, *args, **kwargs): if not req.session.get('is_login', None): return redirect('/admin/login') return func(req, *args, **kwargs) return wrapper
django爲用戶實現防止跨站請求僞造的功能,經過中間件 django.middleware.csrf.CsrfViewMiddleware 來完成。而對於django中設置防跨站請求僞造功能有分爲全局和局部。
全局:
中間件 django.middleware.csrf.CsrfViewMiddleware
局部:
veiw中設置返回值: return render_to_response('Account/Login.html',data,context_instance=RequestContext(request)) 或者 return render(request, 'xxx.html', data) #這裏也能夠看出render 和 render_to_respone 的區別 html中設置Token: {% csrf_token %}
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> {% csrf_token %} <input type="button" onclick="Do();" value="Do it"/> <script src="/static/plugin/jquery/jquery-1.8.0.js"></script> <script src="/static/plugin/jquery/jquery.cookie.js"></script> <script type="text/javascript"> var csrftoken = $.cookie('csrftoken'); function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ beforeSend: function(xhr, settings) { if (!csrfSafeMethod(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } }); function Do(){ $.ajax({ url:"/app01/test/", data:{id:1}, type:'POST', success:function(data){ console.log(data); } }); } </script> </body> </html> 前端html
from django.template.context import RequestContext # Create your views here. def test(request): if request.method == 'POST': print request.POST return HttpResponse('ok') return render_to_response('app01/test.html',context_instance=RequestContext(request)) # https://docs.djangoproject.com/en/dev/ref/csrf/#ajax Views
def upload_file(request): if request.method == "POST": obj = request.FILES.get('fafafa') f = open(obj.name, 'wb') for chunk in obj.chunks(): f.write(chunk) f.close() return render(request, 'file.html') <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/upload_file/" enctype="multipart/form-data" method="POST"> {% csrf_token %} <input type="file" name="fafafa" /> <input type="submit" value="提交" /> </form> </body> </html>
class FileForm(forms.Form): ExcelFile = forms.FileField() from django.db import models class UploadFile(models.Model): userid = models.CharField(max_length = 30) file = models.FileField(upload_to = './upload/') date = models.DateTimeField(auto_now_add=True) def UploadFile(request): uf = AssetForm.FileForm(request.POST,request.FILES) if uf.is_valid(): upload = models.UploadFile() upload.userid = 1 upload.file = uf.cleaned_data['ExcelFile'] upload.save() print upload.file
# 缺點外鍵字段不能很好顯示 from django.core import serializers ret = models.BookType.objects.all() data = serializers.serialize("json", ret)
有些數據結構不支持,這裏能夠經過自定義處理器來作擴展
import json from datetime import date from datetime import datetime class JsonCustomEncoder(json.JSONEncoder): def default(self, field): if isinstance(field, datetime): return field.strftime('%Y-%m-%d %H:%M:%S') elif isinstance(field, date): return field.strftime('%Y-%m-%d') elif isinstance(field, Decimal): return str(field) else: return json.JSONEncoder.default(self, field) ret_str = json.dumps(ret, cls=JsonCustomEncoder)
和tornado同樣,只需修改一個地方
#!/usr/bin/env python # -*- coding:utf-8 -*- from django.utils.safestring import mark_safe class Pagination: def __init__(self, current_page, all_item): try: page = int(current_page) except: page = 1 if page < 1: page = 1 all_pager, c = divmod(all_item, 5) if c > 0: all_pager += 1 self.current_page = page self.all_pager = all_pager @property def start(self): return (self.current_page - 1) * 5 @property def end(self): return self.current_page * 5 def string_pager(self, base_url="/admin/manage/"): list_page = [] if self.all_pager < 11: s = 1 t = self.all_pager + 1 else: # 總頁數大於11 if self.current_page < 6: s = 1 t = 12 else: if (self.current_page + 5) < self.all_pager: s = self.current_page - 5 t = self.current_page + 5 + 1 else: s = self.all_pager - 11 t = self.all_pager + 1 # 首頁 # first = '<a href="%s1">首頁</a>' % base_url # list_page.append(first) # 上一頁 # 當前頁 page if self.current_page == 1: prev = '<a href="javascript:void(0);">上一頁</a>' else: prev = '<a href="%s%s">上一頁</a>' % (base_url, self.current_page - 1,) list_page.append(prev) for p in range(s, t): # 1-11 if p == self.current_page: temp = '<a class="active" href="%s%s">%s</a>' % (base_url, p, p) else: temp = '<a href="%s%s">%s</a>' % (base_url, p, p) list_page.append(temp) if self.current_page == self.all_pager: nex = '<a href="javascript:void(0);">下一頁</a>' else: nex = '<a href="%s%s">下一頁</a>' % (base_url, self.current_page + 1,) list_page.append(nex) # 尾頁 # last = '<a href="%s%s">尾頁</a>' % (base_url, self.all_pager,) # list_page.append(last) # 跳轉 # jump = """<input type='text' /><a onclick="Jump('%s',this);">GO</a>""" % ('/index/', ) # script = """<script> # function Jump(baseUrl,ths){ # var val = ths.previousElementSibling.value; # if(val.trim().length>0){ # location.href = baseUrl + val; # } # } # </script>""" # list_page.append(jump) # list_page.append(script) str_page = "".join(list_page) return mark_safe(str_page)
{{ item }} {% for item in item_list %} <a>{{ item }}</a> {% endfor %} forloop.counter forloop.first forloop.last {% if ordered_warranty %} {% else %} {% endif %} 母板:{% block title %}{% endblock %} 子板:{% extends "base.html" %} {% block title %}{% endblock %} 幫助方法: {{ item.event_start|date:"Y-m-d H:i:s"}} {{ bio|truncatewords:"30" }} {{ my_list|first|upper }} {{ name|lower }} 基本使用
from django import template from django.utils.safestring import mark_safe from django.template.base import resolve_variable, Node, TemplateSyntaxError register = template.Library() @register.simple_tag def my_simple_time(v1,v2,v3): return v1 + v2 + v3 @register.simple_tag def my_input(id,arg): result = "<input type='text' id='%s' class='%s' />" %(id,arg,) return mark_safe(result) 建立任意 .py 文件,如:xx.py
在使用自定義simple_tag的html文件中導入以前建立的 xx.py 文件名
{% load xx %}
使用simple_tag
{% my_simple_time 1 2 3%} {% my_input 'id_username' 'hide'%}
@register.filter def detail(value, arg): # 只能接受兩個參數 allcount, remainder = arg.split(',') allcount = int(allcount) remainder = int(remainder) if value % allcount == remainder: return True return False <div> {% for item in detail_list %} {% if forloop.counter|detail1:"4,0" %} <div> <p>{{ item.student__name }}</p> </div> {% endif %} {% endfor %} </div>
django 中的中間件(middleware),在django中,中間件其實就是一個類,在請求到來和結束後,django會根據本身的規則在合適的時機執行中間件中相應的方法。在django項目的settings模塊中,有一個 MIDDLEWARE_CLASSES 變量,其中每個元素就是一箇中間件,穿過中間件的順序就是下面列表的註冊順序
MIDDLEWARE = [ 'middleware_test_1.middleware1.testMiddleware', 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
下面看一下流程圖
正常流程,request->view-> url->views ->response
若是request裏面直接返回了, 或者出現其餘問題,直接到最裏面的response,不走django裏面的視圖處理了
本身自定義的中間件類能夠定義下面幾種方法
本身定義的類在最新的django裏面須要繼承MiddlewareMixin
from django.utils.deprecation import MiddlewareMixin class testMiddleware(MiddlewareMixin): def process_request(self, request): print(11) def process_response(self, request, response): print(22) return response 建立中間件
MIDDLEWARE = [ 'middleware_test_1.middleware1.testMiddleware', 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] 註冊中間件
因爲Django是動態網站,全部每次請求均會去數據進行相應的操做,當程序訪問量大時,耗時必然會更加明顯,最簡單解決方式是使用:緩存,緩存將一個某個views的返回值保存至內存或者memcache中,5分鐘內再有人來訪問時,則再也不去執行view中的操做,而是直接從內存或者Redis中以前緩存的內容拿到,並返回。
Django中提供了6種緩存方式:
# 此爲開始調試用,實際內部不作任何操做 # 配置: CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', # 引擎 'TIMEOUT': 300, # 緩存超時時間(默認300,None表示永不過時,0表示當即過時) 'OPTIONS':{ 'MAX_ENTRIES': 300, # 最大緩存個數(默認300) 'CULL_FREQUENCY': 3, # 緩存到達最大個數以後,剔除緩存個數的比例,即:1/CULL_FREQUENCY(默認3) }, 'KEY_PREFIX': '', # 緩存key的前綴(默認空) 'VERSION': 1, # 緩存key的版本(默認1) 'KEY_FUNCTION' : default_key_func # 生成key的函數(默認函數會生成爲:【前綴:版本:key】) } } # 自定義key def default_key_func(key, key_prefix, version): """ Default function to generate keys. Constructs the key used by all other methods. By default it prepends the `key_prefix'. KEY_FUNCTION can be used to specify an alternate function with custom key making behavior. """ return '%s:%s:%s' % (key_prefix, version, key) def get_key_func(key_func): """ Function to decide which key function to use. Defaults to ``default_key_func``. """ if key_func is not None: if callable(key_func): return key_func else: return import_string(key_func) return default_key_func
# 此緩存將內容保存至內存的變量中 # 配置: CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 'LOCATION': 'unique-snowflake', } } # 注:其餘配置同開發調試版本 內存 # 此緩存將內容保存至文件 # 配置: CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 'LOCATION': 'filetopath', } } # 注:其餘配置同開發調試版本 文件 # 此緩存將內容保存至數據庫 # 配置: CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.db.DatabaseCache', 'LOCATION': 'my_cache_table', # 數據庫表 } } # 注:執行建立表命令 python manage.py createcachetable 數據庫 # 此緩存使用python-memcached模塊鏈接memcache CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': '127.0.0.1:11211', } } CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': 'unix:/tmp/memcached.sock', } } CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': [ '172.19.26.240:11211', '172.19.26.242:11211', ] } } Memcache緩存(python-memcached模塊) # 此緩存使用pylibmc模塊鏈接memcache CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache', 'LOCATION': '127.0.0.1:11211', } } CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache', 'LOCATION': '/tmp/memcached.sock', } } CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache', 'LOCATION': [ '172.19.26.240:11211', '172.19.26.242:11211', ] } } Memcache緩存(pylibmc模塊)
使用中間件,通過一系列的認證等操做,若是內容在緩存中存在,則使用FetchFromCacheMiddleware獲取內容並返回給用戶,當返回給用戶以前,判斷緩存中是否已經存在,若是不存在則UpdateCacheMiddleware會將緩存保存至緩存,從而實現全站緩存 MIDDLEWARE = [ 'django.middleware.cache.UpdateCacheMiddleware', # 其餘中間件... 'django.middleware.cache.FetchFromCacheMiddleware', ] CACHE_MIDDLEWARE_ALIAS = "" CACHE_MIDDLEWARE_SECONDS = "" CACHE_MIDDLEWARE_KEY_PREFIX = "" 全站使用
方式一: from django.views.decorators.cache import cache_page @cache_page(60 * 15) def my_view(request): ... 方式二: from django.views.decorators.cache import cache_page urlpatterns = [ url(r'^foo/([0-9]{1,2})/$', cache_page(60 * 15)(my_view)), ] 單獨視圖緩存
a. 引入TemplateTag {% load cache %} b. 使用緩存 {% cache 5000 緩存key %} 緩存內容 {% endcache %} 局部視圖使用
Django中提供了「信號調度」,用於在框架執行操做時解耦。通俗來說,就是一些動做發生的時候,信號容許特定的發送者去提醒一些接受者。
Model signals pre_init # django的modal執行其構造方法前,自動觸發 post_init # django的modal執行其構造方法後,自動觸發 pre_save # django的modal對象保存前,自動觸發 post_save # django的modal對象保存後,自動觸發 pre_delete # django的modal對象刪除前,自動觸發 post_delete # django的modal對象刪除後,自動觸發 m2m_changed # django的modal中使用m2m字段操做第三張表(add,remove,clear)先後,自動觸發 class_prepared # 程序啓動時,檢測已註冊的app中modal類,對於每個類,自動觸發 Management signals pre_migrate # 執行migrate命令前,自動觸發 post_migrate # 執行migrate命令後,自動觸發 Request/response signals request_started # 請求到來前,自動觸發 request_finished # 請求結束後,自動觸發 got_request_exception # 請求異常後,自動觸發 Test signals setting_changed # 使用test測試修改配置文件時,自動觸發 template_rendered # 使用test測試渲染模板時,自動觸發 Database Wrappers connection_created # 建立數據庫鏈接時,自動觸發
from django.core.signals import request_finished from django.core.signals import request_started from django.core.signals import got_request_exception from django.db.models.signals import class_prepared from django.db.models.signals import pre_init, post_init from django.db.models.signals import pre_save, post_save from django.db.models.signals import pre_delete, post_delete from django.db.models.signals import m2m_changed from django.db.models.signals import pre_migrate, post_migrate from django.test.signals import setting_changed from django.test.signals import template_rendered from django.db.backends.signals import connection_created def callback(sender, **kwargs): print("xxoo_callback") print(sender,kwargs) xxoo.connect(callback) # xxoo指上述導入的內容
3、自定義信號
a. 定義信號 import django.dispatch pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"]) b. 註冊信號 def callback(sender, **kwargs): print("callback") print(sender,kwargs) pizza_done.connect(callback) c. 觸發信號 from 路徑 import pizza_done pizza_done.send(sender='seven',toppings=123, size=456)