Python全栈开发之21django
Posted 1000-7
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python全栈开发之21django相关的知识,希望对你有一定的参考价值。
http://www.cnblogs.com/wupeiqi/articles/5237704.html
http://www.cnblogs.com/wupeiqi/articles/5246483.html
http://www.cnblogs.com/yuanchenqi/articles/5786089.html
基本配置
一 常用命令
django-admin startproject sitename
python manage.py runserver 0.0.0.0
python manage.py startapp appname
python manage.py syncdb
python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser
二、数据库配置(mysql)
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里面注册app
Django流程
一、MTV模式
MVC模式:所谓MVC就是把web应用分为模型(M),控制器(C),视图(V)三层;他们之间以一种插件似的,松耦合的方式连接在一起。模型负责业务对象与数据库的对象(ORM),视图负责与用户的交互(页面),控制器(C)接受用户的输入调用模型和视图完成用户的请求。
Django的MTV模式本质上与MVC模式没有什么差别,也是各组件之间为了保持松耦合关系,只是定义上有些许不同,Django的MTV分别代表:
Model(模型):负责业务对象与数据库的对象(ORM)
Template(模版):负责如何把页面展示给用户
View(视图):负责业务逻辑,并在适当的时候调用Model和Template
此外,Django还有一个url分发器,它的作用是将一个个URL的页面请求分发给不同的view处理,view再调用相应的Model和Template
路由系统
URL模式以及要为该URL模式调用的视图函数之间的映射表,每个路由对应一个view中的函数,对于这个URL调用这段代码,对于那个URL调用那段代码
参数说明:
- 一个正则表达式字符串
- 一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
- 可选的要传递给视图函数的默认参数(字典形式)
- 一个可选的name参数
传递的参数始终是字符串
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>
视图函数
1、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
2、HttpResponse对象:
对于HttpRequest对象来说,是由django自动创建的,但是,HttpResponse对象就必须我们自己创建。每个view请求处理方法必须返回一个HttpResponse对象。
HttpResponse类在django.http.HttpResponse
在HttpResponse对象上扩展的常用方法:页面渲染:render,render_to_response,
页面跳转:redirect
locals: 可以直接将函数中所有的变量传给模板
django的ORM
这里先创建几张表,分别是一对多和多对多,其中一对一就是一对多的时候外键唯一
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)
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 文件 更多字段
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\'), ) gender = models.CharField(max_length=2,choices = GENDER_CHOICE) 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 更多参数
# 获取个数 # # 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等于11、22、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" 双下画线操作
示例、用Q进行简单搜索
# 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
form验证
#!/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\'手机号码\'}))
cookie和session
一、cookie
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
二、session
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
三、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
局部:
- @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
- @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
二、普通表单
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 %}
三、ajax发送
<!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
django上传文件
一、普通上传文件
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>
二、form上传文件
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
django序列化
一、serializers
# 缺点外键字段不能很好显示 from django.core import serializers ret = models.BookType.objects.all() data = serializers.serialize("json", ret)
二、json
有些数据结构不支持,這里可以通过自定义处理器来做扩展
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)
django自定义分页
和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\'%}
三、使用filter
@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中间件
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里面的视图处理了
自己自定义的中间件类可以定义下面几种方法
- process_request(self,request)
- process_view(self, request, callback, callback_args, callback_kwargs)
- process_template_response(self,request,response)
- process_exception(self, request, exception)
- process_response(self, request, response)
自己定义的类在最新的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缓存
由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5分钟内再有人来访问时,则不再去执行view中的操作,而是直接从内存或者Redis中之前缓存的内容拿到,并返回。
Django中提供了6种缓存方式:
- 开发调试
- 内存
- 文件
- 数据库
- Memcache缓存(python-memcached模块)
- Memcache缓存(pylibmc模块)
一、配置
# 此为开始调试用,实际内部不做任何操作 # 配置: 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信号量
Django中提供了“信号调度”,用于在框架执行操作时解耦。通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者。
一、内置信号
Model signals pre_init # django的modal执行其构造方法前,自动触发 post_init # django的modal执行其构造方法后,自动触发以上是关于Python全栈开发之21django的主要内容,如果未能解决你的问题,请参考以下文章