官方文档Django 文档 | Django 文档 | Django (djangoproject.com)
整合 Django + Vue.js 框架快速搭建web项目 - 云+社区 - 腾讯云 (tencent.com)
HTTP协议web开发知识点 - cls超 - 博客园 (cnblogs.com)
分页
- (2条消息) Django使用Paginator插件实现分页查询_ Dream_it_possible!的博客-CSDN博客_django 分页查询
数据
- django简单的前后端分离的数据传输实例 axios_vue.js_脚本之家 (jb51.net)
- (2条消息) Django 使用request获取浏览器发送的参数(Django编程-5)_ba76191777的博客-CSDN博客
看了个书 黄永祥的《精通Django3 Web开发》
Django采用MTV框架模式,M代表模型model、T代表模板template、V代表视图view。model数据存储层,template表现层,view业务逻辑层。
WSGI:web server gateway interface 服务器网关接口,是为python定义的web服务器和web应用程序或web框架之间的一种简单而通用的接口协议。WSGI有2部分,服务端和客户端,WSGI是一种通信规范,没有实现过程,实现服务器和web应用框架的通信传输的是服务端。实际网站架构有二级架构和三级架构,二级架构直接使用WSGI自身的服务端作为web服务器,仅适用于开发阶段;三级架构则将服务器作为中间件,实现web服务器和web应用架构的通信,适用于上线阶段。
创建项目
django-admin startproject myDjango #创建django项目
python manage.py statrapp index #创建应用index
python manage.py runserver 8001 #运行项目,默认端口号8000,此时用8001运行
文件结构
--myDjango
--index
--migrations #生成数据迁移文件,通过数据迁移文件可以自动在数据库中生成数据表
__init__.py #初始化文件
admin.py #设置后台管理功能
apps.py #当前app的配置信息
models.py #定义数据库映射类,每个类关联一张数据表
tests.py #自动化测试模块,用于单元测试
views.py #视图文件,处理业务逻辑
--myDjango
__init__.py # 初始化文件,一般无需修改
asgi.py # 启动异步通信功能,在线聊天需要
settings.py # 配置文件
urls.py # 路由设置
wsgi.py # 服务器网关接口,用于项目在服务器上部署和上线
manage.py # 命令行工具,python manage.py help可以查看指令信息
网站中涉及文件存储和使用,数据库记录文件地址,若将文件以二进制数据格式写入数据库,会降低数据库响应速度。
setting.py
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-l_+1qz21c-fcihgzjc&vb8!x&l3k)u!*$c12m_)brb8%0b3fz0'
'''
密钥配置:随机值SERECT_KEY,用于重要数据加密处理,主要用于用户密码、CSRF机制和会话session等数据加密;
用户密码:Django内置Auth认证系统,创建用户时将用户密码通过密钥加密处理;
CSRF机制:用于表单提交,防止窃取网站的用户信息制造恶意请求;
会话session:存放在cookie中,一串随机的字符串,标识当前访问网站的用户身份;
'''
# 域名访问权限
ALLOWED_HOSTS = []
'''
DEBUG为True时,ALLOWED_HOSTS列表为空时,只允许localhost或127.0.0.1访问项目;
DEBUG为False时,ALLOWED_HOSTS为必填项,否则程序无法启动,若要所有域名可以访问,应设置ALLOWED_HOSTS = ['*']
'''
连接mysql数据库
mysqlclient:安装pip install mysqlclient
,设置setting.py的DATABASES
DATABASES={
'default':{
'ENGINE':'django.db.backends.mysql',
'NAME':'babys',
'USER':'root',
'PASSWORD':'123456',
'HOST':'127.0.0.1',
'PORT':'3306',
}
}
pymysql:安装pip install pymysql
,设置__init__.py
#babys文件夹下的__init__.py
import pymysql
pymysql.install_as_MySQLdb
MySQL8.0以上的版本连接提示django.db.utils.OperationError
错误的原因四MySQL8.0版本加密方式时CHA2加密方式,可将加密方式改回原方式,运行SQL语句
# newpassword是已设置的用户密码
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'newpassword';
FLUSH PRIVILEGES;
匹配符
__exact filter(job__exact='开发') #精确等于
__contains filter(job__contains='开发') #模糊匹配,包含即可'%开发%'
__gt filter(id__gt=5) #>
__in filter(id__in=[1,2,3]) #在列表内
__startswith filter(job__startswith='开发') #以。。开头
__endswith filter(job__endswith='开发') #以。。结尾
__range filter(dare__range=(start,end)) #类似between,日期、数字、字符均可
__year filter(date__year=2018) #日期字段的year
__iexact、__icontains、__istartswith、__iendswith 忽略大小写的
__gte >= __lt < __lte <=
__month __day __isnull
查询
#前三条 SQL: select * from table limit 3
v=Table.objects.all()[:3]
返回QuerySet
#or查询,引入Q
v=Table.objects.filter( Q(job='网站设计') | Q(id=4) )
#不等于查询,在Q查询前使用~或使用exclude
v=Table.objects.exclude(job='网站设计')
v=Tbale.objects.filter(~Q(job='网站设计'))
#.count()统计数量
#.distinct()去重
#.order_by('-id')根据id降序排列
values()
&values_list()
QuerySet API 参考 | Django 文档 | Django (djangoproject.com)
#某一列 SQL: select job from table
#values()
返回QuerySet,组成为字典形式而不是模型实例
# This list contains a Blog object.
>>> Blog.objects.filter(name__startswith='Beatles')
<QuerySet [<Blog: Beatles Blog>]>
# This list contains a dictionary.
>>> Blog.objects.filter(name__startswith='Beatles').values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
#values()结果序列化为json格式
(1)将QuerySet转为list: city_list = list(cities)
(2)将list序列化为json: city_json = json.dumps(city_list)
# values_list()
>>> Entry.objects.values_list('id', 'headline')
<QuerySet [(1, 'First entry'), ...]>
v=Table.objects.values_list('job')
返回QuetySet,组成为元组形式
#annotate跨表查询,作用域QuerySet,类似于group by方法,对values值进行分组,若不设置,则对主键分组
v=Table.objects.values('job').annotate(Sum('id'))#结果显示'job'字段和聚合后的sum('id')字段
#aggregate计算某个字段的值并返回计算结果,Sum、Count、Avg、Max、Min、Variance方差、StdDev标准差
v=Table.objects.aggregate(id_cnt=Count('id'))
#对查询结果取并集union、交集intersection、差集difference
多表查询
(7条消息) django中related_name作用_wuliangtianzu的博客-CSDN博客_related_name
# 表Person属性hireDate,表Vocation属性name、job,外键name关联到Person表
# 正向查询
v=Vocation.objects.filter(id=1).first()
#或 有查询条件,第一个name是Vocation中的字段name,第二个name是Person在的字段name
v=Vocation.objects.filter(name__name='Tim').first()
v.name.hireDate #v.name代表外键name
# 反向查询
p=Person.objects.filter(id=2).first()
# 若name没有参数related_name
v=p.vocation_set.first() #vocation_set的返回值为QuerySet
v.job
# 若name设置参数related_name=ps
v=p.ps.first()
v.job
#或 有查询条件 ps是name的related_name,job是Vocation的字段
p=Person.objects.filter(ps__job='网站设计').first()
v=p.person.first() #通过related_name反向获取Vocation模型数据
v.job
# select_related方法
# select Person.name, Vocation.payment from Person left outer join Vocation on name
p=Person.objects.select_related('ps').values('name','ps__payment')
# select_performer方法
执行原生SQL语句
'''extra有6个参数
select:查询字段;where:查询条件;params:若where中有%s,啧params为其提供值;
tables:连接其他表;order_by:排序方式;select_params:为select的%s提供值
'''
Vocation.objects.extra(where=["job=%s"],params=['网站设计'],select={"seat":"%s"},select_params=['seatInfo'])
'''raw有4个参数
raw_query:SQL语句;params:为raw_query的%s提供数值;translations为查询的字段名设置别名;using为数据库对象'''
Vocation.objects.raw('select * from index_vocation')
'''execute无需经过ORM框架,可通过游标执行SQL语句,容易受到SQL注入攻击'''
return HttpResonse(html,status=200)
,其中html变量是相应内容,一般是网页内容或者json数据,网页内容以html语言为主(比如html='Hello World
'
),内容过大时会增加视图函数代码量,因此Django定义了render、render_to_response(2.0版本后被弃用)、redirect函数进行封装;render(request, template_name, context=None, content_type=None, status=None, using=None)
'''request:浏览器向服务器发送的请求对象;
template_name:渲染模板的文件名,用于生成网页内容;
context:对模板上下文的变量进行赋值,以字典格式表示;(将视图函数的变量传递给模板引擎,再有模板引擎解析这些变量并展示在网页上,变量过多时使用locals()函数取代参数context,会以字典形式返回当前的所以局部变量)'''
模板上下文也叫模板变量,{{ variable }}
数据由视图函数传递,支持python所有数据类型
valiable='字符串或者整型数字' <div>{{ variable }}div>
valiable={'name':'字典或实例化对象'} <div>{{ variable.name }}div>
valiable=['元组或列表'] <div>{{ variable.0 }}div> (.索引)
标签
(7条消息) 我的Django学习笔记(2)DTL模型的标签_hide_in_darkness的博客-CSDN博客
(7条消息) Django自定义标签_CSDN-CSDN博客_django 自定义标签
自定义模板(template)的标签(tags)和过滤器(filters) | Django 文档 | Django (djangoproject.com)
{% for %} 支持嵌套,mylist可以是列表、元组或者某个对象
{% for item in mylist %}
{{ item }}
{% endfor %} 循环终止符
{% if %} 判断条件夫与上下文之间要使用空格分开
{% if name=="Lucy" %}
{{name}}
{% elif name=="Lily" %}
{{name}}
{% endif %}
{% url %}
生成不带变量的url地址<a href="{% url 'index' %}">首页a>
生成带变量的url地址<a href="{% url 'page' 1 %}">第1页a>
url标签:返回与给定视图和可选参数匹配的绝对路径引用(不带域名的URL)
url反转传递关键字参数:
{% url '[<appname>:]<urlname>' arg(=value) %}
url反转传递查询字符串,在URL外手动添加查询字符串
{% url '[<appname>:]<urlname>'}?next=xxx
注意:
如果反转的URL不存在,NoReverseMatch则会引发异常,这将导致您的网站显示错误页面。
如果您想检索一个URL但不显示它,则可以使用一个稍微不同的调用:
{% url '[<appname>:]<urlname>' as othername %}
{% with %}
在模版中定义变量
{% with var(=value) %} 或:{% with value as var %}
注意: 在var(变量名)和value(赋值)中间不需要加空格
{% load %}导入静态文件标签库{% load staticfiles %}
{% static %}来自静态文件标签库{% static "css/index.css" %}
标签继承
DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
{% block title %}
<title>首页title>
{% endblock %}
head>
<body>
{% block body %}
{% endblock %}
body>
html>
{% extends "base.html" %} 继承base.html
{% block body %} 重写body接口
<a href="{% url 'index:index' }">首页a>
{% endblock %}
过滤器,过滤器、冒号、参数之间不能有空格,其他可有可无
自定义模板(template)的标签(tags)和过滤器(filters) | Django 文档 | Django (djangoproject.com)
{{ variable | filter }}
{{ value|cut:arg }}从value中删除所有arg的值,比如Value="string with space",arg=" ",结果为"stringwithspace"
{{ value | floatformat:arg }} 四舍五入,没用arg时保留1位,arg为"2"时保留2位
{{ value | length }}返回value的长度
{{ value | random }}从给定的list中返回一个任意的item
__init__.py
项目应用的初始化文件,在文件中设置属性default_app_config
指向app.py
定义的AppConfig
类
apps.py
中定义AppConfig
类,通过设置类属性verbose_name
用于设置项目应用在admin后台系统的名称
admin.py
将项目定义的模型注册并绑定到admin后台系统,模型在后台系统显示的名称由模型属性Meta
的verbose_name
和verbose_name_plural
设置;在admin.py
中用admin.site.register()
的方法将模型注册绑定到admin后台系统,但实际开发中不建议此方法,原因是功能扩展性太差,不能满足开发需求;还可以通过类继承的方式实现模型的注册绑定;
自定义ModelAdmin的函数方法
get_readonly_fields() # 数据只读函数,可以设置不同用户不同的权限
# 设置字段样式,自定义函数colored_name(),判断相应字段的值,不同字段的color_code颜色值不同,然后返回格式化的代码format_html()
get_queryset() #数据查询函数,默认全表查询,可自定义设置不同用户不同的查询范围
formfield_for_choice_field() #下拉框设置函数,只能过滤已经存在的下拉框数据
formfield_for_dbfield() #下拉框设置,使得在admin中新增数据时实现模型之间的关联
def formfield_for_dbfield(self, db_field, **kwargs):
if db_field.name == 'types':
db_field.choices = [(x['seconds'], x['seconds'])
for x in Types.objects.values('seconds')]
return super().formfield_for_dbfield(db_field, **kwargs)
save_model() #保存函数
#数据批量处理,下面是批量导出的一个例子
def get_datas(self, request, queryset):
temp = []
for d in queryset:
t=[d.name,d.types,str(d.discount)]
temp.append(t)
f = open('d://data.txt', 'a')
for t in temp:
f.write(','.join(t) + '\r\n')
f.close()
# 设置提示信息
self.message_user(request, '数据导出成功!')
get_datas.short_description = '导出所选数据' # 设置函数的显示名称
actions = ['get_datas'] # 添加到“动作”栏
部署Django项目有2种主流方案:Nginx+uWSGI+Django和Apache+WSGI+Django;
Nginx和Apache接收浏览器所有http请求并统一管理。静态资源的http请求由Nginx和Apache自己处理,非静态资源的http请求由Nginx和Apache传递给uWSGI服务器,在传递给Django应用,最后Django处理并响应。
上线配置
DEBUG = False
ALLOWED_HOSTS = ['*'] # 域名访问权限
STATIC_ROOT = (BASE_DIR / 'static') #static文件夹不存在,由指令 python manage.py collectstatic 创建
# 项目中存在两个静态文件夹,在不同的DEBUG模式下读取不同文件夹
#在项目的urls.py中添加静态资源路由信息,使得Django知道如何遭到静态资源文件
# 定义静态资源的路由信息
re_path('static/(?P.*)' , serve, {'document_root': settings.STATIC_ROOT}, name='static')
在windows下用自带的IIS服务器,网上很多教程。
def loginView(request):
title = '用户登录'
classContent = 'logins'
if request.method == 'POST':
username = request.POST.get('username', '')
password = request.POST.get('password', '')
if User.objects.filter(username=username):
#验证账号密码与模型User的账号密码是否一致
user = authenticate(username=username, password=password)
if user:#通过验证后使用内置函数login执行用户登录
login(request, user)
return redirect(reverse('shopper:shopper'))#登陆后跳转到个人中心页面
else:#执行用户注册
state = '注册成功'
d = dict(username=username, password=password, is_staff=1, is_active=1)
user = User.objects.create_user(**d)#向User模型添加新用户
user.save()
return render(request, 'login.html', locals())
def logoutView(request):
logout(request)
return redirect(reverse('index:index'))
format_html()
格式化生成html模板Cross-Site Request Forgery,跨网站请求伪造,也称One Click Attack或者Session Riding,常缩写为CSRF或者XSRF,是对网站的恶意利用,窃取网站用户信息制造而已请求。
Django默认开启CSRF防护,只适用于post请求,并不防护get请求,因为get请求是以只读的形式访问网站资源,一般情况不破坏和篡改网站数据,在post请求的表单中加入**{% csrf_token %}
**
Django为防护csrf,在用户提交表单时会自动加入csrfmiddlewaretoken隐藏控件,控件属性的value值由django随机身材,此隐藏控件的值会与网站后台保存的csrfmiddlewaretoken进行匹配,只有匹配成功时才处理网站的表单数据;
Django中使用csrf防护功能首先要在settings.py中设置,创建项目时已默认开启MIDDLEWARE中的django.middleware.csrf.CsrfViewMiddleware
;
取消此功能,在模板文件中删除{% csrf_token %}
,并在对应的视图函数中添加装饰器@csrf_exempt
(没用这一步用户提交表单时程序会由于csrf验证失败而抛出403错误);
要对整个网站取消csrf防护,注释掉中间件CsrfViewMiddleware即可;在整个网站没有csrf防护时相对某些请求设置,需要在模板做添加{% csrf_token %}并在相应的视图函数中添加装饰器@csrf_protect
若网站使用前端的Ajax向Django提交表单数据,则需要设置请求参数csrfmiddlewaretoken,否则会被视为恶意请求。
<script>
function submitForm(){
var csrf = $('input[name="csrfmiddlewaretoken"]').val();
var user = $('#username').val();
var password = $('#password').val();
$.ajax({
url:'/index.html',
type:'POST',
data:{'user':user,
'password':password,
'csrfmiddlewaretoken':csrf,
success:function(arg){
console.log(arg)
}
}
})
}
script>
session与cookie:浏览器向服务器发送请求,服务器做出响应后,二者便会断开连接,下次用户再来访问服务器时,服务器无法识别此用户身份,导致每次刷新页面都需要重新操作一次用户登录才可以识别用户;session与cookie为了解决http协议无状态的弊端,使浏览器和服务器建立长久联系的会话而出现;
Ajax即"Asynchronous Javascript And XML",是一种创建交互式、快速动态网页应用的网页开 发技术,无需加载整个网页,能够实现局部更新的技术。Ajax是指向网站的某个路由地址发送http请求并获取响应内容,响应内容经过Javascript处理后渲染在网页上,从而实现网页内容的局部更新,一般情况下响应内容以JSON格式为主。
原生Javascript的Ajax请求
jQuery的Ajax请求,jQuery是一个快速、简介的Javascript框架,封装了Javascript常用的功能代码,优化HTML文档操作、事件处理、动画设计和Ajax交互;
$.ajax{
url:"",//请求的url地址
dataType:"json",//返回的数据格式
async:true,//是否是异步,默认是
data:{"id":"value"},//请求参数
type:"GET",//请求方式
beforeSend:function(){
//请求前的处理
},
success:function(req){
//请求成功的处理
},
complete:function(){
//请求完成的处理
},
error:function(){
//请求出错的处理
}
};