Django知识点汇总
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django知识点汇总相关的知识,希望对你有一定的参考价值。
HTTP(hypertext transport protocol),即超文本传输协议。这个协议详细规定了浏览器和万维网服务器之间互相通信的规则。
HTTP就是一个通信规则,通信规则规定了客户端发送给服务器的内容格式,也规定了服务器发送给客户端的内容格式。其实我们要学习的就是这个两个格式!客户端发送给服务器的格式叫“请求协议”;服务器发送给客户端的格式叫“响应协议”。
特点:
- HTTP叫超文本传输协议,基于请求/响应模式的!
- HTTP是无状态协议。
URL:统一资源定位符,就是一个网址:协议名://域名:端口/路径,例如:http://www.oldboy.cn:80/index.html
8.2 请求协议
请求协议的格式如下:
请求首行; // 请求方式 请求路径 协议和版本,例如:GET /index.html HTTP/1.1 请求头信息;// 请求头名称:请求头内容,即为key:value格式,例如:Host:localhost 空行; // 用来与请求体分隔开 请求体。 // GET没有请求体,只有POST有请求体。为一个个键值对 实例: GET请求: "GET /index.html http1.1\\r\\nUser-Agent:Mozilla/5.0 (Windows NT 6.1; Win64; x6..\\r\\n\\r\\nAccept-Encoding:gzip\\r\\n\\r\\n" POST请求: "POST /index.html http1.1\\r\\nUser-Agent:Mozilla/5.0 (Windows NT 6.1; Win64; x6..\\r\\n\\r\\nAccept-Encoding:gzip\\r\\n\\r\\nuser=cqz&hobby=lihao" 请求头以\\r\\n划分 请求体以\\r\\n\\r\\n划分
浏览器发送给服务器的内容就这个格式的,如果不是这个格式服务器将无法解读!在HTTP协议中,请求有很多请求方法,其中最为常用的就是GET和POST。
8.2.1 GET请求
HTTP默认的请求方法就是GET
* 没有请求体 * 数据必须在1K之内! * GET请求数据会暴露在浏览器的地址栏中
GET请求常用的操作:
1. 在浏览器的地址栏中直接给出URL,那么就一定是GET请求 2. 点击页面上的超链接也一定是GET请求 3. 提交表单时,表单默认使用GET请求,但可以设置为POST
8.2.2 POST请求
(1). 数据不会出现在地址栏中 (2). 数据的大小没有上限 (3). 有请求体 (4). 请求体中如果存在中文,会使用URL编码!
我们都知道Http协议中参数的传输是"key=value"这种简直对形式的,如果要传多个参数就需要用“&”符号对键值对进行分割。如"?name1=value1&name2=value2",这样在服务端在收到这种字符串的时候,会用“&”分割出每一个参数,然后再用“=”来分割出参数值。 针对“name1=value1&name2=value2”我们来说一下客户端到服务端的概念上解析过程: 上述字符串在计算机中用ASCII吗表示为: 6E616D6531 3D 76616C756531 26 6E616D6532 3D 76616C756532。 6E616D6531:name1 3D:= 76616C756531:value1 26:& 6E616D6532:name2 3D:= 76616C756532:value2 服务端在接收到该数据后就可以遍历该字节流,首先一个字节一个字节的吃,当吃到3D这字节后,服务端就知道前面吃得字节表示一个key,再想后吃,如果遇到26,说明从刚才吃的3D到26子节之间的是上一个key的value,以此类推就可以解析出客户端传过来的参数。 现在有这样一个问题,如果我的参数值中就包含=或&这种特殊字符的时候该怎么办。 比如说“name1=value1”,其中value1的值是“va&lu=e1”字符串,那么实际在传输过程中就会变成这样“name1=va&lu=e1”。我们的本意是就只有一个键值对,但是服务端会解析成两个键值对,这样就产生了奇异。 如何解决上述问题带来的歧义呢?解决的办法就是对参数进行URL编码 URL编码只是简单的在特殊字符的各个字节前加上%,例如,我们对上述会产生奇异的字符进行URL编码后结果:“name1=va%26lu%3D”,这样服务端会把紧跟在“%”后的字节当成普通的字节,就是不会把它当成各个参数或键值对的分隔符。 为什么要进行URL编码
8.3 接收自定义http头部(headers)
用Python的httplib库来做模拟客户端,参考网上写出模拟代码如下:
#coding=utf8 import httplib httpClient = None try: myheaders = { "category": "Books", "id": "21", ‘My-Agent‘: "Super brower" } httpClient = httplib.HTTPConnection(‘10.14.1XX.XXX‘,8086,timeout=30) httpClient.request(‘GET‘,‘/headinfo/‘,headers=myheaders) response = httpClient.getresponse() print response.status print response.reason print response.read() except Exception, e: print e finally: if httpClient: httpClient.close()
其中‘/headinfo/‘为服务器的响应目录。
然后是服务端的响应代码,一个能够返回客户端自定义头部的模块
from django.http import HttpResponse def headinfo(request): category = request.META.get(‘HTTP_CATEGORY‘, ‘unkown‘) id = request.META.get(‘HTTP_ID‘,‘unkown‘) agent = request.META.get(‘MY-AGENT‘,‘unkown‘) html = "<html><body>Category is %s, id is %s, agent is %s</body></html>" % (category, id, agent) return HttpResponse(html)
结果:
注意点:自定义请求头时,Django自动在头部META字典中的key值都会被加上“HTTP_”的前缀,category 会变成 HTTP_CATEGORY ,auth-api 会变成 HTTP_AUTH_API
8.4 http请求request详解
属性 描述 path 表示提交请求页面完整地址的字符串, 不包括域名,如 "/music/bands/the_beatles/" 。 method 表示提交请求使用的HTTP方法。 它总是大写的。例如: if request.method == ‘GET‘: do_something() elif request.method == ‘POST‘: do_something_else() GET 一个类字典对象,包含所有的HTTP的GET参数的信息。 见 QueryDict 文档。 POST 一个类字典对象,包含所有的HTTP的POST参数的信息。 见 QueryDict 文档。 通过POST提交的请求有可能包含一个空的 POST 字典, 也就是说, 一个通过POST方法提交的表单可能不包含数据。 因此,不应该使用 if request.POST 来判断POST方法的使用, 而是使用if request.method == "POST" (见表中的 method 条目)。 注意: POST 并 不 包含文件上传信息。 见 FILES 。 REQUEST 为了方便而创建,这是一个类字典对象,先搜索 POST , 再搜索 GET 。 灵感来自于php的$_REQEUST 。 例如, 若 GET = {"name": "john"} , POST = {"age": ‘34‘} , REQUEST["name"] 会是 "john" , REQUEST["age"] 会是 "34" 。 强烈建议使用 GET 和 POST ,而不是 REQUEST 。 这是为了向前兼容和更清楚的表示。 COOKIES 一个标准的Python字典,包含所有cookie。 键和值都是字符串。cookie使用的更多信息见第12章。 FILES 一个类字典对象,包含所有上传的文件。 FILES 的键来自 <input type="file" name="" />中的 name 。 FILES 的值是一个标准的Python字典, 包含以下三个键: filename :字符串,表示上传文件的文件名。 content-type :上传文件的内容类型。 content :上传文件的原始内容。 注意 FILES 只在请求的方法是 POST ,并且提交的 <form> 包含enctype="multipart/form-data" 时 才包含数据。否则, FILES 只是一个空的类字典对象。 META 一个标准的Python字典,包含所有有效的HTTP头信息。 有效的头信息与客户端和服务器有关。 这里有几个例子: CONTENT_LENGTH CONTENT_TYPE QUERY_STRING :未解析的原始请求字符串。 REMOTE_ADDR :客户端IP地址。 REMOTE_HOST :客户端主机名。 SERVER_NAME :服务器主机名。 SERVER_PORT :服务器端口号。 在 META 中有效的任一HTTP头信息都是带有 HTTP_ 前缀的 键,例如: HTTP_ACCEPT_ENCODING HTTP_ACCEPT_LANGUAGE HTTP_HOST :客户端发送的 Host 头信息。 HTTP_REFERER :被指向的页面,如果存在的。 HTTP_USER_AGENT :客户端的user-agent字符串。 HTTP_X_BENDER : X-Bender 头信息的值, 如果已设的话。 user 一个 django.contrib.auth.models.User 对象表示 当前登录用户。 若当前用户尚未登录,user 会设为 django.contrib.auth.models.AnonymousUser 的一个实例。 可以将它们与is_authenticated() 区别开: if request.user.is_authenticated(): # Do something for logged-in users. else: # Do something for anonymous users. user 仅当Django激活 AuthenticationMiddleware 时有效。 关于认证和用户的完整细节,见第12章。 session 一个可读写的类字典对象,表示当前session。 仅当Django已激活session支持时有效。 见 http://djangobook.py3k.cn/chapter12/ raw_post_data POST的原始数据。 用于对数据的复杂处理。
8.5 HttpRequest 的方法
方法 描述 __getitem__(key) 请求所给键的GET/POST值,先查找POST,然后是GET。 若键不存在,则引发异常KeyError 。该方法使用户可以以访问字典方式来访问一个 HttpRequest 实例。例如, request["foo"] 和先检查 request.POST["foo"] 再检查request.GET["foo"] 一 样。 has_key() 返回 True 或 False , 标识 request.GET 或 request.POST 是否包含所给的 键。 get_full_path() 返回 path ,若请求字符串有效,则附加于其后。 例如,"/music/bands/the_beatles/?print=true" 。 is_secure() 如果请求是安全的,则返回 True 。 也就是说,请求是以HTTPS的形式提交的。
九、COOKIE 与 SESSION
9.1简介
1、cookie不属于http协议范围,由于http协议无法保持状态,但实际情况,我们却又需要“保持状态”,因此cookie就是在这样一个场景下诞生。 cookie的工作原理是:由服务器产生内容,浏览器收到请求后保存在本地;当浏览器再次访问时,浏览器会自动带上cookie,这样服务器就能通过cookie的内容来判断这个是“谁”了。 2、cookie虽然在一定程度上解决了“保持状态”的需求,但是由于cookie本身最大支持4096字节,以及cookie本身保存在客户端,可能被拦截或窃取,因此就需要有一种新的东西,它能支持更多的字节,并且他保存在服务器,有较高的安全性。这就是session。 问题来了,基于http协议的无状态特征,服务器根本就不知道访问者是“谁”。那么上述的cookie就起到桥接的作用。 我们可以给每个客户端的cookie分配一个唯一的id,这样用户在访问时,通过cookie,服务器就知道来的人是“谁”。然后我们再根据不同的cookie的id,在服务器上保存一段时间的私密资料,如“账号密码”等等。 3、总结而言:cookie弥补了http无状态的不足,让服务器知道来的人是“谁”;但是cookie以文本的形式保存在本地,自身安全性较差;所以我们就通过cookie识别不同的用户,对应的在session里保存私密的信息以及超过4096字节的文本。 4、另外,上述所说的cookie和session其实是共通性的东西,不限于语言和框架
9.2认证机制
制作一个登陆页面,在验证了用户名和密码的正确性后跳转到后台的页面。但是测试后也发现,如果绕过登陆页面。直接输入后台的url地址也可以直接访问的。这个显然是不合理的。其实我们缺失的就是cookie和session配合的验证。有了这个验证过程,我们就可以实现和其他网站一样必须登录才能进入后台页面了。 先说一下这种认证的机制。每当我们使用一款浏览器访问一个登陆页面的时候,一旦我们通过了认证。服务器端就会发送一组随机唯一的字符串(假设是123abc)到浏览器端,这个被存储在浏览端的东西就叫cookie。而服务器端也会自己存储一下用户当前的状态,比如login=true,username=hahaha之类的用户信息。但是这种存储是以字典形式存储的,字典的唯一key就是刚才发给用户的唯一的cookie值。那么如果在服务器端查看session信息的话,理论上就会看到如下样子的字典 {‘123abc‘:{‘login‘:true,‘username:hahaha‘}} 因为每个cookie都是唯一的,所以我们在电脑上换个浏览器再登陆同一个网站也需要再次验证。那么为什么说我们只是理论上看到这样子的字典呢?因为处于安全性的考虑,其实对于上面那个大字典不光key值123abc是被加密的,value值{‘login‘:true,‘username:hahaha‘}在服务器端也是一样被加密的。所以我们服务器上就算打开session信息看到的也是类似与以下样子的东西 {‘123abc‘:dasdasdasd1231231da1231231} 知道了原理,我们下面就来用代码实现
9.3认证应用
第一步: 先在templates目录下创建两个html,login.html负责登录页面。backend页面代表后台页面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>login</title> <link rel="stylesheet" href="http://830909.blog.51cto.com/static/plugins/bootstrap-3.3.5-dist/css/bootstrap.min.css"> </head> <body> <div class="container"> <form action="login.html" method="post"> <div class="form-group"> <label class="sr-only">username</label> <input type="text" class="form-control" name="username" placeholder="用户名"/> </div> <div class="form-group"> <label class="sr-only">Password</label> <input type="password" class="form-control" name="passwd" placeholder="密码"/> </div> <div class="form-group"> <input class="btn btn-primary" type="submit" value="http://830909.blog.51cto.com/8311014/Submit"> </div> </form> </div> <script type="application/javascript" src="http://830909.blog.51cto.com/static/js/jquery-2.2.1.min.js"></script> <script type="application/javascript" src="http://830909.blog.51cto.com/static/plugins/bootstrap-3.3.5-dist/js/bootstrap.min.js"></script> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>backend</title> <link rel="stylesheet" href="http://830909.blog.51cto.com/static/plugins/bootstrap-3.3.5-dist/css/bootstrap.min.css"> <link rel="stylesheet" href="http://830909.blog.51cto.com/static/css/commons.css"> </head> <body> <div class="container"> <h2>cookie 内容是 {{ cookie_content }}</h2> <h2>session 内容是 {{ session_content }}</h2> <h2>登录用户名 :{{ username }}</h2> <a href="http://830909.blog.51cto.com/logout/">注销</a> </div> <script type="application/javascript" src="http://830909.blog.51cto.com/static/js/jquery-2.2.1.min.js"></script> <script type="application/javascript" src="http://830909.blog.51cto.com/static/plugins/bootstrap-3.3.5-dist/js/bootstrap.min.js"></script> </body> </html>
第二步:编辑app01应用下的views.py文件,编写代码逻辑部分
# /usr/bin/env python # coding:utf-8 from django.shortcuts import render from django.shortcuts import redirect def login(request): if request.method=="POST": username=request.POST[‘username‘] pwd=request.POST[‘passwd‘] if username==‘abc‘ and pwd==‘123‘: #设置session内部的字典内容 request.session[‘is_login‘]=‘true‘ request.session[‘username‘]=‘abc‘ #登录成功就将url重定向到后台的url return redirect(‘/backend/‘) #登录不成功或第一访问就停留在登录页面 return render(request,‘login.html‘) def backend(request): """ 这里必须用读取字典的get()方法把is_login的value缺省设置为False, 当用户访问backend这个url先尝试获取这个浏览器对应的session中的 is_login的值。如果对方登录成功的话,在login里就已经把is_login 的值修改为了True,反之这个值就是False的 """ is_login=request.session.get(‘is_login‘,False) #如果为真,就说明用户是正常登陆的 if is_login: #获取字典的内容并传入页面文件 cookie_content=request.COOKIES session_content=request.session username=request.session[‘username‘] return render(request,‘backend.html‘, { ‘cookie_content‘:cookie_content, ‘session_content‘:session_content, ‘username‘:username }) else: """ 如果访问的时候没有携带正确的session, 就直接被重定向url回login页面 """ return redirect(‘/login/‘) def logout(request): """ 直接通过request.session[‘is_login‘]回去返回的时候, 如果is_login对应的value值不存在会导致程序异常。所以 需要做异常处理 """ try: #删除is_login对应的value值 del request.session[‘is_login‘] except KeyError: pass #点击注销之后,直接重定向回登录页面 return redirect(‘/login/‘)
第三步,编辑mydjango目录下的urls.py文件。设置函数与页面的绑定关系
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r‘^admin/‘, admin.site.urls), url(r‘^login/‘, views.login), url(r‘^backend/‘, views.backend), url(r‘^logout/‘, views.logout), ]
最后打开浏览器直接访问/backend/页面的时候直接就被重定向到了/login/
总结
1、login页面正确登录的话,后台页面可以获取到浏览器携带的cookie的。 2、第一行的sessionid其实就是cookie值 3、session的内容是加密的,从客户端获取不到session的内容 4、服务端可以通过预设的key值取出session的内容并打印到前段 5、django的session默认是存储在数据库里的,我们再到数据库查看一下真正session内容
9.4cookie知识点:
# 1、获取Cookie: # request.COOKIES[‘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获取(不是绝对,底层抓包可以获取到也可以被覆盖) # 由于cookie保存在客户端的电脑上,所以,JavaScript和jquery也可以操作cookie。 # <script src=‘/static/js/jquery.cookie.js‘></script> # $.cookie("list_pager_num", 30,{ path: ‘/‘ });
9.5session知识点:
Django中默认支持Session,其内部提供了5种类型的Session供开发者使用:
1、数据库Session(默认)
Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_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") ...
2、缓存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. 使用 同上
3、文件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. 使用 同上
4、缓存+数据库Session
数据库用于做持久化,缓存用于提高效率 a. 配置 settings.py SESSION_ENGINE = ‘django.contrib.sessions.backends.cached_db‘ # 引擎 b. 使用 同上
5、加密cookie Session
a. 配置 settings.py SESSION_ENGINE = ‘django.contrib.sessions.backends.signed_cookies‘ # 引擎 b. 使用 同上
扩展:Session用户验证
def login(func): def wrap(request, *args, **kwargs): # 如果未登陆,跳转到指定页面 if request.path == ‘/test/‘: return redirect(‘http://www.baidu.com‘) return func(request, *args, **kwargs) return wrap
十、Django的用户认证
10.1认证登录
from django.contrib import auth
django.contrib.auth中提供了许多方法,这里主要介绍其中的三个:
10.1.1 authenticate()
提供了用户认证,即验证用户名以及密码是否正确,一般需要username password两个关键字参数 如果认证信息有效,会返回一个 User 对象。authenticate()会在User 对象上设置一个属性标识那种认证后端认证了该用户,且该信息在后面的登录过程中是需要的。当我们试图登陆一个从数据库中直接取出来不经过authenticate()的User对象会报错的!! user=authenticate(username=‘someone‘,password=‘somepassword‘)
10.1.2 login(HttpRequest, user)
该函数接受一个HttpRequest对象,以及一个认证了的User对象 此函数使用django的session框架给某个已认证的用户附加上session id等信息。 from django.contrib.auth import authenticate, login def my_view(request): username = request.POST[‘username‘] password = request.POST[‘password‘] user = authenticate(username=username, password=password) if user is not None: login(request, user) # Redirect to a success page. ... else: # Return an ‘invalid login‘ error message. ...
10.1.3 logout(request) 注销用户
from django.contrib.auth import logout def logout_view(request): logout(request) # Redirect to a success page. 该函数接受一个HttpRequest对象,无返回值。当调用该函数时,当前请求的session信息会全部清除。该用户即使没有登录,使用该函数也不会报错
10.1.4 user对象的 is_authenticated()
要求:
1 用户登陆后才能访问某些页面, 2 如果用户没有登录就访问该页面的话直接跳到登录页面 3 用户在跳转的登陆界面中完成登陆后,自动访问跳转到之前访问的地址
方法1:
def my_view(request): if not request.user.is_authenticated(): return redirect(‘%s?next=%s‘ % (settings.LOGIN_URL, request.path))
方法2:login_required函数
django已经为我们设计好了一个用于此种情况的装饰器:login_requierd()
from django.contrib.auth.decorators import login_required @login_required def my_view(request): ...
若用户没有登录,则会跳转到django默认的 登录URL ‘/accounts/login/ ‘ (这个值可以在settings文件中通过LOGIN_URL进行修改)。并传递 当前访问url的绝对路径 (登陆成功后,会重定向到该路径)。
+++++++++++++++++++
10.2 User对象
User 对象属性:username, password(必填项)password用哈希算法保存到数据库
is_staff : 用户是否拥有网站的管理权限.
is_active : 是否允许用户登录, 设置为``False``,可以不用删除用户来禁止 用户登录
10.3 User 对象方法
10.3.1 is_authenticated()
如果是真正的 User 对象,返回值恒为 True 。 用于检查用户是否已经通过了认证。
通过认证并不意味着用户拥有任何权限,甚至也不检查该用户是否处于激活状态,这只是表明用户成功的通过了认证。
这个方法很重要, 在后台用request.user.is_authenticated()判断用户是否已经登录,如果true则可以向前台展示request.user.name
10.3.2 创建用户
使用 create_user 辅助函数创建用户: from django.contrib.auth.models import User user = User.objects.create_user(username=‘‘,password=‘‘,email=‘‘)
10.3.3 set_password(passwd)
这个方法是用来更改密码的,使用步骤: user=User.objects.get(username=‘‘) user.set_password(passeord=‘‘) user.save
10.3.4 check_password(passwd)
用户需要修改密码的时候 首先要让他输入原来的密码 ,如果给定的字符串通过了密码检查,返回 True
10.3.5 修改密码
使用 set_password() 来修改密码 user = User.objects.get(username=‘‘) user.set_password(password=‘‘) user.save
示例:注册
def sign_up(request): state = None if request.method == ‘POST‘: password = request.POST.get(‘password‘, ‘‘) repeat_password = request.POST.get(‘repeat_password‘, ‘‘) email=request.POST.get(‘email‘, ‘‘) if password == ‘‘ or repeat_password == ‘‘: state = ‘empty‘ elif password != repeat_password: state = ‘repeat_error‘ else: username = request.POST.get(‘username‘, ‘‘) if User.objects.filter(username=username): state = ‘user_exist‘ else: new_user = User.objects.create_user(username=username, password=password,email=email) new_user.save() new_my_user = MyUser(user=new_user, telephone=request.POST.get(‘telephone‘, ‘‘)) new_my_user.save() return redirect(‘/book/‘) content = { ‘state‘: state, ‘user‘: None, } return render(request, ‘book/sign_up.html‘, content)
示例:改密码
@login_required def set_password(request): user = request.user state = None if request.method == ‘POST‘: old_password = request.POST.get(‘old_password‘, ‘‘) new_password = request.POST.get(‘new_password‘, ‘‘) repeat_password = request.POST.get(‘repeat_password‘, ‘‘) if user.check_password(old_password): if not new_password: state = ‘empty‘ elif new_password != repeat_password: state = ‘repeat_error‘ else: user.set_password(new_password) user.save() return redirect("/log_in/") else: state = ‘password_error‘ content = { ‘user‘: user, ‘state‘: state, } return render(request, ‘book/set_password.html‘, content)
十一、Form与ModelForm
11.1 From
Django会将表单的提交变得更加简单和安全,包括重构数据后在页面间传递,创建前端的HTML页面以及接收和处理客户端传来的数据。实施上,你只需要事先定义好form表单的各种属性,在前端页面简单调用即可。当然,Django为Form提供了许多属性,方便自定义,甚至你可以重写其中的一些方法。
应用:使用注册表完成验证并注册
1、urls.py
urlpatterns = [ url(r‘^admin/‘, admin.site.urls), url(r‘^register/‘, views.register), ]
2、models.py
from django.db import models from django.contrib.auth.models import AbstractUser class UserInfo(AbstractUser): """ 用户信息 """ nid = models.BigAutoField(primary_key=True) nickname = models.CharField(verbose_name=‘昵称‘, max_length=32) telephone = models.CharField(max_length=11, blank=True, null=True, unique=True, verbose_name=‘手机号码‘) avatar = models.FileField(verbose_name=‘头像‘, upload_to=‘upload/avatar/‘,default="/upload/avatar/default_avatar.jpg") create_time = models.DateTimeField(verbose_name=‘创建时间‘,auto_now_add=True) fans = models.ManyToManyField(verbose_name=‘粉丝们‘, to=‘UserInfo‘, through=‘UserFans‘, through_fields=(‘user‘, ‘follower‘)) def __str__(self): return self.username
3、在app 目录下新建 form.py
from django import forms from django.core.exceptions import NON_FIELD_ERRORS, ValidationError class RegForm(forms.Form): username=forms.CharField(min_length=2,error_messages={"required":"*用户名不能为空!","min_length":"*用户名太短!"}, widget=forms.TextInput(attrs={"id":"username","placeholder":"用户为2到12位数字或字母"})) password=forms.CharField(error_messages={"required":"*密码不能为空!"}, widget=forms.PasswordInput(attrs={"id":"passwordsignup","placeholder":"eg. 密码不能少于6位且不能为纯数字"})) repeat_password=forms.CharField(error_messages={"required":"*密码不能为空!"}, widget=forms.PasswordInput(attrs={"id":"passwordsignup_confirm","placeholder":"eg. 密码不能少于6位且不能为纯数字"})) email=forms.EmailField(error_messages={"required":"*邮箱不能为空!","invalid":"*邮箱格式不正确"}, widget=forms.EmailInput(attrs={"id":"emailsignup","placeholder":"[email protected]"})) validcode=forms.CharField(error_messages={"required":"*验证码不能为空!"}, widget=forms.TextInput(attrs={"class":"validcode_input","id":"validcode","placeholder":"valid_code"})) def __init__(self,request,*args,**kwargs): super(RegForm,self).__init__(*args,**kwargs) self.request=request def clean_username(self): # if self.cleaned_data["username"].isdigit() or self.cleaned_data["username"].isalpha(): # raise ValidationError("*用户名必须包含数字与字母!") # if len(self.cleaned_data["username"]) <2: # raise ValidationError("*用户名太短!") if len(self.cleaned_data["username"]) >12: raise ValidationError("*用户名太长!") else: return self.cleaned_data["username"] def clean_password(self): # 关于密码字段的钩子 if len(self.cleaned_data["password"]) <5: raise ValidationError("*密码不能少于6位!") elif self.cleaned_data["password"].isdigit(): raise ValidationError("*密码不能为纯数字!") else: return self.cleaned_data["password"] def clean_repeat_password(self): # 关于密码字段的钩子 if len(self.cleaned_data["repeat_password"]) < 5: raise ValidationError("*密码不能少于6位!") elif self.cleaned_data["repeat_password"].isdigit(): raise ValidationError("*密码不能为纯数字!") else: return self.cleaned_data["repeat_password"] def clean(self): if self.cleaned_data.get("password") == self.cleaned_data.get("repeat_password"): #self.cleaned_data.get("password") 与self.cleaned_data["password"] 的区别是后者取值是当值不存在时没有值会报错 return self.cleaned_data else: raise ValidationError("*密码不一致") def clean_validcode(self): if self.cleaned_data["validcode"].upper() == self.request.session["validcode"].upper(): return self.cleaned_data["validcode"] else: raise ValidationError("验证码错误!")
4、views.py
def register(request): if request.is_ajax(): data = {"tag": False, "error_message": ""} form_obj=forms.RegForm(request,request.POST) if form_obj.is_valid(): username=form_obj.cleaned_data["username"] email = form_obj.cleaned_data["email"] password = form_obj.cleaned_data["password"] repeat_password = form_obj.cleaned_data["repeat_password"] user_validcode = form_obj.cleaned_data["validcode"].upper() validcode = request.session[‘validcode‘].upper() file_obj = request.FILES.get("img") models.UserInfo.objects.create_user(username=username,email=email,password=password,avatar=file_obj) data["tag"]=True else: errors=form_obj.errors data["error_message"] = errors return HttpResponse(json.dumps(data)) form_obj=forms.RegForm(request) return render(request,"register.html",{"form_obj":form_obj})
5、register.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>添加个人信息</title> <style> .formset{ color: rebeccapurple; border: dashed cadetblue; } </style> </head> <body> <form action="/register/" method="post"> {% csrf_token %} <h1>博客园-注册</h1> <p> <label for="username" class="uname" data-icon="u">用户名</label> {{ form_obj.username }} <span id="username_error" class="ajax_errors"></span> </p> <p> <label for="emailsignup" class="youmail" data-icon="e"> 邮箱</label> {{ form_obj.email }} <span id="emailsignup_error" class="ajax_errors"></span> </p> <p> <label for="passwordsignup" class="youpasswd" data-icon="p">密码 </label> {{ form_obj.password }} <span id="passwordsignup_error" class="ajax_errors"></span> </p> <p> <label for="passwordsignup_confirm" class="youpasswd" data-icon="p">确认密码</label> {{ form_obj.repeat_password }} <span id="passwordsignup_confirm_error" class="ajax_errors"></span> </p > <p class="file_avatar"><label for="avatar" >头像</label> <img src="{% static ‘images/default_avatar.jpg‘ %}" alt="" id="file_img" class="sol"> <input type="file" id="file_choose" class="sol"></p> <p> <label for="validcode" class="validcode" data-icon="p" style="display: block"> 验证码 </label> {{ form_obj.validcode }} <span class="valid_img_box"> <img src="/validcode/" alt="" class="valid_img"> <span>看不清楚?</span> </span> </p> <p style="margin-bottom: 45px!important"> <spanp id="validcode_error" class="ajax_errors"></spanp> </p> <p class="signin button"> <input type="button" class="register_but" value="注册" style="float: left"/> <a href="/index/"><input type="button" value="返回"/></a> </p> <p class="change_link"> 已经有账号 ? <a href="/login/" class="to_register"> 去登录 </a> </p> </form> </body> </html>
11.2 ModelForm
11.2.1ModelForm参数和使用
ModelForm a. class Meta: model, # 对应Model的 fields=None, # 字段 exclude=None, # 排除字段 labels=None, # 提示信息 help_texts=None, # 帮助提示信息 widgets=None, # 自定义插件 error_messages=None, # 自定义错误信息(整体错误信息from django.core.exceptions import NON_FIELD_ERRORS) field_classes=None # 自定义字段类 (也可以自定义字段) localized_fields=(‘birth_date‘,) # 本地化,如:根据不同时区显示数据 如: 数据库中 2016-12-27 04:10:57 setting中的配置 TIME_ZONE = ‘Asia/Shanghai‘ USE_TZ = True 则显示: 2016-12-27 12:10:57 b. 验证执行过程 is_valid -> full_clean -> 钩子 -> 整体错误 c. 字典字段验证 def clean_字段名(self): # 可以抛出异常 # from django.core.exceptions import ValidationError return "新值" d. 用于验证 model_form_obj = XXOOModelForm() model_form_obj.is_valid() model_form_obj.errors.as_json() model_form_obj.clean() model_form_obj.cleaned_data e. 用于创建 model_form_obj = XXOOModelForm(request.POST) #### 页面显示,并提交 ##### # 默认保存多对多 obj = form.save(commit=True) # 不做任何操作,内部定义 save_m2m(用于保存多对多) obj = form.save(commit=False) obj.save() # 保存单表信息 obj.save_m2m() # 保存关联多对多信息 f. 用于更新和初始化 obj = model.tb.objects.get(id=1) model_form_obj = XXOOModelForm(request.POST,instance=obj) ... PS: 单纯初始化 model_form_obj = XXOOModelForm(initial={...})
11.2.2 通过ModelForm完成三张表格的数据新增:
1) 在app01目录下建立forms.py文件,今后将所有的form都写在这个文件中,这个文件需要在views.py中导入,方便导入相应的FORM
2) 创建ModelForm:
forms.py:
# -*- coding: UTF-8 -*- from django.forms import ModelForm from .models import Node,Line,Device #定义Node的Form,Form名字为 模式名+Form class NodeForm(ModelForm): #自定义ModelForm的内容 class Meta: #该ModelForm参照Model: Node model = Node #在Form中不显示node_signer这个字段 exclude = [‘node_signer‘] class LineForm(ModelForm): class Meta: model = Line exclude = [‘line_signer‘] class DeviceForm(ModelForm): class Meta: model = Device exclude = [‘device_signer‘]
建立url与view的关联关系
url(r‘^add/‘, echo.views.add),
在views.py中建立相应的函数
views.py:
# -*- coding: UTF-8 -*- from .models import Node,Line,Device from forms import NodeForm,LineForm,DeviceForm from django.shortcuts import render, redirect def add(request): #获取来自NodeForm的表单数据 form = NodeForm(request.POST or None) #判断form是否有效 if form.is_valid(): #创建实例,需要做些数据处理,暂不做保存 instance = form.save(commit=False) #将登录用户作为登记人 instance.node_signer = request.user #保存该实例 instance.save() #跳转至列表页面 return redirect(‘/lists/‘) #创建context来集中处理需要传递到页面的数据 context = { ‘form‘: form, } #如果没有有效提交,则仍留在原来页面 return render(request, ‘add.html‘, context)
在templates文件夹下建立HTML文件,add.html
add.html:
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <form method=‘POST‘ action=‘‘>{% csrf_token %} {{ form }} <input type=‘submit‘ value=‘提交‘ /> </form> </body> </html>
十二、分页
12.1分页器的使用
>>> from django.core.paginator import Paginator >>> objects = [‘john‘, ‘paul‘, ‘george‘, ‘ringo‘] >>> p = Paginator(objects, 2) >>> p.count #数据总数 4 >>> p.num_pages #总页数 2 >>> type(p.page_range) # `<type ‘rangeiterator‘>` in Python 2. <class ‘range_iterator‘> >>> p.page_range #页码的列表 range(1, 3) # =========[1,2] >>> page1 = p.page(1) #第1页的page对象 >>> page1 <Page 1 of 2> >>> page1.object_list #第1页的数据 [‘john‘, ‘paul‘] >>> page2 = p.page(2) >>> page2.object_list #第2页的数据 [‘george‘, ‘ringo‘] >>> page2.has_next() #是否有下一页 False >>> page2.has_previous() #是否有上一页 True >>> page2.has_other_pages() #是否有其他页 True >>> page2.next_page_number() #下一页的页码 Traceback (most recent call last): ... EmptyPage: That page contains no results >>> page2.previous_page_number() #上一页的页码 1 >>> page2.start_index() # 本页第一条记录的序数(从1开始) 3 >>> page2.end_index() # 本页最后录一条记录的序数(从1开始) 4 >>> p.page(0) #错误的页,抛出异常 Traceback (most recent call last): ... EmptyPage: That page number is less than 1 >>> p.page(3) #错误的页,抛出异常 Traceback (most recent call last): ... EmptyPage: That page contains no results
12.2实现一个分页效果
index.html
{% load staticfiles %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="{% static ‘bootstrap.css‘ %}"> </head> <body> <div class="container"> <h4>分页器</h4> <ul> {% for book in book_list %} <li>{{ book.title }} {{ book.price }}</li> {% endfor %} </ul> <ul class="pagination" id="pager"> {% if book_list.has_previous %} <li class="previous"><a href="/blog/?page={{ book_list.previous_page_number }}">上一页</a></li> {% else %} <li class="previous disabled"><a href="#">上一页</a></li> {% endif %} {% for num in paginator.page_range %} {% if num == currentPage %} <li class="item active"><a href="/blog/?page={{ num }}">{{ num }}</a></li> {% else %} <li class="item"><a href="/blog/?page={{ num }}">{{ num }}</a></li> {% endif %} {% endfor %} {% if book_list.has_next %} <li class="next"><a href="/blog/?page={{ book_list.next_page_number }}">下一页</a></li> {% else %} <li class="next disabled"><a href="#">下一页</a></li> {% endif %} </ul> </div> </body> </html>
views.py
from django.shortcuts import render,HttpResponse # Create your views here. from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from app01.models import * def index(request): ‘‘‘ 批量导入数据: Booklist=[] for i in range(100): Booklist.append(Book(title="book"+str(i),price=30+i*i)) Book.objects.bulk_create(Booklist) ‘‘‘ book_list=Book.objects.all() paginator = Paginator(book_list, 10) page = request.GET.get(‘page‘,1) currentPage=int(page) try: print(page) book_list = paginator.page(page) except PageNotAnInteger: book_list = paginator.page(1) except EmptyPage: book_list = paginator.page(paginator.num_pages) return render(request,"index.html",locals())
十三、缓存
由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5分钟内再有人来访问时,则不再去执行view中的操作,而是直接从内存或者Redis中之前缓存的内容拿到,并返回。
Django中提供了6种缓存方式:
开发调试 内存 文件 数据库 Memcache缓存(python-memcached模块) Memcache缓存(pylibmc模块)
1、配置
a、开发调试
# 此为开始调试用,实际内部不做任何操作 # 配置: 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‘ 函数名 # 生成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
b、内存
# 此缓存将内容保存至内存的变量中 # 配置: CACHES = { ‘default‘: { ‘BACKEND‘: ‘django.core.cache.backends.locmem.LocMemCache‘, ‘LOCATION‘: ‘unique-snowflake‘, } } # 注:其他配置同开发调试版本
c、文件
# 此缓存将内容保存至文件 # 配置: CACHES = { ‘default‘: { ‘BACKEND‘: ‘django.core.cache.backends.filebased.FileBasedCache‘, ‘LOCATION‘: ‘/var/tmp/django_cache‘, } } # 注:其他配置同开发调试版本
d、数据库
# 此缓存将内容保存至数据库 # 配置: CACHES = { ‘default‘: { ‘BACKEND‘: ‘django.core.cache.backends.db.DatabaseCache‘, ‘LOCATION‘: ‘my_cache_table‘, # 数据库表 } } # 注:执行创建表命令 python manage.py createcachetable
e、Memcache缓存(python-memcached模块)
# 此缓存使用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‘, ] } }
f、Memcache缓存(pylibmc模块)
# 此缓存使用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‘, ] } }
2、应用
a. 全站使用
使用中间件,经过一系列的认证等操作,如果内容在缓存中存在,则使用FetchFromCacheMiddleware获取内容并返回给用户,当返回给用户之前,判断缓存中是否已经存在,如果不存在则UpdateCacheMiddleware会将缓存保存至缓存,从而实现全站缓存 MIDDLEWARE = [ ‘django.middleware.cache.UpdateCacheMiddleware‘, # 其他中间件... ‘django.middleware.cache.FetchFromCacheMiddleware‘, ] CACHE_MIDDLEWARE_ALIAS = "" CACHE_MIDDLEWARE_SECONDS = "" CACHE_MIDDLEWARE_KEY_PREFIX = ""
b. 单独视图缓存
方式一: 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)), ]
c、局部视图使用
a. 引入TemplateTag {% load cache %} b. 使用缓存 {% cache 5000 缓存key %} 缓存内容 {% endcache %}
十四、信号
Django中提供了“信号调度”,用于在框架执行操作时解耦。通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者。
1、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 # 创建数据库连接时,自动触发
对于Django内置的信号,仅需注册指定信号,当程序执行相应操作时,自动触发注册函数:
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指上述导入的内容
from django.core.signals import request_finished from django.dispatch import receiver @receiver(request_finished) def my_callback(sender, **kwargs): print("Request finished!")
2、自定义信号
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)
由于内置信号的触发者已经集成到Django中,所以其会自动调用,而对于自定义信号则需要开发者在任意位置触发。
十五、序列化
序列化
在django中,在将数据库中检索的数据返回给客户端用户,数据类型为QuerySet格式,而QuerySet格式不能被json格式化处理传到前端,因此在处理此类数据时有两种方法:
方法一:使用django自带的系列化模块 serializers模块
1、serializers
from django.core import serializers ret = models.BookType.objects.all() data = serializers.serialize("json", ret)
注:1、serializers序列化后的数据格式为列表,列表为每一个查询记录
2、serializers模块不能跨表查询,涉及一对多查询时,只能查询到关联字段
方法二:查询时转换为QuerySet字典或列表格式
2、json.dumps
import json #ret = models.BookType.objects.all().values(‘caption‘) ret = models.BookType.objects.all().values_list(‘caption‘) ret=list(ret) #将QuerySet进行转化 result = json.dumps(ret)
以上是关于Django知识点汇总的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Django Summernote 中显示编程片段的代码块?
django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE的解决办法(转)(代码片段
django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE的解决办法(转)(代码片段