本章简介:
- Django 简介
- Django 基本配置
- Django url
- Django view
- Django 模板语言
- Django Form
- Django Cookie
- Django Session
- Django CSRF
Django 简介
Django是一个开放源代码的Web应用框架,由Python写成。采用了MVC的软件设计模式,即模型M,视图V和控制器C。它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的。并于2005年7月在BSD许可证下发布。这套框架是以比利时的吉普赛爵士吉他手Django Reinhardt来命名的。
Django的主要目标是使得开发复杂的、数据库驱动的网站变得简单。Django注重组件的重用性和“可插拔性”,敏捷开发和DRY法则(Don‘t Repeat Yourself)。在Django中Python被普遍使用,甚至包括配置文件和数据模型。
优点:
- 完美的文档,Django的成功,我觉得很大一部分原因要归功于Django近乎完美的官方文档(包括Djangobook)。
- 全套的解决方案,Django象Rails一样,提供全套的解决方案(full-stackframework + batteries included),基本要什么有什么(比如:cache、session、feed、orm、geo、auth),而且全部Django自己造,开发网站应手的工具Django基本都给你做好了,因此开发效率是不用说的,出了问题也算好找,不在你的代码里就在Django的源码里。
- 强大的URL路由配置,Django让你可以设计出非常优雅的URL,在Django里你基本可以跟丑陋的GET参数说拜拜。
- 自助管理后台,admin interface是Django里比较吸引眼球的一项contrib,让你几乎不用写一行代码就拥有一个完整的后台管理界面。
缺点:
- 系统紧耦合,如果你觉得Django内置的某项功能不是很好,想用喜欢的第三方库来代替是很难的,比如下面将要说的ORM、Template。要在Django里用SQLAlchemy或Mako几乎是不可能,即使打了一些补丁用上了也会让你觉得非常非常别扭。
- Django自带的ORM远不如SQLAlchemy强大,除了在Django这一亩三分地,SQLAlchemy是Python世界里事实上的ORM标准,其它框架都支持SQLAlchemy了,唯独Django仍然坚持自己的那一套。
- Template功能比较弱,不能插入Python代码,要写复杂一点的逻辑需要另外用Python实现Tag或Filter。
Django流程介绍
Django采用MTV模式。所谓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
接下来就挨个说说每个模块来构成的Django
Django 基本配置
一、创建django程序
- 终端命令:django-admin startproject sitename
- IDE创建Django程序时,本质上都是自动执行上述命令
1、终端命令
# 创建project django-admin startproject mysite # 创建app cd mysite python3 startapp app01 # 运行程序 python3 manage.py runserver 127.0.0.1:8000
2、IDE创建(PyCharm为例)
File --> New Project --> 选择Django --> Appliocation Name 创建app
二、生成目录结构如下:
三、配置文件(settings)
1、刚创建django project时,开始写入程序,第一步先要在配置文件中注册app
INSTALLED_APPS = [ ‘django.contrib.admin‘, ‘django.contrib.auth‘, ‘django.contrib.contenttypes‘, ‘django.contrib.sessions‘, ‘django.contrib.messages‘, ‘django.contrib.staticfiles‘, ‘app01‘, # 注册app ]
2、数据库连接
DATABASES = { ‘default‘: { ‘ENGINE‘: ‘django.db.backends.mysql‘, ‘NAME‘:‘数据库名‘, ‘USER‘: ‘root‘, ‘PASSWORD‘: ‘xxx‘, ‘HOST‘: ‘‘, ‘PORT‘: ‘‘, } }
注:由于Django内部连接MySQL时使用的是MySQLdb模块,而python3中还无此模块,所以需要使用pymysql来代替
如下设置放置的与project同名的配置的 __init__.py文件中
import pymysql pymysql.install_as_MySQLdb()
3、静态文件配置
STATICFILES_DIRS = ( os.path.join(BASE_DIR,‘static‘), )
注:需要在project下创建static文件夹
Django url
URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL模式以及要为该URL模式调用的视图函数之间的映射表;你就是以这种方式告诉Django,对于这个URL调用这段代码,对于那个URL调用那段代码。URL的家在是从配置文件中开始。
1、先写一个简单的世界你好吧
url文件
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r‘^admin/‘, admin.site.urls), url(r‘^index/‘, views.index), ]
views文件
from django.shortcuts import render # Create your views here. def index(request): return render(request,‘index.html‘)
templates文件夹下新建index.html文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>Hello 张岩林</h1> </body> </html>
2、路由正则
urlpatterns = [ url(r‘^index/(?P<pager>\d*)/,views.index,{‘id‘:333}), ]
注:Django支持路由正则功能,同时想拿到值可以在view中的函数中把相对应得明明写入即可接收到,{‘id‘:333}传入函数,通过key可以取到值
views中index函数
from django.shortcuts import render # Create your views here. def index(request,pager,id): print(pager,id) return render(request,‘index.html‘)
由此看出正则这块可以写分页功能
3、app对路由规则进行一次分类
需要在app01中新建一个urls文件,然后写入,project下urls配置
from django.conf.urls import url from django.contrib import admin from app01 import views from django.conf.urls import include urlpatterns = [ url(r‘^admin/‘, admin.site.urls), url(r‘^buy/‘, include(‘app01.urls‘)), ]
app01下urls配置
#!/usr/bin/env python # -*- coding:utf-8 -*- from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r‘^admin/‘, admin.site.urls), url(r‘^index/‘, views.index), ]
访问url如下:
http://127.0.0.1/buy/index/
django中的路由系统和其他语言的框架有所不同,在django中每一个请求的url都要有一条路由映射,这样才能将请求交给对一个的view中的函数去处理。其他大部分的Web框架则是对一类的url请求做一条路由映射,从而是路由系统变得简洁。
Django views
http请求中产生两个核心对象:
- http请求:HttpRequest对象
- http响应:HttpResponse对象
一、HttpRequest对象
# 获取提交方式 request.method if request.method == "POST": times = time.time() return render(request,‘index.html‘) # 获取前端post提交的数据 request.POST.get(‘username‘) # 获取域名后路径 get_full_path() 例:http://127.0.0.1:8000/index33/?name=123 ,req.get_full_path()得到的结果就是/index33/?name=123
二、HttpResponse对象
def test(request): # 往前端写入字符串 return HttpResponse("xxx") # 跳转路径 return redirect(‘/index/‘) # 渲染HTML文件两种方式 return render(reuqest, "test.html") return render_to_response(‘text.html‘) # 可以直接将函数中所有的变量传给模板 return render(reuqest, "test.html",locals()) # 可以根据通过字典的方式往前端传值,取值输入key即可 return render(reuqest, "test.html",{‘zhang‘:‘好帅‘})
Django 模板语言
1、if/else
{% if %}标签计算一个变量值,如果是“true”,即它存在、不为空并且不是false的boolean值
系统则会显示{% if %}和{% endif %}间的所有内容:
{% if today_is_weekend %} <p>Welcome to the weekend!</p> {% else %} <p>Get back to work.</p> {% endif %}
2、{% for %}
标签允许你按顺序遍历一个序列中的各个元素,Python的for语句语法为for X in Y,X是用来遍历Y的变量 ,每次循环模板系统都会渲染{% for %}和{% endfor %}之间的所有内容
例如,显示给定athlete_list变量来显示athlete列表:
<ul> {% for athlete in athlete_list %} <li>{{ athlete.name }}</li> {% endfor %} </ul> forloop.counter # for循环个数forloop.first # for循环第一个值forloop.last # for循环最后一个值
3、母版,子版继承,导入
母板:{% block title %}{% endblock %} 子板:{% extends "base.html" %} {% block title %}{% endblock %}
4、自定义模板simple_tag
a、在app中创建templatetags模块
b、创建任意 .py 文件,如:xx.py
#!/usr/bin/env python #coding:utf-8 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)
注:事例中变量名不能变,必须是固定写法
c、在使用自定义simple_tag的html文件中导入之前创建的 xx.py 文件名
{% load xx %}
d、使用simple_tag
{% my_simple_time 1 2 3%} {% my_input ‘id_username‘ ‘hide‘%}
Django Form
有时候我们需要在前台用 get 或 post 方法提交一些数据,所以自己写一个网页,用到 html 表单的知识。
一、基础form提交
比如写一个计算 a和 b 之和的简单应用,网页上这么写
<!DOCTYPE html> <html> <body> <p>请输入两个数字</p> <form action="/add/" method="POST"><input type="text" name="a"> <input type="text" name="b"> <input type="submit" value="提交"> </form> </body> </html>
把这些代码保存成一个index.html,放在 templates 文件夹中。
网页的值传到服务器是通过 <input> 或 <textarea>标签中的 name 属性来传递的,在服务器端这么接收:
from django.http import HttpResponse from django.shortcuts import render def index(request): return render(request, ‘index.html‘) def add(request): a = request.POST.GET(‘a‘) b = request.POST.GET(‘b‘) a = int(a) b = int(b) return HttpResponse(str(a+b))
但是,比如用户输入的不是数字,而是字母,就出错了,还有就是提交后再回来已经输入的数据也会没了。
当然如果我们手动将输入之后的数据在 views 中都获取到再传递到网页,这样是可行的,但是很不方便,所以 Django 提供了更简单易用的 forms 来解决验证等这一系列的问题。
二、Django Forms应用
1、简单案例一
在app01下新建一个文件forms.py
from django import forms class AddForm(forms.Form): a = forms.IntegerField() b = forms.IntegerField()
我们的视图函数 views.py 中
#!/usr/bin/env python # -*- coding:utf-8 -*- from django.shortcuts import render,HttpResponse from app01.forms import AddForm def index(request): if request.method == ‘POST‘:# 当提交表单时 # form 包含提交的数据 form = AddForm(request.POST) # 如果提交的数据合法 if form.is_valid(): a = form.cleaned_data[‘a‘] b = form.cleaned_data[‘b‘] return HttpResponse(str(int(a) + int(b))) # 当正常访问时 else: form = AddForm() return render(request, ‘index.html‘, {‘form‘: form})
对应的模板文件 index.html
<form method=‘post‘> {% csrf_token %} {{ form }} <input type="submit" value="提交"> </form>
这个简单的案例,大家不知道有没有看出其中的蹊跷呢,仔细观察,form类给我做了验证,用户输入错了会弹出报错信息
2、进阶案例二
models.py
from django.db import models # Create your models here. class BookType(models.Model): caption = models.CharField(max_length=64) class Book(models.Model): name = models.CharField(max_length=64) pages = models.IntegerField() price = models.DecimalField(max_digits=10,decimal_places=2) pubdate = models.DateField() book_type = models.ForeignKey(‘BookType‘)
views.py
#!/usr/bin/env python # -*- coding:utf-8 -*- from django.shortcuts import render from app01.forms import Form1 def form1(request): if request.method == ‘POST‘: # 获取请求内容做验证 f = Form1(request.POST) if f.is_valid(): print(f.cleaned_data) else: print(type(f.errors),f.errors) return render(request,‘form1.html‘,{‘error‘:f.errors,‘form‘:f}) else: f = Form1() return render(request,‘form1.html‘,{‘form‘:f})
在app01下新建一个文件forms.py
#!/usr/bin/env python # -*- coding:utf-8 -*- from django import forms from app01 import models class Form1(forms.Form): # 用户名,给该标签添加一个class属性,还有空值的报错信息修改 user = forms.CharField( widget=forms.TextInput(attrs={‘class‘: ‘c1‘}), error_messages={‘required‘: ‘用户名不能为空‘},) # 密码定义最大长度和最小长度 pwd = forms.CharField(max_length=4,min_length=2) # 邮箱定义错误信息,required为空值错误信息,invalid为邮箱匹配错误信息 email = forms.EmailField(error_messages={‘required‘: ‘邮箱不能为空‘, ‘invalid‘: ‘邮箱格式错误‘}) # 生成多行文本编辑框 memo = forms.CharField(widget=forms.Textarea()) # 下拉菜单实时更新数据库 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"})) def __init__(self,*args, **kwargs): super(Form1, 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"}))
前端form1.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .input-group{ position: relative; padding: 20px; width: 250px; } .input-group input{ width: 200px; display: inline-block; } .input-group span{ display: inline-block; position: absolute; height: 12px; font-size: 8px; border: 1px solid red; background-color: darksalmon; color: white; top: 41px; left: 20px; width: 202px; } </style> </head> <body> <form action="/form1/" method="post"> <div class="input-group"> {{ form.user }} {% if error.user.0 %} <span>{{ error.user.0 }}</span> {% endif %} </div> <div class="input-group"> {{ form.pwd }} {% if error.pwd.0 %} <span>{{ error.pwd.0 }}</span> {% endif %} </div> <div class="input-group"> {{ form.email }} {% if error.email.0 %} <span>{{ error.email.0 }}</span> {% endif %} </div> <div class="input-group"> {{ form.memo }} {% if error.memo.0 %} <span>{{ error.memo.0 }}</span> {% endif %} </div> <div class="input-group"> {{ form.book_type }} {% if error.book_type.0 %} <span>{{ error.book_type.0 }}</span> {% endif %} </div> <div> <input type="submit" value="提交"> </div> </form> </body> </html>
Django Cookie
1、获取cookie
# 方式一 request.COOKIES[‘key‘] # 方式二 request.COOKIES.get(‘key‘) # 方式三 request.get_signed_cookie(key, default=RAISE_ERROR, salt=‘‘, max_age=None) # 参数: default: 默认值 salt: 加密盐 max_age: 后台控制过期时间
2、设置cookie
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获取(不是绝对,底层抓包可以获取到也可以被覆盖)
Django Session
一、session使用
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种类
Django中默认支持Session,其内部提供了5种类型的Session供开发者使用:
- 数据库(默认)
- 缓存
- 文件
- 缓存+数据库
- 加密cookie
1、数据库Session
Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。
配置 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,默认修改之后才保存(默认)
2、缓存Session
配置 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,默认修改之后才保存
3、文件Session
配置 settings.py SESSION_ENGINE = ‘django.contrib.sessions.backends.file‘ # 引擎 SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() 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,默认修改之后才保存
4、缓存+数据库Session
数据库用于做持久化,缓存用于提高效率 配置 settings.py SESSION_ENGINE = ‘django.contrib.sessions.backends.cached_db‘ # 引擎
5、加密cookie Session
配置 settings.py SESSION_ENGINE = ‘django.contrib.sessions.backends.signed_cookies‘ # 引擎
6、session自定义验证登录,装饰器
def login(func): def wrap(request, *args, **kwargs): # 如果未登陆,跳转到指定页面 if request.path == ‘/index/‘: return redirect(‘/login/‘) return func(request, *args, **kwargs) return wrap
Django CSRF
一、简介
django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成。而对于django中设置防跨站请求伪造功能有分为全局和局部。
全局:
中间件 django.middleware.csrf.CsrfViewMiddleware
局部:
- @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
- @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
注:from django.views.decorators.csrf import csrf_exempt,csrf_protect
二、应用
1、普通表单
veiw中设置返回值: return render_to_response(‘Account/Login.html‘,data,context_instance=RequestContext(request)) 或者 return render(request, ‘xxx.html‘, data) html中设置Token: {% csrf_token %}
2、ajax
view.py
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/index.html‘,context_instance=RequestContext(request))
index.html
<!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>
注:原文出处http://www.cnblogs.com/wupeiqi/articles/5237704.html