Django框架03
-
数据的编辑和删除
# 查询所有数据 res = models.User.objects.filter() res = models.User.objects.all()
# 编辑数据 """ 1.首先得获取用户想要编辑的数据主键值 url?edit_id=1 url/1/ 2.后端查询出对应的数据对象展示到前端 利用input标签的value属性 3.提交post请求修改数据 前期提交post请求一定要先去配置文件中注释点一行(csrf...) 如果不注释会报403错误 """
# 批量更新 models.User.objects.filter(id=edit_id).update(**kwargs)
# 单个更新 user_obj = models.User.objects.filter(id=edit_id).first() user_obj.username = 'jason' user_obj.passsword = '666' user_obj.save() """ 该方法当字段比较多的时候效率很降低很多 因为它是从头到尾讲数据所有的字段重新写一遍 """
# 删除数据 """ 1.数据并不会真正意义上的删除,我们在创建表的时候会加一个用来标示是否被删除的字段 is_delete is_alive is_status ... 删数据其实就是修改字段的状态 之后通过代码筛选出没有删除的状态数据即可 2.删除数据的时候应该有一个二次确认的过程而不应该直接删除 ajax讲完之后加二次确认结合sweetalaert """ -
图书管理系统表设计(orm创建表关系)
class User:
models.ForeignKey(to='Publish')
models.ForeignKey(to=Publish) # 报错
class Publish:
pass
"""
一对多
models.ForeignKey(to='关联表名') 常用
models.ForeignKey(to=关联表名) 关联表名必须出现在上方(了解即可)
1.在django1.X版本中外键默认就是级联更新删除的
2.会自动给字段加_id后缀 无论你有没有加(自己不要自作聪明的加上)
3.一对多 外键字段建在多的一方
一对一
models.OneToOneField(to='关联表名')
1.在django1.X版本中外键默认就是级联更新删除的
2.会自动给字段加_id后缀 无论你有没有加(自己不要自作聪明的加上)
3.外键建在任意一方均可 但是推荐你建在查询频率较高的表中(orm查询方便)
多对多
models.ManyToManyField(to='关联表名')
1.在django1.X版本中外键默认就是级联更新删除的
2.该字段是一个虚拟字段不会真正的在表中展示出来 而是用来告诉Django orm当前表和关联表是多对多的外键关系 需要自动创建第三张关系表
3.在Django orm中多对多的表关系有好几种(三种)创建方式
4.外键建在任意一方均可 但是推荐你建在查询频率较高的表中(orm查询方便)
判断表关系的方式:换位思考
""" -
django请求生命周期流程图
""" 浏览器 发送请求(HTTP协议) web服务网关接口 1.请求来的时候解析封装 响应走的时候打包处理 2.django默认的wsgiref模块不能承受高并发 最大只有1000左右 上线之后会替换成uwsgi来增加并发量 3.WSGI跟wsgiref和uwsgi是什么关系 WSGI是协议 wsgiref和uwsgi是实现该协议的功能模块 django后端 1.django中间件(暂时不考虑 后面讲) 类似于django的保安 门户 2.urls.py 路由层 识别路由匹配对应的视图函数 3.views.py 视图层 网站整体的业务逻辑 4.templates文件夹 模版层 网站所有的html文件 5.models.py 模型层 ORM 额外扩展:缓存数据库的作用 """
-
路由分发
""" url()方法第一个参数是正则表达式 一旦匹配成功了 就不会往下走了 而是直接触发正则后面的视图函数的运行 url(r'^admin/',...) # 首页 url(r'^$',...) # 尾页 url(r'',...) """ # django路由匹配的时候其实可以匹配两次 第一次如果url后面没有加斜杠 django会让浏览器加斜杠再发送一次请求 配置文件 APPEND_SLASH = True/False
-
无名有名分组
# 无名分组 url(r'^index/(\d+)/',view.index) """ 将括号内正则表达式匹配的内容当作位置参数传递给后面的视图函数 index(request,111) """ # 有名分组 url(r'^index/(?P<year>\d+)/',view.index) """ 将括号内正则表达式匹配的内容当作关键字参数传递给后面的视图函数 index(request,year=111) """ # 无名和有名不能混合使用 # 单个分组都可以重复使用 url(r'^index/(\d+)/(\d+)/(\d+)/',view.index) url(r'^index/(?P<year>\d+)/(?P<xxx>\d+)/(?P<ooo>\d+)/',view.index) 反向解析 """ 本质:通过一些方法得到一个结果 该结果可以访问到对应的url从而触发视图函数的运行 """ # 最简单的情况 url第一个参数里面没有正则符号 url(r'^index/',view.index,name='xxx') # 前端 {% url 'xxx' %} # 后端 from django.shortcuts import reverse reverse('xxx') """ 别名不能出现冲突!!! """
今日内容概要
-
无名有名分组反向解析
-
路由分发
-
名称空间(了解)
-
伪静态(了解)
-
虚拟环境(了解)
-
django1.X和django2.X的区别(了解)
-
视图层
-
三板斧
-
JsonResponse
-
form表单上传文件
-
FBV(function based view)与CBV(class based view)
(视图函数既可以是函数也可以是类)
今日内容详细
无名有名分组反向解析
# 无名分组反向解析
url(r'^index/(\d+)/',views.index,name='xxx')
# 前端
{% url 'xxx' 123 %}
# 后端
reverse('xxx', args=(1,))
"""
这个数字写代码的时候应该放什么
数字一般情况下放的是数据的主键值 数据的编辑和删除
url(r'^edit/(\d+)/',views.edit,name='xxx')
def edit(request,edit_id):
reverse('xxx',args=(edit_id,))
{%for user_obj in user_queryset%}
<a href="{% url 'xxx' user_obj.id %}">编辑</a>
{%endfor%}
今天每个人都必须完成的作业(*******)
利用无名有名 反向解析 完成数据的增删改查
"""
# 有名分组反向解析
url(r'^func/(?P<year>\d+)/',views.func,name='ooo')
# 前端
<a href="{% url 'ooo' year=123 %}">111</a> 了解
<a href="{% url 'ooo' 123 %}">222</a> 记忆
# 后端
# 有名分组反向解析 写法1 了解
print(reverse('ooo',kwargs={'year':123}))
# 简便的写法 减少你的脑容量消耗 记跟无名一样的操作即可
print(reverse('ooo',args=(111,)))
路由分发
"""
django的每一个应用都可以有自己的templates文件夹 urls.py static文件夹
正是基于上述的特点 django能够非常好的做到分组开发(每个人只写自己的app)
作为组长 只需要将手下书写的app全部拷贝到一个新的django项目中 然后在配置文件里面注册所有的app再利用路由分发的特点将所有的app整合起来
当一个django项目中的url特别多的时候 总路由urls.py代码非常冗余不好维护
这个时候也可以利用路由分发来减轻总路由的压力
利用路由分发之后 总路由不再干路由与视图函数的直接对应关系
而是做一个分发处理
识别当前url是属于哪个应用下的 直接分发给对应的应用去处理
"""
# 总路由
from app01 import urls as app01_urls
from app02 import urls as app02_urls
urlpatterns = [
url(r'^admin/', admin.site.urls),
# 1.路由分发
url(r'^app01/',include(app01_urls)), # 只要url前缀是app01开头 全部交给app01处理
url(r'^app02/',include(app02_urls)) # 只要url前缀是app02开头 全部交给app02处理
# 2.终极写法 推荐使用
url(r'^app01/',include('app01.urls')),
url(r'^app02/',include('app02.urls'))
# 注意事项:总路由里面的url千万不能加$结尾
]
# 子路由
# app01 urls.py
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'^reg/',views.reg)
]
# app02 urls.py
from django.conf.urls import url
from app02 import views
urlpatterns = [
url(r'^reg/',views.reg)
]
名称空间(了解)
# 当多个应用出现了相同的别名 我们研究反向解析会不会自动识别应用前缀
"""
正常情况下的反向解析是没有办法自动识别前缀的
"""
# 名称空间
# 总路由
url(r'^app01/',include('app01.urls',namespace='app01')),
url(r'^app02/',include('app02.urls',namespace='app02'))
# 解析的时候
# app01
urlpatterns = [
url(r'^reg/',views.reg,name='reg')
]
# app02
urlpatterns = [
url(r'^reg/',views.reg,name='reg')
]
reverse('app01:reg')
reverse('app02:reg')
{% url 'app01:reg' %}
{% url 'app02:reg' %}
# 其实只要保证名字不冲突 就没有必要使用名称空间
"""
一般情况下 有多个app的时候我们在起别名的时候会加上app的前缀
这样的话就能够确保多个app之间名字不冲突的问题
"""
urlpatterns = [
url(r'^reg/',views.reg,name='app01_reg')
]
urlpatterns = [
url(r'^reg/',views.reg,name='app02_reg')
]
伪静态(了解)
"""
静态网页
数据是写死的 万年不变
伪静态
将一个动态网页伪装成静态网页
为什么要伪装呢?
https://www.cnblogs.com/Dominic-Ji/p/9234099.html
伪装的目的在于增大本网站的seo查询力度
并且增加搜索引擎收藏本网上的概率
搜索引擎本质上就是一个巨大的爬虫程序
总结:
无论你怎么优化 怎么处理
始终还是干不过RMB玩家
"""
urlpatterns = [
url(r'^reg.html',views.reg,name='app02_reg')
]
虚拟环境(了解)
"""
在正常开发中 我们会给每一个项目配备一个该项目独有的解释器环境
该环境内只有该项目用到的模块 用不到一概不装
linux:缺什么才装什么
虚拟环境
你每创建一个虚拟环境就类似于重新下载了一个纯净的python解释器
但是虚拟环境不要创建太多,是需要消耗硬盘空间的
扩展:
每一个项目都需要用到很多模块 并且每个模块版本可能还不一样
那我该如何安装呢? 一个个看一个个装???
开发当中我们会给每一个项目配备一个requirements.txt文件
里面书写了该项目所有的模块即版本
你只需要直接输入一条命令即可一键安装所有模块即版本
"""
django版本区别
"""
1.django1.X路由层使用的是url方法
而在django2.Xhe3.X版本中路由层使用的是path方法
url()第一个参数支持正则
path()第一个参数是不支持正则的 写什么就匹配什么
如果你习惯使用path那么也给你提供了另外一个方法
from django.urls import path, re_path
from django.conf.urls import url
re_path(r'^index/',index),
url(r'^login/',login)
2.X和3.X里面的re_path就等价于1.X里面的url
2.虽然path不支持正则 但是它的内部支持五种转换器
path('index/<int:id>/',index)
# 将第二个路由里面的内容先转成整型然后以关键字的形式传递给后面的视图函数
def index(request,id):
print(id,type(id))
return HttpResponse('index')
str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
int,匹配正整数,包含0。
slug,匹配字母、数字以及横杠、下划线组成的字符串。
uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
path,匹配任何非空字符串,包含了路径分隔符(/)(不能用?)
3.除了有默认的五个转换器之外 还支持自定义转换器(了解)
class MonthConverter:
regex='\d{2}' # 属性名必须为regex
def to_python(self, value):
return int(value)
def to_url(self, value):
return value # 匹配的regex是两个数字,返回的结果也必须是两个数字
from django.urls import path,register_converter
from app01.path_converts import MonthConverter
# 先注册转换器
register_converter(MonthConverter,'mon')
from app01 import views
urlpatterns = [
path('articles/<int:year>/<mon:month>/<slug:other>/', views.article_detail, name='aaa'),
]
4.模型层里面1.X外键默认都是级联更新删除的
但是到了2.X和3.X中需要你自己手动配置参数
models.ForeignKey(to='Publish')
models.ForeignKey(to='Publish',on_delete=models.CASCADE...)
"""
视图层
三板斧
"""
HttpResponse
返回字符串类型
render
返回html页面 并且在返回给浏览器之前还可以给html文件传值
redirect
重定向
"""
# 视图函数必须要返回一个HttpResponse对象 正确 研究三者的源码即可得处结论
The view app01.views.index didn't return an HttpResponse object. It returned None instead.
# render简单内部原理
from django.template import Template,Context
res = Template('<h1>{{ user }}</h1>')
con = Context({'user':{'username':'jason','password':123}})
ret = res.render(con)
print(ret)
return HttpResponse(ret)
JsonResponse对象
"""
json格式的数据有什么用?
前后端数据交互需要使用到json作为过渡 实现跨语言传输数据
前端序列化
JSON.stringify() json.dumps()
JSON.parse() json.loads()
"""
import json
from django.http import JsonResponse
def ab_json(request):
user_dict = {'username':'jason好帅哦,我好喜欢!','password':'123','hobby':'girl'}
l = [111,222,333,444,555]
# 先转成json格式字符串
# json_str = json.dumps(user_dict,ensure_ascii=False)
# 将该字符串返回
# return HttpResponse(json_str)
# 读源码掌握用法
# return JsonResponse(user_dict,json_dumps_params={'ensure_ascii':False})
# In order to allow non-dict objects to be serialized set the safe parameter to False.
# return JsonResponse(l,safe=False)
# 默认只能序列化字典 序列化其他需要加safe参数
form表单上传文件及后端如何操作
"""
form表单上传文件类型的数据
1.method必须指定成post
2.enctype必须换成formdata
"""
def ab_file(request):
if request.method == 'POST':
# print(request.POST) # 只能获取普通的简直对数据 文件不行
print(request.FILES) # 获取文件数据
# <MultiValueDict: {'file': [<InMemoryUploadedFile: u=1288812541,1979816195&fm=26&gp=0.jpg (image/jpeg)>]}>
file_obj = request.FILES.get('file') # 文件对象
print(file_obj.name)
with open(file_obj.name,'wb') as f:
for line in file_obj.chunks(): # 推荐加上chunks方法 其实跟不加是一样的都是一行行的读取
f.write(line)
return render(request,'form.html')
request对象方法
"""
request.method
request.POST
request.GET
request.FILES
request.body # 原生的浏览器发过来的二进制数据 后面详细的讲
request.path
request.path_info
request.get_full_path() 能过获取完整的url及问号后面的参数
"""
print(request.path) # /app01/ab_file/
print(request.path_info) # /app01/ab_file/
print(request.get_full_path()) # /app01/ab_file/?username=jason
FBV与CBV
# 视图函数既可以是函数也可以是类
def index(request):
return HttpResponse('index')
# CBV
# CBV路由
url(r'^login/',views.MyLogin.as_view())
from django.views import View
class MyLogin(View):
def get(self,request):
return render(request,'form.html')
def post(self,request):
return HttpResponse('post方法')
"""
FBV和CBV各有千秋
CBV特点
能够直接根据请求方式的不同直接匹配到对应的方法执行
内部到底是怎么实现的?
CBV内部源码(******)
"""