视图层
目录
1. 昨日回顾
查询数据
get()
filter()
all()
创建数据
create()
user_obj = models.Userinfo(**kwargs)
user_obj.save()
数据的编辑与删除
后端如何获取前端用户想要编辑的数据对象
1.利用get请求url后面可以携带参数的方式 将数据的主键值传递给后端
编辑功能的思路:获取用户想要编辑的数据对象 展示到前端页面 用户修改之后点击修改 再去修改数据库中对应的数据
1.方式1
modeles.Userinfo.objects.filter(**kwargs).update() # 批量更新
2.方式2 (不推荐使用 效率极低 会将每一个字段对应的值全部重写一遍)
edit_obj = models.Userinfo.objects.filter(pk=edit_id).first() # pk会自动帮你查找当前表的主键字段
edit_obj.username = username
edit_obj.password = password
edit_obj.save()
删除
models.Userinfo.objects.filter(pk=delete_id).delete()
"""真正的数据是不会被删除的 通常都是给数据设置一个是否删除的标志位"""
图书管理系统表设计(orm如何创建表与表之间的关系)
一对多:一对多外键字段应该建在多的那一方
models.ForeignKey(to='关联的表名') # 自动建关系 默认就是跟关联表的主键字段
"""ForeginKey字段在创建的时候 orm会自动在字段后面加_id"""
多对多
ManyToManyField(to='关联的表名') # 并不会创建一个实际字段 仅仅是用来告诉django orm自动创建第三张表
一对一
OneToOneField(to='关联的表名')
"""OneToOneField字段在创建的时候 orm会自动在字段后面加_id"""
django请求生命周期流程图
路由层
路由匹配: url第一个参数是正则
无名分组: url(r'^index/(\d+)/',views.index)
在调用视图函数index的时候 会将\d+匹配到的内容 当做位置参数传递给index
有名分组: url(r'^index/(?P<year>\d+)/',views.index)
在调用视图函数index的时候 会将\d+匹配到的内容 当做关键字参数(year='')传递给index
"""注意 无名有名不能混合使用 但是可以单独使用 单独使用的时候支持多个"""
反向解析
本质:根据某一个东西得出一个结果 该结果可以直接访问到对应的url
没有正则表达式的反向解析
url(r'^index/',views.index,name='xxx') # 起别名 别名一定不要重复
前端反向解析: {% url 'xxx' %}
后端反向解析:
from django.shortcuts import reverse
url = reverse('xxx')
无名和有名分组的反向解析: url(r'^index/(\d+)/',views.index,name='xxx')
前端反向解析: {% url 'xxx' 123 %}
后端反向解析:
from django.shortcuts import reverse
url = reverse('xxx',args=(123,))
"""个人建议:在处理容器类型数据的时候 无论有几个值 你最后都加一个逗号"""
url(r'^index/(?P<year>\d+)/',views.index,name='xxx')
前端反向解析: {% url 'xxx' 123 %}
{% url 'xxx' year=123 %} # 了解
后端反向解析:
from django.shortcuts import reverse
url = reverse('xxx',args=(123,))
url = reverse('xxx',kwargs={'year':123}) # 了解
"""个人建议:在处理容器类型数据的时候 无论有几个值 你最后都加一个逗号"""
路由分发
django中的每一个app都可以有自己独立的static文件夹,templates文件夹,urls.py等
正是由于上述的特点 你基于django开发项目 就真正可以做到分组分功能分模块独立的去开发
当应用特别多的时候 总路由中的代码过于冗长 不好维护
# 1.在应用下自己手动创建urls.py
# 2.在路由中导入
# 1
from app01 import urls as app01_urls
from app02 import urls as app02_urls
url(r'^app01/',include(app01_urls)),
url(r'^app02/',include(app02_urls))
# 2
url(r'^app01/',include('app01.urls')),
url(r'^app02/',include('app02.urls'))
名称空间
url(r'^app01/',include('app01.urls',namespace='app01')),
url(r'^app02/',include('app02.urls',namespace='app02'))
# app01 urls.py
url(r'^index/',views.index,name='index')
# app02 urls.py
url(r'^index/',views.index,name='index')
url = reverse('app01:index')
url = reverse('app02:index')
{% url 'app01:index' %}
{% url 'app02:index' %}
# app01 urls.py
url(r'^index/',views.index,name='app01_index')
# app02 urls.py
url(r'^index/',views.index,name='app02_index')
伪静态
url看起来像是一个静态页面(.html结尾)
虚拟环境
不同的项目应该有各自独立的解释器环境 最大化节省资源
实际功能中针对不同的项目 会有一个叫requestsments.txt文件
该文件中列出来是一个个该项目需要用的到模块名和版本号
eg:
django = 1.11.11
nginx = 1.21
后期通过命令直接会去下载该文件内所有的模块及对应版本
虚拟环境 就类似于是个python解释器环境 每创建一个就类似于重新下载了一个纯净的python解释器环境
django版本区别
url和path
path第一个参数不支持正则 写什么就匹配什么 精准匹配
re_path跟url是一模一样的用法
提供五个默认的转换器
还支持用户自定义转换器
2. 视图层
# 1.HttpResponse # 返回字符串
# 2.render # 返回一个html页面 还可以给模板传递
# render的内部原理
from django.template import Template,Context
def index(request):
res = Template("<h1> {{ user }} </h1>")
con = Context({'user':{'username':'jason','pwd':'123'}})
ret = res.render(con)
print(ret)
return HttpResponse(ret)
# 3.redirect # 重定向
3. JsonResponse
# JsonResponse: 返回json格式数据的
'''
为什么要给前端返回json格式字符串
前后端分离 就是基于json格式传输数据
后端就专门写接口 前端调用你这个接口 就能够拿到一个
json格式的字符串
然后前端利用序列化反序列转换成前端对应的数据类型
js常用数据类型: 数值类型、字符类型、数组 []、自定义对象 {}、undefined与null、布尔值 true false、symbol(新加的)
JSON.stringify 序列化 >>> json.dumps
JSON.parse 反序列 >>> json.loads
'''
def index(request):
# user = {'username': 'aa哈哈哈', 'pwd': '123'}
# json_str = json.dumps(user, ensure_ascii=False)
# return HttpResponse(json_str)
# return JsonResponse(user,json_dumps_params={'ensure_ascii':False})
l = [1,2,3,4,5,6]
return JsonResponse(l, safe=False)
# JsonResponse默认只支持序列化字典 如果你想序列化其他类型(json能够支持的类型) 你需要将safe参数由默认的True改成False
4. form表单上传文件
'''
注意事项:
1.提交方式必须是post
2.enctype参数必须有默认的urlencoded变成formdata
FBV与CBV 即CBV源码分析
FBV(Function Based View) 基于函数的视图
CBV(Class Based View) 基于类的视图
思考:你在类中写了两个方法 一个叫get一个叫post
为什么前端get请求来就会触发get方法
post请求来就会触发post方法 如何实现的???
'''
# 上传文件
def up(request):
if request.method == 'POST':
# 获取文件对象
file_obj = request.FILES.get('myfile')
with open(file_obj.name,'wb') as f: # file_obj.name 获取文件名
for chunk in file_obj.chunks():
f.write(chunk)
return render(request,'up.html')
# CBV路由
url(r'^reg/',views.MyReg.as_view())
@classonlymethod
def as_view(cls, **initkwargs):
def view(request, *args, **kwargs):
self = cls(**initkwargs) # cls就是我们自己的写的MyReg类
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
# 上面的一通操作 就是给我们自己写的类的对象赋值
return self.dispatch(request, *args, **kwargs)
# 对象在查找属性或方法的时候 顺序是什么? 先从自己找 再从产生对象的类中找 再去类的父类中找...
"""也就意味着你在看源码的时候 你一定要牢记上面的话"""
return view
# views.py
from django.views import View
class MyReg(View):
def get(self,request):
return render(request,'reg.html')
def post(self,request):
return HttpResponse("我是MyReg类中post方法")
"""CBV最精髓的部分"""
def dispatch(self, request, *args, **kwargs):
if request.method.lower() in self.http_method_names: # 判断当前请求方式在不在默认的八个请求方式中
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
# handler = getattr(自己写的类产生的对象,'小写的请求方法(get\post)','获取不到对应的方法就报错')
# handler就是我们自己定义的跟请求方法相对应的方法的函数内存地址
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs) # 在调用获取到的方法
5. django settings源码分析及实际应用
'''
django的配置文件有两个
一个是暴露给用户可以自定义配置的
一个是默认的全局配置文件
用户指定了就用用户的
用户没有指定就用默认的
'''
from django.conf import settings
settings = LazySettings()
class LazySettings(LazyObject):
def _setup(self, name=None):
# os.environ你可以把它看成是一个全局的大字典
settings_module = os.environ.get(ENVIRONMENT_VARIABLE) # 从大字典中取值
# settings_module = 'day59.settings'
self._wrapped = Settings(settings_module) # Settings('day59.settings')
class Settings(object):
def __init__(self, settings_module): # settings_module = 'day59.settings'
for setting in dir(global_settings): # 循环获取global_settings文件中所有的名字
if setting.isupper(): # 在判断名字是否是大写
# 如果是大写 利用反射 获取到大写的名字所对应的值 不停地添加到对象中
setattr(self, setting, getattr(global_settings, setting))
# store the settings module in case someone later cares
self.SETTINGS_MODULE = settings_module
mod = importlib.import_module(self.SETTINGS_MODULE) # 'day59.settings'
# from day59 import settings
# mod 指代的就是暴露给用户的配置文件模块名
for setting in dir(mod): # 循环获取暴露给用户配置文件中所有的名字
if setting.isupper(): # 判断是否是大写
setting_value = getattr(mod, setting) # 如果是大写 获取大写的变量名所对应的值
setattr(self, setting, setting_value) # 不停的给对象设置值
6. 模板传值
# 如果传递给前端一个函数名,会直接加括号调用,将函数的返回值展示到前端,django的模板语法不支持给函数传参
<p>{{ func }}</p>
# 方法都不能传参
<p>{{ obj }}</p>
<p>{{ obj.get_cls }}</p>
<p>{{ obj.get_func }}</p>
<p>{{ obj.get_self }}</p>
# django模板语法在获取容器类型内部元素的值的时候 统一只采用 句点符(.)
# 模板语法取值
<p>{{ l.1 }}</p>
<p>{{ l.3 }}</p>
<p>{{ d.username }}</p>
<p>{{ d.password }}</p>
<p>{{ d.password.1 }}</p>
7. 过滤器与标签
'''
1.过滤器(|)
(前端代码并不一定非要在前端写 你也可以在后端写好 传递给前端页面)
前后端取消转义
前端
|safe
后端
from django.utils.safestring import mark_safe
sss2 = "<a href='http://www.xiaohuar.com'>下午上课 需要激情</a>"
res = mark_safe(sss2)
模板语法的符号就两种
{{}} 变量相关
{%%} 逻辑相关
'''
{#过滤器 有点类似于小的方法 #}
{#特点 会将|左边的当做过滤器的第一个参数 |右边的当前过滤器第二个参数#}
<p>{{ n|add:100 }}</p>
<p>{{ n|add:'abc' }}</p> {# 返回空 #}
<p>{{ s|add:'abc' }}</p>
<p>{{ l|length }}</p>
<p>{{ d|length }}</p>
<p>{{ file_size|filesizeformat }}</p>
<p>截取10个字符 三个点也算{{ w|truncatechars:10 }}</p>
<p>截取10个字符 三个点也算{{ w1|truncatechars:10 }}</p>
<p>安装空格截取单词 三个点不算{{ w|truncatewords:6 }}</p>
<p>安装空格截取单词 三个点不算{{ w1|truncatewords:6 }}</p>
<p>安装空格截取单词 三个点不算{{ w2|truncatewords:6 }}</p>
<p>{{ l|slice:'0:5' }}</p>
<p>{{ l|slice:'0:5:2' }}</p>
<p>{{ ctime|date:'Y-m-d' }}</p>
<p>{{ ctime|date:'Y年m月d日' }}</p>
<p>{{ sss|safe }}</p>
<p>{{ sss1|safe }}</p>
<p>{{ res }}</p>
<p>{{ xo|default:'' }}</p>
{#有值就拿值 没值就用后面默认的#}
# 2.标签
# if判断
# for循环
{% for foo in l %}
{% if forloop.first %}
<p>第一次</p>
{% elif forloop.last %}
<p>最后一次</p>
{% else %}
<p>嗨起来</p>
{% endif %}
{% endfor %}
# 3.自定义过滤器、标签的步骤
# 1.在应用名下面新建一个templatetags文件夹(必须叫这个名字)
# 2.在该文件夹下新建一个任意名称的py文件
# 3.在该pa文件内固定写两行代码
from django.template import Library
register = Library()
# 4.自定义的过滤器
@register.filter(name='myfilter')
def index(a,b):
return a + b
# 5.自定义的标签
@register.simple_tag(name='myst')
def login(a,b,c,d):
return f'{a}{b}{c}{d}'
# 6.区别 标签不能再if中使用
# 可以用
{% if 0|myfilter:123 %}
<p>有值</p>
{% endif %}
# 不能用
{#{% if myst 1 2 3 4 5 %}#}
{# <p>有值</p>#}
{#{% endif %}#}
8. 模板的继承
# 事先需要再模板中 通过block划定区域
{% block 区域名字 %}
{% endblock %}
# 子板中如何使用
{% extends '模板的名字'%}
{% block 区域名字 %}
<h1>登录页面</h1>
{% endblock %}
# 一个页面上 block块越多 页面的扩展性越高
# 通常情况下 都应该有三片区域
{% block css %}
{% endblock %}
{% block content %}
{% endblock %}
{% block js %}
{% endblock %}
# 子板中还可以通过 {{ block.super }} 来继续使用母版的内容
9. 模板的导入
# 当你写了一个特别好看的form表单 你想再多个页面上都使用这个form表单,你就可以将你写的form表单当作模块的形式导入 导入过来之后 就可以直接展示
{% include 'good_page.html' %}