Django基础
一:安装django
首先创建虚拟环境并进入虚拟环境(https://blog.csdn.net/pcn01/article/details/103819684)
pip install django==2.1.7 # 默认下载最新版本
创建django项目:
django-admin startproject dailyfresh
创建应用命令如下:
python manage.py startapp booktest
二:路由层
2.1 path与re_path函数
在新版本Django2.x中,url的路由表示用path和re_path代替,模块的导入由django1.x版本的from django.conf.urls import url,include变成现在的Django2.x中的from django.urls import path, re_path, include
path函数的定义为:path(route, view, name = None, kwargs = None)
path('book_detail/<book_id>/', views.book_detail), # 默认为str转换器;视图函数中接收参数必须为:book_id
path('book/publisher/<int:p_id>', views.publisher), # 指定p_id参数为int类型
re_path(r'^user/', include('user.urls')),
re_path(r'^login$', views.login),
# r 表示转义
# ^ 严格的开头
# $ 严格的结尾
在浏览器中输入的URL,哪些部分参与正则匹配?
http://ip:port/和get post参数不参与正则匹配
2.2 url的反向解析
第一种写法是在project urls中指定app_name与实例命名空间
path('user/', include(('user.urls', 'user'), namespace = 'user')),
# 如果指定实例命名空间,那么前提是必须要先指定应用命名空间
第二种写法是在project urls中指定实例命名空间,然后在app urls中指定app_name
path('book/', include('book.urls', namespace = 'book')
app url中指定app_name:
app_name = 'book'
urlpatterns = [
path('', views.index, name = 'index'),
]
视图函数中反转url
def login(request):
username = request.GET.get('username')
if username:
return redirect(reverse('book:index')
else:
return HttpResponse('this is user login page')
# return redirect(reverse('book:index', args=(111,222))
# return redirect(reverse('book:index', kwargs={"key1":value1....}) # 应用有名分组,按照关键字传参
HTML里的反向:
{%url '路由别名' 2019 12 %}
{%url '路由别名' year=2019 month=12 %}
三:视图层
3.1 HttpRequest对象属性
视图函数中的request就是HttpRequest类的对象;request包含浏览器请求的信息,服务器接收到http协议的请求后,会根据报文创建HttpRequest对象,这个对象不需要我们创建,直接使用服务器构造好的对象就可以。视图的第一个参数必须是HttpRequest对象,在django.http模块中定义了HttpRequest对象的API。
1.HttpRequest.GET
# 一个类似于字典的对象,包含 HTTP GET 的所有参数。详情请参考 QueryDict 对象。
2.HttpRequest.POST
# 一个类似于字典的对象,如果请求中包含表单数据,则将这些数据封装成 QueryDict 对象。
# POST 请求可以带有空的 POST 字典 —— 如果通过 HTTP POST 方法发送一个表单,但是表单中没有任何的数据,QueryDict 对象依然会被创建。因此,不应该使用 if request.POST 来检查使用的是否是POST 方法;应该使用 if request.method == "POST"
# 另外:如果使用 POST 上传文件的话,文件信息将包含在 FILES 属性中。
# 注意:键值对的值是多个的时候,比如checkbox类型的input标签,select标签,需要用:request.POST.getlist("hobby")
3.HttpRequest.body
# 一个字符串,代表请求报文的主体。在处理非 HTTP 形式的报文时非常有用,例如:二进制图片、XML,Json等。但是,如果要处理表单数据的时候,推荐还是使用 HttpRequest.POST 。
4.HttpRequest.path
# 一个字符串,表示请求的路径组件(不含域名)。例如:"/music/bands/the_beatles/"
5.HttpRequest.method
# 一个字符串,表示请求使用的HTTP 方法。必须使用大写。例如:"GET"、"POST"
6.HttpRequest.encoding
# 一个字符串,表示提交的数据的编码方式(如果为 None 则表示使用 DEFAULT_CHARSET 的设置,默认为 'utf-8')。
# 这个属性是可写的,你可以修改它来修改访问表单数据使用的编码。
# 接下来对属性的任何访问(例如从 GET 或 POST 中读取数据)将使用新的 encoding 值。
# 如果你知道表单数据的编码不是 DEFAULT_CHARSET ,则使用它。
7.HttpRequest.META
8.HttpRequest.FILES
9.HttpRequest.COOKIES
10.HttpRequest.session
11.HttpRequest.user(用户认证组件下使用)
12.HttpRequest.get_full_path()
返回 path,如果可以将加上查询字符串。
例如:"/music/bands/the_beatles/?print=true"
13.HttpRequest.is_ajax()
如果请求是通过XMLHttpRequest 发起的,则返回True,方法是检查 HTTP_X_REQUESTED_WITH 相应的首部是否是字符串'XMLHttpRequest'。
大部分现代的 JavaScript 库都会发送这个头部。如果你编写自己的 XMLHttpRequest 调用(在浏览器端),你必须手工设置这个值来让 is_ajax() 可以工作。
如果一个响应需要根据请求是否是通过AJAX 发起的,并且你正在使用某种形式的缓存例如Django 的 cache middleware,
你应该使用 vary_on_headers('HTTP_X_REQUESTED_WITH') 装饰你的视图以让响应能够正确地缓存。
3.2 HttpResponse对象
响应对象主要有三种形式(响应三剑客):
HttpResponse()
render()
redirect()
HttpResponse()括号内直接跟一个具体的字符串作为响应体,比较直接很简单
四:模板层
4.1 模板变量
在 Django 模板中遍历复杂数据结构的关键是句点字符, 语法:
{{ var_name }}
views.py:
def index(request):
import datetime
s="hello"
l=[111,222,333] # 列表
dic={"name":"yuan","age":18} # 字典
date = datetime.date(1993, 5, 2) # 日期对象
class Person(object):
def __init__(self,name):
self.name=name
person_yuan=Person("yuan") # 自定义类对象
person_egon=Person("egon")
person_alex=Person("alex")
person_list=[person_yuan,person_egon,person_alex]
return render(request,"index.html",{"l":l,"dic":dic,"date":date,"person_list":person_list})
template:
<h4>{{s}}</h4>
<h4>列表:{{ l.0 }}</h4>
<h4>列表:{{ l.2 }}</h4>
<h4>字典:{{ dic.name }}</h4>
<h4>日期:{{ date.year }}</h4>
<h4>类对象列表:{{ person_list.0.name }}</h4>
注意:句点符也可以用来引用对象的方法(无参数方法):
<h4>字典:{{ dic.name.upper }}</h4>
模板变量的解析顺序:如 {{ book.btitle }}
1:首先把book当成一个字典,把btitle当成键名,进行取值 book[‘btitle’]
2:如果上面取不到值,把book当成一个对象,把btitle当成属性,进行取值 book.title
3:如果2取不到值,把book当成一个对象,把btitle当成对象的方法,进行取值 book.title
如果解析失败,则产生内容时用空字符串填充模板变量
使用模板变量时,点前面的可以是一个字典,可以是一个对象,还可以是一个列表
4.2 模板语法之过滤器
{{ value|default:"nothing" }} # 如果一个变量是false或者为空,使用给定的默认值。否则,使用变量的值
{{ value|length }} # 返回值的长度。它对字符串和列表都起作用
{{ value|filesizeformat }} # 将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)
{{ value|date:"Y-m-d" }} # 格式化时间
{{ value|truncatechars:10 }} # 如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾
{{ value|safe }}
# Django的模板中会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全。但是有的时候我们可能不希望这些HTML元素被转义,比如我们做一个内容管理系统,后台添加的文章中是经过修饰的,这些修饰可能是通过一个类似于FCKeditor编辑加注了HTML修饰符的文本,如果自动转义的话显示的就是保护HTML标签的源文件。为了在Django中关闭HTML的自动转义有两种方式,如果是一个单独的变量我们可以通过过滤器“|safe”的方式告诉Django这段代码是安全的不必转义
4.3 模板标签
标签看起来像是这样的: {% tag %}。标签比变量更加复杂:一些在输出中创建文本,一些通过循环或逻辑来控制流程,一些加载其后的变量将使用到的额外信息到模版中。一些标签需要开始和结束标签 (例如{% tag %} …标签 内容 … {% endtag %})。
for标签:
遍历每一个元素:
{% for person in person_list %}
<p>{{ person.name }}</p>
{% endfor %}
可以利用{% for obj in list reversed %}反向完成循环。
遍历一个字典:
{% for key,val in dic.items %}
<p>{{ key }}:{{ val }}</p>
{% endfor %}
注:循环序号可以通过{{forloop}}显示
forloop.counter The current iteration of the loop (1-indexed)
forloop.counter0 The current iteration of the loop (0-indexed)
forloop.revcounter The number of iterations from the end of the loop (1-indexed)
forloop.revcounter0 The number of iterations from the end of the loop (0-indexed)
forloop.first True if this is the first time through the loop
forloop.last True if this is the last time through the loop
for … empty:
for 标签带有一个可选的{% empty %} 从句,以便在给出的组是空的或者没有被找到时,可以有所操作。
{% for person in person_list %}
<p>{{ person.name }}</p>
{% empty %}
<p>sorry,no person here</p>
{% endfor %}
if 标签:
{% if %}会对一个变量求值,如果它的值是“True”(存在、不为空、且不是boolean类型的false值),对应的内容块会输出。
{% if num > 100 or num < 0 %}
<p>无效</p>
{% elif num > 80 and num < 100 %}
<p>优秀</p>
{% else %}
<p>凑活吧</p>
{% endif %}
with:
使用一个简单地名字缓存一个复杂的变量,当你需要使用一个“昂贵的”方法(比如访问数据库)很多次的时候是非常有用的
{% with total=business.employees.count %}
{{ total }} employee{{ total|pluralize }}
{% endwith %}
4.4 静态文件的载入
{% load staticfiles %}
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>天天生鲜-注册</title>
<link rel="stylesheet" type="text/css" href="{% static 'css/reset.css' %}">
</head>
如果不想每次都在模板中写 {% load staticfiles %} 代码,可以在settings配置文件中添加以下代码:
TEMPLATES = [
{
......................
'OPTIONS': {
'context_processors': [
.......................
],
'builtins': ['django.templatetags.static'] # 加入此行代码
},
},
]
4.5 自定义过滤器
过滤器的本质就是python函数;自定义的过滤器至少要有一个参数,最多两个参数
1:首先在项目目录下新建一个包,名为:templatetags,该目录名是固定的
2:在templatetags目录下新建filters.py文件,该文件名可任意取
from django.template import Library
register = Library()
@register.filter # 必须使用register.filter装饰下面自定义的函数
def mod(num):
# 判断num是否为偶数
return num % 2 == 0
3:模板文件中使用自定义的过滤器
<!DOCTYPE html>
<html lang="en">
{% load filters %} # 导入过滤器,filters为自定义过滤器的文件名,该文件下所有的过滤器都导入了
.........................
<ul>
{% for book in books %}
{% if book.id|mod %} # 管道符会将前面的值传递给mod函数
<li style="background:green;">{{ forloop.counter }} : {{ book.btitle }}</li>
{% else %}
<li style="background:red;">{{ forloop.counter }} : {{ book.btitle }}</li>
{% endif %}
{% endfor %}
</ul>
..................
4:如果自定义过滤器中有多个参数,如:
from django.template import Library
register = Library()
@register.filter
def mod(num):
# 判断num是否为偶数
return num % 2 == 0
@register.filter
def mod_val(num, val):
'''判断num是否能被val整除'''
return num % val == 0
模板中使用方法:
<ul>
{% for book in books %}
{% if book.id|mod_val:2 %} # 第二个参数自己传递给mod_val函数
<li style="background:green;">{{ forloop.counter }} : {{ book.btitle }}</li>
{% else %}
<li style="background:red;">{{ forloop.counter }} : {{ book.btitle }}</li>
{% endif %}
{% endfor %}
</ul>
4.6 verbatim标签
verbatim 标签:默认在 DTL 模板中是会去解析那些特殊字符的。比如 {% 和 %} 以及 {{ 等。如果你在某个代码片段中不想使用 DTL 的解析引擎。那么你可以把这个代码片段放在 verbatim 标签中
五:AJAX请求
JsonResponse对象的content-type为’application/json’
<script>
$(function() {
$('#btnLogin').click(function() {
username = $('#username').val();
password = $('#password').val();
$.ajax({
'url': '/login',
'type': 'post',
'data': {'username': username, 'password': password},
'dataType': 'json'
}).success(function(data) {
console.log(data);
if (data.res == 0) {
$('#message').show().html('用户名或密码错误')
}else{
location.href = '/';
}
})
})
})
</script>
视图函数:
def login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if username == 'smart' and password == '123':
return JsonResponse({'res': 1})
else:
return JsonResponse({'res': 0})
return render(request, 'login.html')
六:状态保持
6.1 cookie
http协议是无状态的。下一次去访问一个页面时并不知道上一次对这个页面做了什么。
1:以键值对方式进行存储
2:通过浏览器访问一个网站时,会将浏览器存储的跟网站相关的所有cookie信息发送给该网站的服务器。request.COOKIES
3:cookie是基于域名安装的
4:cookie是有过期时间的,如果不指定,默认关闭浏览器之后cookie就会过期
设置COOKIE需要一个HttpResponse类的对象或者是它子类的对象
浏览器发给服务器的cookie,保存在request对象COOKIES中
def set_cookie(request):
response = HttpResponse('设置cookie')
response.set_cookie('num', 1, max_age = 14*24*3600) # max_age设置过期时间:多长时间过期
# response.set_cookie('num', 1, expires = datetime.now() + timedelta(days = 14)) # expires设置过期时间:什么时间点过期
return response
def get_cookie(request):
num = request.COOKIES['num']
return HttpResponse(num)
6.2 session
session存储在服务器端
1:session是以键值对进行存储的
2:session依赖于cookie
3:session也是有过期时间,如果不指定,默认两周就会过期
def set_session(request):
request.session['username'] = 'smart'
request.session['age'] = 18
return HttpResponse('设置session')
def get_session(request):
username = request.session['username']
age = request.session['age'] # 也可以使用get获取数据:request.session.get('age', 默认值)
return HttpResponse(username + ':' + str(age))
####### session的其它操作 ##############
request.session.clear() # 清除session,在存储中删除值部分
request.session.flush() # 清除session,删除数据库的记录
del request.session['key'] # 删除某个键对应的值
request.session.has_key('islogin') # 判断session中是否有islogin键
django将session入库
session_data为base64加密后的字符串
request.session.set_expiry(value) # 设置session的过期时间
# value是一个整数,会话的session_id cookie将在value秒没有活动后过期
# value为0,那么用户会话的session_id cookie将在用户的浏览器关闭时过期
# value为None,那会会话的session_id cookie两周之后过期
cookie and session的应用场景:
cookie:记住用户名,安全性要求不高
session:涉及到安全性要求比较高的数据。银行卡账户,密码
七:中间件
7.1 自定义中间件
中间件可以定义五个方法,分别是:
process_request(self,request)
process_view(self, request, view_func, view_args, view_kwargs)
process_exception(self, request, exception)
process_response(self, request, response)
process_template_response(self,request,response)(了解)
utils.middle.py文件:
from django.utils.deprecation import MiddlewareMixin
class MD1(MiddlewareMixin):
def process_request(self, request):
print('MD1下的process_request方法')
def process_response(self, request, response):
print('MD1下的process_response方法')
return response # 必须返回response对象
class MD2(MiddlewareMixin):
def process_request(self, request):
print('MD2下的process_request方法')
def process_response(self, request, response):
print('MD2下的process_response方法')
return response
注册自定义中间件:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
.......................................
'utils.middle.MD1',
'utils.middle.MD2',
]
访问一个视图函数,输出结果 如下:
MD1下的process_request方法
MD2下的process_request方法
MD2下的process_response方法
MD1下的process_response方法
# 整个执行流程可看上图