Django入门
链接
官方文档Django 文档 | Django 文档 | Django (djangoproject.com)
基础
-
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的DATABASESDATABASES={ '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;
-
model
匹配符
__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注入攻击'''
view
- 用视图处理HTTP请求,在视图中定义def函数,称为FBV(function base views);以类的形式实现响应与请求处理,称为CBV(class base views)
- 视图响应式return HttpResponse类,
return HttpResonse(html,status=200)
,其中html变量是相应内容,一般是网页内容或者json数据,网页内容以html语言为主(比如html='<h1>Hello World</h1>'
),内容过大时会增加视图函数代码量,因此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,会以字典形式返回当前的所以局部变量)'''
template
-
模板上下文也叫模板变量,
{{ 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" %}
-
标签继承
<!--base.html--> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> {% block title %} <title>首页</title> {% endblock %} </head> <body> {% block body %} {% endblock %} </body> </html> <!--index.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
admin
-
__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<path>.*)', serve, {'document_root': settings.STATIC_ROOT}, name='static')
在windows下用自带的IIS服务器,网上很多教程。
杂项
使用内置User实现注册登录登出
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模板
其他
csrf防护
-
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:浏览器向服务器发送请求,服务器做出响应后,二者便会断开连接,下次用户再来访问服务器时,服务器无法识别此用户身份,导致每次刷新页面都需要重新操作一次用户登录才可以识别用户;session与cookie为了解决http协议无状态的弊端,使浏览器和服务器建立长久联系的会话而出现;
- cookie存储在客户端,是从浏览器向服务器传递数据,使得服务器能够识别当前用户,而服务器对cookie的识别机制通过session实现;
- session存储了当前用户的基本信息,存储在服务器端,安全性比cookie高;
- 当获取用户的session数据时,首先从用户传递cookie里获取sessionid,然后根据sessionid在网站服务器中找到响应的session;
Ajax
-
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(){ //请求出错的处理 } };