Django-admin startproject mysite --项目名称
启动 Django
python manage.py runserver 127.0.0.1:80 --启动IP地址,端口号(默认127.0.0.1:8000)
创建应用
python manage.py startapp app01
1.配置数据库
MySQL数据库首先需要安装驱动程序
pip install PyMySQL
在__init__.py包文件引入
from pymysql import install_as_MySQLdb
install_as_MySQLdb() # 让pymysql以MySQLDB的运行模式和Django的ORM对接
运行
修改
DATABASES配置信息
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'HOST': '127.0.0.1', # 数据库主机
'PORT': 3306, # 数据库端口
'USER': 'root', # 数据库用户名
'PASSWORD': '123', # 数据库用户密码
'NAME': 'student' # 数据库名字
}
}
在MySQL中创建数据库
create database student; # mysql8.0默认就是utf8mb4;
create database student default charset=utf8mb4; # mysql8.0之前的版本
注意3: 如果想打印orm转换过程中的sql,需要在settings中进行如下配置:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
读写分离多个操作多个数据库
https://www.cnblogs.com/shaoyishi/p/17038652.html
https://blog.csdn.net/weixin_44346972/article/details/127107886
https://www.jb51.net/article/248460.htm
6.3、数据迁移
将模型类定义表架构的代码转换成SQL同步到数据库中,这个过程就是数据迁移。django中的数据迁移,就是一个类,这个类提供了一系列的终端命令,帮我们完成数据迁移的工作。
(1)生成迁移文件
所谓的迁移文件, 是类似模型类的迁移类,主要是描述了数据表结构的类文件.
python manage.py makemigrations #student #student 就是你自己构建模块名称
(2)同步到数据库中
python manage.py migrate #student#student 就是你自己构建模块名称
补充:在django内部提供了一系列的功能,这些功能也会使用到数据库,所以在项目搭建以后第一次数据迁移的时候,会看到django项目中其他的数据表被创建了。其中就有一个django内置的admin站点管理。
1.可以使用引入JsonResponse 直接返回json数据
(注意如果返回列表类型数据需要改变 JsonResponse 的参数 safe=False )
from django.http import JsonResponse
#来序列号json类型数据
def jsoss(request):
# book = {'title': '金苹果吗', 'price': 199}
books = [{'title': '金苹果吗', 'price': 199},{'title': '水浒传', 'price': 299}]
return JsonResponse(books,json_dumps_params={'ensure_ascii': False}, safe=False,charset='utf-8')
静态文件配置修改
STATIC_URL = ‘/static/’ # 别名
X_FRAME_OPTIONS = ‘ALLOWALL’
STATIC_ROOT = BASE_DIR / ‘static’
STATICFILES_DIRS = [BASE_DIR / ‘static’, r"N:\phpstudy_pro\pythonLixi\commerce_pro\commerce_html\admin\dist", ]
STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR,'static') ]
跨域允许
ALLOWED_HOSTS = ['*']
Django的POST请求报403,及四种解决方法
发布于2018-10-10 10:15:39阅读 11.8K0
Django默认开启防止csrf(跨站点请求伪造)攻击,在post请求时,没有上传 csrf字段,导致校验失败,报403错误
解决方法1:
注释掉此段代码,即可。
缺点:导致Django项目完全无法防止csrf攻击
解决方法2:
在 views.py文件中
#导入,可以使此次请求忽略csrf校验
from django.views.decorators.csrf import csrf_exempt
#在处理函数加此装饰器即可
@csrf_exempt
def post(request):
name=request.post['name']
return HttpResponse('welcome!{}'.format(name))
.请求方式 POST
def show(request):
# print("moblie", m, type(m))
#print(request.method)
print(request.body) #获取json 格式
user = request.POST.get('user') # 获取 urlenceded
pwd = request.POST.get('pwd')
qq = request.POST.getlist('qq')
return HttpResponse("hi用户 {} \n密码 {} \nQQ: {}".format(user,pwd,qq))
请求方式 GET
#获取请求路径
获取全部get 请求数据
request.GET()
request.GET.get()
request.path
request.get_full_path()
print(request.path) # /users
print(request.get_full_path()) # /users?a=1
获取请求头
# 获取请求头数据
# print(request.META)
# print(request.META.get("HTTP_HOST"))
# print(request.META.get("HTTP_XXX"))
三、利用[field.verbose_name]增加针对mysql字段注释的处理
修改django/db/backends/base/schema.py 文件,column_sql 函数,如下:
步骤一:找到Python按照根目录;如:
D:\python\Python38-32
步骤二:找到需要修改的文件;如:
D:\python\Python38-32\Lib\site-packages\django\db\backends\base\schema.py
步骤三:找到 column_sql 函数 的结尾处,大概 256 行,如下修改:
利用[field.verbose_name]增加针对mysql字段注释的处理
if self.connection.client.executable_name =='mysql' and field.verbose_name:
sql +=" COMMENT '%s'" % field.verbose_name
Return the sql
模板替换语法 (深度查询)
什么.什么.查找模板中的变量即可
from django.shortcuts import render, HttpResponse
# from django.template.loader import get_template
class book(object):
def __init__(self, name, price):
self.name = name
self.price = price
def __str__(self):
return "书记名称: {} 价钱: {}".format(self.name, self.price)
# Create your views here.
def index(request):
name = '立下了'
age = 28
# 是否结婚
Married = False
shendu = '深度查询'
book_list = ['三国', '水浒', '西游', '红楼']
zhangsan = {'name': "张三", "age": 39, 'occupation': '罪犯'}
resbook0 = book('三体', 299)
resbook1 = book('乱', 299)
resbook2 = book('红粉佳人', 299)
resbook3 = book('无敌卡', 299)
books = [resbook0,resbook1,resbook2,resbook3]
return render(request, 'get_template.html', locals())
什么.什么.查找模板中的变量即可
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>获取模板文件</title>
<style >
span{
display: inline-block;
margin-bottom:18px ;
}
</style>
</head>
<body>
<h1>{{ shendu }}</h1>
姓名:<span style="color: #0a53be">{{ name }}</span><br>
年龄:<span style="color: #37be0a">{{ age }}</span><br>
婚否:<span style="color: #be0a55">{{ Married }}</span><br>
四大名著:<span style="color: #000000">{{ book_list }}</span><br>
第二本名著:<span style="color: #000000">{{ book_list.1 }}</span><br>
法外狂赌{{zhangsan.name}}:<span style="color: #000000">他的年龄:{{ zhangsan.age }}</span> <span style="color: #000000">他的职业:{{ zhangsan.occupation }}</span><br>
</body>
<h2>书籍名称 {{ resbook.name }}</h2>
<div>
{{ resbook.age }}
</div>
<!-- 最最查询方法 -->
<div>{{ books.2.price }} </div>
</html>
如果仍然无法获得代码提示,则可以尝试强制PyCharm重新加载项目缓存。在PyCharm中,选择“File”->“Invalidate Caches / Restart”,然后选择“Invalidate and Restart”。
5.3.2、变量渲染之内置过滤器
内置过滤器
过滤器用法代码last获取列表/元组的最后一个成员{{liast | last}}first获取列表/元组的第一个成员{{list|first}}length获取数据的长度{{list | length}}defualt当变量没有值的情况下, 系统输出默认值,{{str|default=“默认值”}}safe让系统不要对内容中的html代码进行实体转义{{htmlcontent| safe}}upper字母转换成大写{{str | upper}}lower字母转换成小写{{str | lower}}title每个单词首字母转换成大写{{str | title}}date日期时间格式转换{{ value| date:“D d M Y” }}cut从内容中截取掉同样字符的内容{{content | cut:“hello”}}list把内容转换成列表格式{{content | list}}add加法{{num| add}}filesizeformat把文件大小的数值转换成单位表示{{filesize | filesizeformat}}join按指定字符拼接内容{{list| join(“-”)}}random随机提取某个成员{list | random}}slice按切片提取成员{{list | slice:“:-2”}}truncatechars按字符长度截取内容{{content | truncatechars:30}}truncatewords按单词长度截取内容同上
5.3.4、标签
(1)if 标签
{% if age > 18 %}
<p>成年电影 </p>
{% else %}
<p>为成年电影</p>
{% endif %}
在 Django 模板中,可以使用嵌套的 {% if %} 标签来实现逻辑判断。嵌套的 {% if %} 标签需要注意缩进和正确的语法,以下是一个示例:
{% if condition1 %}
{% if condition2 %}
... some content ...
{% endif %}
{% endif %}
(2)for标签
{% for student in student_list %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ student.name }}</td>
<td>{{ student.age }}</td>
<td>{{ student.get_sex_display }}</td>
<td>{{ student.birthday|date:'Y-m-d' }}</td>
<td>{{ student.clas.name }}</td>
<td>
{% if student.courses.all %}
{% for course in student.courses.all %}
<button class="btn btn-sm btn-success">{{ course.title }}</button>
{% endfor %}
{% else %}
<button class="btn btn-sm btn-success">暂时没有任何选修</button>
{% endif %}
</td>
<td>
<a class="btn-sm btn-warning" href="/student/edit/{{ student.pk }}">编辑</a>
<a class="btn-sm btn-danger" href="/student/delete/{{ student.pk }}">删除</a>
</td>
</tr>
{% endfor %}
{% for i in book_list %}
<ul>
<li style="list-style: none">{{ i }}</li>
</ul>
{% endfor %}
<table width="800" border="1">
<tr>
<th>序号</th>
<th>书籍名称</th>
<th>价格</th>
<th>出版社</th>
</tr>
{% for t in books %}
<tr>
<th>{{ forloop.counter }}</th>
<th>{{ t.name }}</th>
<th>{{ t.price }}</th>
<th>{{ t.press }}</th>
</tr>
{% endfor %}
模板嵌套继承
传统的模板分离技术,依靠{% include "模板文件名"%}实现,这种方式,虽然达到了页面代码复用的效果,但是由此也会带来大量的碎片化模板,导致维护模板的成本上升.因此, Django框架中除了提供这种模板分离技术以外,还并行的提供了 模板继承给开发者.
{% include "模板文件名"%} # 模板嵌入
{% extends "base.html" %} # 模板继承
1.include
{% include 'ad.html' %}
2.extends
{% extends 'base.html' %}
{% block title %}
<title>订单</title>
{% endblock title %}
{% block content %}
{{ block.super }}
<h3>我的订单</h3>
<ul>
{% for foo in order_list %}
<li>{{ foo }}</li>
{% endfor %}
</ul>
{% include 'ad.html' %}
{% endblock content %}
ORM
在models.py 文件中定义模型类。
from django.db import models
from datetime import datetime
模型类必须要直接或者间接继承于 models.Model
class BaseModel(models.Model):
"""公共模型[公共方法和公共字段]"""
# created_time = models.IntegerField(default=0, verbose_name="创建时间")
created_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
# auto_now_add 当数据添加时设置当前时间为默认值
# auto_now= 当数据添加/更新时, 设置当前时间为默认值
updated_time = models.DateTimeField(auto_now=True)
class Meta(object):
abstract = True # 设置当前模型为抽象模型, 当系统运行时, 不会认为这是一个数据表对应的模型.
class Student(BaseModel):
"""Student模型类"""
#1. 字段[数据库表字段对应]
SEX_CHOICES = (
(0,"女"),
(1,"男"),
(2,"保密"),
)
# 字段名 = models.数据类型(约束选项1,约束选项2, verbose_name="注释")
# SQL: id bigint primary_key auto_increment not null comment="主键",
# id = models.AutoField(primary_key=True, null=False, verbose_name="主键") # django会自动在创建数据表的时候生成id主键/还设置了一个调用别名 pk
# SQL: name varchar(20) not null comment="姓名"
# SQL: key(name),
name = models.CharField(max_length=20, db_index=True, verbose_name="姓名" )
# SQL: age smallint not null comment="年龄"
age = models.SmallIntegerField(verbose_name="年龄")
# SQL: sex tinyint not null comment="性别"
# sex = models.BooleanField(verbose_name="性别")
sex = models.SmallIntegerField(choices=SEX_CHOICES, default=2)
# SQL: class varchar(5) not null comment="班级"
# SQL: key(class)
classmate = models.CharField(db_column="class", max_length=5, db_index=True, verbose_name="班级")
# SQL: description longtext default "" not null comment="个性签名"
description = models.TextField(default="", verbose_name="个性签名")
#2. 数据表结构信息
class Meta:
db_table = 'tb_student' # 指明数据库表名,如果没有指定表明,则默认为子应用目录名_模型名称,例如: users_student
verbose_name = '学生信息表' # 在admin站点中显示的名称
verbose_name_plural = verbose_name # 显示的复数名称
#3. 自定义数据库操作方法
def __str__(self):
"""定义每个数据对象的显示信息"""
return "<User %s>" % self.name
(1) 数据库表名
模型类如果未指明表名db_table,Django默认以 小写app应用名_小写模型类名 为数据库表名。
可通过db_table 指明数据库表名。
(2) 关于主键
django会为表创建自动增长的主键列,每个模型只能有一个主键列。
如果使用选项设置某个字段的约束属性为主键列(primary_key)后,django不会再创建自动增长的主键列。
class Student(models.Model):
# django会自动在创建数据表的时候生成id主键/还设置了一个调用别名 pk
id = models.AutoField(primary_key=True, null=False, verbose_name=“主键”) # 设置主键
默认创建的主键列属性为id,可以使用pk代替,pk全拼为primary key。
(3) 属性命名限制
不能是python的保留关键字。
不允许使用连续的2个下划线,这是由django的查询方式决定的。__ 是关键字来的,不能使用!!!
定义属性时需要指定字段类型,通过字段类型的参数指定选项,语法如下:
属性名 = models.字段类型(约束选项, verbose_name=“注释”)
(4)字段类型
类型说明AutoField自动增长的IntegerField,通常不用指定,不指定时Django会自动创建属性名为id的自动增长属性BooleanField布尔字段,值为True或FalseNullBooleanField支持Null、True、False三种值CharField字符串,参数max_length表示最大字符个数,对应mysql中的varcharTextField大文本字段,一般大段文本(超过4000个字符)才使用。IntegerField整数DecimalField十进制浮点数, 参数max_digits表示总位数, 参数decimal_places表示小数位数,常用于表示分数和价格 Decimal(max_digits=7, decimal_places=2) ==> 99999.99~ 0.00FloatField浮点数DateField日期
参数auto_now表示每次保存对象时,自动设置该字段为当前时间。
参数auto_now_add表示当对象第一次被创建时自动设置当前。
参数auto_now_add和auto_now是相互排斥的,一起使用会发生错误。TimeField时间,参数同DateFieldDateTimeField日期时间,参数同DateFieldFileField上传文件字段,django在文件字段中内置了文件上传保存类, django可以通过模型的字段存储自动保存上传文件, 但是, 在数据库中本质上保存的仅仅是文件在项目中的存储路径!!ImageField继承于FileField,对上传的内容进行校验,确保是有效的图片
(5)约束选项
选项说明null如果为True,表示允许为空,默认值是False。相当于python的Noneblank如果为True,则该字段允许为空白,默认值是False。 相当于python的空字符串,“”db_column字段的名称,如果未指定,则使用属性的名称。db_index若值为True, 则在表中会为此字段创建索引,默认值是False。 相当于SQL语句中的keydefault默认值,当不填写数据时,使用该选项的值作为数据的默认值。primary_key如果为True,则该字段会成为模型的主键,默认值是False,一般不用设置,系统默认设置。unique如果为True,则该字段在表中必须有唯一值,默认值是False。相当于SQL语句中的unique
注意:null是数据库范畴的概念,blank是表单验证范畴的
(6) 外键
在设置外键时,需要通过on_delete选项指明主表删除数据时,对于外键引用表数据如何处理,在django.db.models中包含了可选常量:
CASCADE
级联,删除主表数据时连通一起删除外键表中数据
PROTECT
保护,通过抛出ProtectedError异常,来阻止删除主表中被外键应用的数据
SET_NULL
设置为NULL,仅在该字段null=True允许为null时可用
SET_DEFAULT
设置为默认值,仅在该字段设置了默认值时可用
SET()
设置为特定值或者调用特定方法,例如:
from django.conf import settings
from django.contrib.auth import get_user_model
from django.db import models
def get_sentinel_user():
return get_user_model().objects.get_or_create(username='deleted')[0]
class UserModel(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET(get_sentinel_user),
)
# 一对多
# on_delete= 关联关系的设置
# models.CASCADE 删除主键以后, 对应的外键所在数据也被删除
# models.DO_NOTHING 删除主键以后, 对应的外键不做任何修改
# 反向查找字段 related_name
clas = models.ForeignKey(to='clas',related_name='claslit', on_delete=models.CASCADE,db_constraint=False)
# 多对多
# 建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表
courses = models.ManyToManyField("Course",related_name='claslit', db_table="db_student2course",db_constraint=False)
# 一对一,使用同一对多
stu_detail = models.OneToOneField("StudentDetail",related_name='claslit', on_delete=models.CASCADE,db_constraint=False)
模糊查询
def select_student2(requset):
# data=MyHeadline.objects.filter(name__contains='个').values('name')
# data = Student.objects.filter(name__contains='李').values('id', 'name', 'age')
data = Student.objects.filter(age__gt=22).values('id', 'name', 'age').order_by('-id')
return Jsonbases(data)
8.1.1.自定义中间件
(1)定义中间件
创建存放自定义中间件的文件这里选择在app01里创建mdws.py文件:
from django.utils.deprecation import MiddlewareMixin
class Md1(MiddlewareMixin):
def process_request(self, request):
print("Md1请求")
# return HttpResponse("Md1中断") # 拦截
def process_response(self, request, response):
print("Md1返回")
return response
class Md2(MiddlewareMixin):
def process_request(self, request):
print("Md2请求")
# return HttpResponse("Md2中断")
def process_response(self, request, response):
print("Md2返回")
return response
process_request默认返回None,返回None,则继续执行下一个中间件的process_request;一旦返回响应体对象,则会拦截返回。process_response必须有一个形参response,并return response;这是view函数返回的响应体,像接力棒一样传承给最后的客户端。
Django 存取cookie
取cookie
request.get_signed_cookie('islogin', salt=你的密钥)
def index(request):
try:
res_islogin = request.get_signed_cookie('islogin', salt=ORM2.settings.SAIT)
if res_islogin:
userid = request.get_signed_cookie('userid',salt=ORM2.settings.SAIT)
student_list = Student.objects.filter(isdel=0).all()
stuuser = Student.objects.get(id=userid)
# data = [{'name': i.courses} for i in student_list]
# print(data)
return render(request, 'xinliu/html/ltr/index.html',
{'student_list': student_list, 'stuusername': stuuser.name})
# return render(request, 'student/index.html', {'student_list': student_list})
else:
return redirect(to='/student/login')
except Exception as e:
return redirect(to='/student/login')
存
res_islogin.set_signed_cookie(‘islogin’, “true”,max_age=’失效时间‘,salt=’你的密钥‘)
max_age参数用于设置cookie的最大有效期(以秒为单位)
def login(request):
exampleModal = ''
if request.method == 'POST':
data = request.POST.dict()
user = data['username']
# data = json.loads(data)
try:
resstu = Student.objects.get(name=user)
res_islogin = HttpResponseRedirect('/student/')
res_islogin.set_signed_cookie('islogin', "true",max_age=30,salt=ORM2.settings.SAIT)
res_islogin.set_signed_cookie('userid', resstu.id,max_age=30,salt=ORM2.settings.SAIT)
return res_islogin
except Exception as e:
exampleModal = 2
# return Jsonbases(data)
return render(request, 'xinliu/html/ltr/login/login-9.html', {'exampleModal': exampleModal})
Django 存取session
session写入
request.session["last_time"] = now
def shop(request):
last_time = request.session.get("last_time")
now = datetime.datetime.now().strftime("%Y-%m-%d %X")
request.session["last_time"] = now
return render(request, "shop.html", {"last_time": last_time})
读session
def s_index(request):
# 读session
is_login = request.session.get("is_login")
if is_login:
username = request.session.get("username")
return render(request, "index.html", {"user": username})
else:
return redirect("/s_login/")
del request.session["last_time"]
(3)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,
默认修改之后才保存(默认)
使用特殊装饰完成数据库事务
以下是一个使用
atomic()装饰器来打开事务的示例代码:
from django.db import transaction
@transaction.atomic
def my_view(request):
# 在这里执行数据库操作
8.2.3、用户认证组件
Django默认已经提供了认证系统Auth模块,我们认证的时候,会使用auth模块里面给我们提供的表。认证系统包含:
用户管理
权限
用户组
密码哈希系统
用户登录或内容显示的表单和视图
一个可插拔的后台系统 admin
(1)Django用户模型类
Django认证系统中提供了用户模型类User保存用户的数据,默认的User包含以下常见的基本字段:
字段名字段描述username必选。150个字符以内。 用户名可能包含字母数字,_,@,+ . 和-个字符。first_name可选(blank=True)。 少于等于30个字符。last_name可选(blank=True)。 少于等于30个字符。email可选(blank=True)。 邮箱地址。password必选。 密码的哈希加密串。 (Django 不保存原始密码)。 原始密码可以无限长而且可以包含任意字符。groups与Group 之间的多对多关系。user_permissions与Permission 之间的多对多关系。is_staff布尔值。 设置用户是否可以访问Admin 站点。is_active布尔值。 指示用户的账号是否激活。 它不是用来控制用户是否能够登录,而是描述一种帐号的使用状态。is_superuser是否是超级用户。超级用户具有所有权限。last_login用户最后一次登录的时间。date_joined账户创建的时间。 当账号创建时,默认设置为当前的date/time。
上面缺少一些字段,所以后面我们会对当前内置的用户模型进行改造,比如说它里面没有手机号字段,后面我们需要加上。
(2)重要方法
Django 用户认证(Auth)组件需要导入 auth 模块
认证模块
from django.contrib import auth
对应数据库用户表,可以继承扩展
from django.contrib.auth.models import User
(1)用户对象
create() # 创建一个普通用户,密码是明文的。
create_user() # 创建一个普通用户,密码是密文的。
User.objects.create_user(username='wang', password='1234')
create_superuser() # 与create_user() 相同,但是设置is_staff 和is_superuser 为True。
User.objects.create_superuser(username='wang', password='1234')
User.objects.set_password(*raw_password*)
设置用户的密码为给定的原始字符串,并负责密码的。 不会保存User对象。当None为raw_password时,密码将设置为一个不可用的密码。
User.objects.check_password(*raw_password*)
如果给定的raw_password是用户的真实密码,则返回True,可以在校验用户密码时使用。
(2)认证方法
auth.authenticate(username,password)
将输入的密码转为密文去认证,认证成功返回用户对象,失败则返回None
(3)登录和注销方法
from django.contrib import auth
该函数接受一个HttpRequest对象,以及一个认证了的User对象。此函数使用django的session框架给某个已认证的用户附加上session id等信息。
auth.login()
该函数接受一个HttpRequest对象,无返回值。当调用该函数时,当前请求的session信息会全部清除。该用户即使没有登录,使用该函数也不会报错。
auth.logout()
(4)request.user
Django有一个默认中间件,叫做AuthenticationMiddleware,每次请求进来都会去session中去一个userid,取不到的话,赋值request.user = AnonymousUser() , 一个匿名用户对象。
当用户组件auth.login一旦执行,将userid到session中后,再有请求进入Django,将注册的userid对应的user对象赋值给request.user,即再后面的任何视图函数中都可以从request.user中取到该客户端的登录对象。
(5)自定义用户表
from django.contrib.auth.models import AbstractUser设置Auth认证模块使用的用户模型为我们自己定义的用户模型格式:“子应用目录名.模型类名”AUTH_USER_MODEL = ‘users.User’
8.3、Django的分页器
from django.core.paginator import Paginator
(1) index视图
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)
print("count:",paginator.count) #数据总数
print("num_pages",paginator.num_pages) #总页数
print("page_range",paginator.page_range) #页码的列表
page1=paginator.page(1) # 第1页的page对象
for i in page1: # 遍历第1页的所有数据对象
print(i)
print(page1.object_list) #第1页的所有数据
page2=paginator.page(2)
print(page2.has_next()) #是否有下一页
print(page2.next_page_number()) #下一页的页码
print(page2.has_previous()) #是否有上一页
print(page2.previous_page_number()) #上一页的页码
# 抛错
#page=paginator.page(12) # error:EmptyPage
#page=paginator.page("z") # error:PageNotAnInteger
'''
book_list = Book.objects.all()
paginator = Paginator(book_list, 10)
page = request.GET.get('page', 1)
current_page = 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", {"book_list": book_list, "paginator": paginator, "currentPage": current_page})
(2) index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</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="/index/?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="/index/?page={{ num }}">{{ num }}</a></li>
{% else %}
<li class="item"><a href="/index/?page={{ num }}">{{ num }}</a></li>
{% endif %}
{% endfor %}
{% if book_list.has_next %}
<li class="next"><a href="/index/?page={{ book_list.next_page_number }}">下一页</a></li>
{% else %}
<li class="next disabled"><a href="#">下一页</a></li>
{% endif %}
</ul>
</div>
</body>
</html>
from django.core.paginator import Paginator
from django.shortcuts import render
def my_view(request):
获取数据列表
data_list = MyModel.objects.all()
初始化分页器
paginator = Paginator(data_list, 10) # 每页显示10条数据
获取当前页面号码
page_number = request.GET.get('page')
获取当前页面的数据对象
page_obj = paginator.get_page(page_number)
渲染分页器网页
return render(request, 'my_template.html', {'page_obj': page_obj})
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Django Bootstrap 3分页器</title>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<div class="container">
<h1>分页数据列表</h1>
{% if page_obj.has_other_pages %}
<nav aria-label="Page navigation">
<ul class="pagination">
{% if page_obj.has_previous %}
<li>
<a href="?page={{ page_obj.previous_page_number }}" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{% endif %}
{% for i in page_obj.paginator.page_range %}
{% if page_obj.number == i %}
<li class="active"><a href="#">{{ i }} <span class="sr-only">(current)</span></a></li>
{% else %}
<li><a href="?page={{ i }}">{{ i }}</a></li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li>
<a href="?page={{ page_obj.next_page_number }}" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>名称</th>
<th>年龄</th>
</tr>
</thead>
<tbody>
{% for obj in page_obj %}
<tr>
<td>{{ obj.id }}</td>
<td>{{ obj.name }}</td>
<td>{{ obj.age }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
分页接口
from django.core.paginator import Paginator
from django.http import JsonResponse
def my_view(request):
获取数据列表
data_list = MyModel.objects.all()
初始化分页器
paginator = Paginator(data_list, 10) # 每页显示10条数据
获取当前页面号码
page_number = request.GET.get(‘page’)
获取当前页面的数据对象
page_obj = paginator.get_page(page_number)
将页面数据转换为JSON对象
page_data = {
“current_page”: page_obj.number,
“total_pages”: paginator.num_pages,
“data”: [
{“id”: obj.id, “name”: obj.name, “age”: obj.age} for obj in page_obj
]
}
返回JSON响应
return JsonResponse(page_data)
8.4.3、RESTful API规范
RESTful是一种专门为Web 开发而定义API接口的设计风格,尤其适用于前后端分离的应用模式中。
这种风格的理念认为后端开发任务就是提供数据的,对外提供的是数据资源的访问接口,所以在定义接口时,客户端访问的URL路径就表示这种要操作的数据资源。
而对于数据资源分别使用POST、DELETE、GET、UPDATE等请求动作来表达对数据的增删查改。
POST http://www.xxx.com/api/students/ 添加学生数据
GET http://www.xxx.com/api/students/ 获取所有学生
GET http://www.xxx.com/api/students/1/ 获取id=pk的学生
DELETE http://www.xxx.com/api/students/1/ 删除id=pk的一个学生
PUT http://www.xxx.com/api/students/1/ 修改一个学生的全部信息 [id,name,sex,age,]
PATCH http://www.xxx.com/api/students/1/ 修改一个学生的部分信息[age]
而对于数据资源分别使用POST、DELETE、GET、UPDATE等请求动作来表达对数据的增删查改。
GET/students获取所有学生请求方法请求地址后端操作POST/students增加学生GET/students/获取编号为pk的学生PUT/students/修改编号为pk的学生DELETE/students/删除编号为pk的学生
restful规范是一种通用的规范,不限制语言和开发框架的使用。事实上,我们可以使用任何一门语言,任何一个框架都可以实现符合restful规范的API接口。
参考文档:http://www.runoob.com/w3cnote/restful-architecture.html
接口实现过程中,会存在幂等性。所谓幂等性是指代客户端发起多次同样请求时,是否对于服务端里面的资源产生不同结果。如果多次请求,服务端结果还是一样,则属于幂等接口,如果多次请求,服务端产生结果是不一样的,则属于非幂等接口。
请求方式是否幂等是否安全GET幂等安全POST不幂等不安全PUT/PATCH幂等不安全DELETE幂等不安全
8.4、FBV与CBV
8.4.4、CBV使用
FBV模式
path(‘index/’, views.index),
CBV模式
path(“index/”,views.IndexView.as_view()),
path(“books/”,views.BookView.as_view())
import inspect
from django.core import serializers
class cbcview(View):
def __init__(self):
self.init = str(inspect.currentframe().f_code.co_name).upper()
def handle_request(self, method):
return HttpResponse('CBV ' + str(method.__name__).upper())
def get(self, request):
stu= Student.objects.all()
seriali = serializers
resjson=seriali.serialize('json',stu)
return HttpResponse(resjson,content_type='json')
def post(self, request):
return self.handle_request(self.post)
def delete(self, requset):
return self.handle_request(self.delete)
8.6、ORM进阶
8.6.1、queryset特性
(1)可切片
使用Python 的切片语法来限制查询集记录的数目 。它等同于SQL 的LIMIT 和OFFSET 子句。
Article.objects.all()[:5] # (LIMIT 5)
Article.objects.all()[5:10] # (OFFSET 5 LIMIT 5)
不支持负的索引(例如Article.objects.all()[-1])。通常,查询集 的切片返回一个新的查询集 —— 它不会执行查询。
(2)可迭代
articleList=models.Article.objects.all()
for article in articleList:
print(article.title)
(3)惰性查询
查询集 是惰性执行的 —— 创建查询集不会带来任何数据库的访问。你可以将过滤器保持一整天,直到查询集 需要求值时,Django 才会真正运行这个查询。
queryResult=models.Article.objects.all() # not hits database
print(queryResult) # hits database
for article in queryResult:
print(article.title) # hits database
一般来说,只有在“请求”查询集 的结果时才会到数据库中去获取它们。当你确实需要结果时,查询集 通过访问数据库来求值。 关于求值发生的准确时间。
(4)缓存机制
每个查询集都包含一个缓存来最小化对数据库的访问。理解它是如何工作的将让你编写最高效的代码。
在一个新创建的查询集中,缓存为空。首次对查询集进行求值 —— 同时发生数据库查询 ——Django 将保存查询的结果到查询集的缓存中并返回明确请求的结果(例如,如果正在迭代查询集,则返回下一个结果)。接下来对该查询集 的求值将重用缓存的结果。
请牢记这个缓存行为,因为对查询集使用不当的话,它会坑你的。例如,下面的语句创建两个查询集,对它们求值,然后扔掉它们:
queryset = Book.objects.all()
print(queryset) # hit database
print(queryset) # hit database
注:简单地打印查询集不会填充缓存。
这意味着相同的数据库查询将执行两次,显然倍增了你的数据库负载。同时,还有可能两个结果列表并不包含相同的数据库记录,因为在两次请求期间有可能有Article被添加进来或删除掉。为了避免这个问题,只需保存查询集并重新使用它:
queryset = Book.objects.all()
ret = [i for i in queryset] # hit database
print(queryset) # 使用缓存
print(queryset) # 使用缓存
何时查询集会被缓存?
遍历queryset时if语句(为了避免这个,可以用exists()方法来检查是否有数据)
所以单独queryset的索引或者切片都不会缓存。
queryset = Book.objects.all()
one = queryset[0] # hit database
two = queryset[1] # hit database
print(one)
print(two)
(5)exists()与iterator()方法
exists
简单的使用if语句进行判断也会完全执行整个queryset并且把数据放入cache,虽然你并不需要这些 数据!为了避免这个,可以用exists()方法来检查是否有数据:
if queryResult.exists():
#SELECT (1) AS “a” FROM “blog_article” LIMIT 1; args=()
print(“exists…”)
iterator
当queryset非常巨大时,cache会成为问题。
处理成千上万的记录时,将它们一次装入内存是很浪费的。更糟糕的是,巨大的queryset可能会锁住系统 进程,让你的程序濒临崩溃。要避免在遍历数据的同时产生queryset cache,可以使用iterator()方法 来获取数据,处理完数据就将其丢弃。
objs = Book.objects.all().iterator()
iterator()可以一次只从数据库获取少量数据,这样可以节省内存
for obj in objs:
print(obj.title)
#BUT,再次遍历没有打印,因为迭代器已经在上一次遍历(next)到最后一次了,没得遍历了
for obj in objs:
print(obj.title)
当然,使用iterator()方法来防止生成cache,意味着遍历同一个queryset时会重复执行查询。所以使 #用iterator()的时候要当心,确保你的代码在操作一个大的queryset时没有重复执行查询。
queryset的cache是用于减少程序对数据库的查询,在通常的使用下会保证只有在需要的时候才会查询数据库。 使用exists()和iterator()方法可以优化程序对内存的使用。不过,由于它们并不会生成queryset cache,可能 会造成额外的数据库查询。
总结:在使用缓存机制还是生成器机制的选择上如果是,数据量大情况主要使用生成器;数据少使用次数多的情况使用缓存机制。
5442

被折叠的 条评论
为什么被折叠?



