Django--路由层、视图层、模版层
路由层:
路由匹配
url(正则表达式,视图函数内存地址)
只要正则匹配到了内容,就不再往下匹配,而是直接运行后面的视图函数
匹配首页)
url(r'^&', home)
匹配尾页
url(r'', errors)
路由匹配的规律
第一次是按照用户输入什么就匹配什么
第二次是Django会让浏览器自动在尾部加上斜杠再次匹配,要是还是匹配不上就不报错
上述的规律不是浏览器的特点,而是Django的功能
Django settings文件夹中
APPEND_SALSH = True # 这个是自动加斜杠的
无名分组
路由匹配成功之后,如果正则表达式中有分组,那么在调用视图函数的时候会将括号内正则表达式匹配到的内容当作位置参数传递给后面的视图函数
url(r'^index/(\d+)/', index)
def index(request, args):
return Httpresponse对象
有名分组
路由匹配成功之后,如果正则表达式中有有名分组并且起了别名的话,那么在调用视图函数的时候会将括号内正则表达式匹配到的内容当作关键字参数传递给后面的视图函数
url(r'^index/(?P<year>\d+)/', index)
def index(request, index):
return Httpresponse对象
有名分组和无名分组不能混合使用,但是两者可以单独使用多个
反向解析
由来是很多html页面和后端代码中频繁使用了指名道姓的url(/index/)
那么这个时候如果一旦发生了变化,前后端所有的地方都需要修改,造成了可维护性比较差
反向解析的本质就是通过某个方法获取的一个能够访问对应的url的结果
没有涉及到正则表达式符号的情况下
url(r'^index/', index, name='index')
前端:
{% url 'aaa' %}
后端:
from django.shortcuts import HttpResponse,render,redirect,reverse
url = reverse('index')
无名分组和有名分组的情况
无名:
url(r'^index/(\d+)/',index,name='bbb')
前端:
{% url 'bbb' 1 %}
后端:
url = reverse('aaa',args=(1,))
有名:
url(r'^index/(?P<edit_id>\d+)/',index,name='bbb')
前端:
{% url 'bbb' 1 %}
{% url 'bbb' year=1 %}
后端:
url = reverse('aaa',args=(1,))
url = reverse('aaa',kwargs={'year':1})
路由分发
include()
django中的每一个app都可以是独立的urls.py, static静态文件, templates模版文件夹
真是基于上面的特点,Django就可以很好的支持多人分组开发,每个人只需要开发各自的app就可以了,最后只需要创建一个空的Django项目将所有人的app注册进来,总路由中来一个路由分发就可以将多个人的功能整合到一个项目中了
当项目比较巨大的时候,如果不使用路由分发,那么路由中的url代码太多了,不利于维护和更新
from app01 import urls as app01_urls
from app02 import urls as app02_urls
url(r'应用名前缀/',include(app01_urls))
url(r'应用名前缀/',include(app02_urls))
# 推荐使用下面的方式
url(r'应用名前缀/',include('app01.urls'))
url(r'应用名前缀/',include('app02.urls'))
路由分发要注意的点:
总路由中的最后千万不要加$符号
名称空间
你在起别名的时候,虽然能够同一个应用下不重名,但是你没办法实现多个人多个app不重名的情况
一旦重名在进行反向解析的话就不能识别所在的应用了
在总路由中 给每一个应用开设一个名称空间
url(r'应用名前缀/',include('app01.urls',namespace='app01'))
url(r'应用名前缀/',include('app02.urls',namespace='app02'))
子路由:
url(r'^index/',index,name='aaa')
url(r'^index/',index,name='aaa')
反向解析的时候:
reverse('app01:aaa')
reverse('app02:aaa')
{% url 'app01:aaa' %}
{% url 'app02:aaa' %}
其实你可以完全不使用名称空间 只需要保证别名不重复就行,也就是你在起别名的时候给每个别名加上所在应用名的前缀
伪静态
就是在url后面加上一个.html
虚拟环境
不同的项目应该有属于该项目独有的python解释器环境,这样的话就可以避免资源的浪费以及版本兼容的问题
注意⚠️:
虚拟环境虽然好用,但是不要无限制的进行创建 你机器上的虚拟环境可以手动进行删除
Django版本之间的区别:
路由2.X里面的是path第一个参数也不再支持正则表达式,而是写什么就匹配什么,如果这个时候你还是想要使用正则进行匹配的话,这里面提供了一个re_path模块就是1.X里面的url
虽然path不再支持正则,但是他提供了五种转化器(可以将路由匹配到的内容自动转换成对应的数据格式然后再传递给后面的视图函数)
视图层
如果一个一个应用下面的视图函数特别多,这时候你就可以新建一个views文件夹,然后根据不同的功能起不同的名字的py文件存放不同的功能,实现持续的解耦合 和增加可读性
views
user.py
account.py
order.py
...
前后端分离
JsonResponse(data,safe=False,json_dumps_params={'ensure_ascii':False})
如果在son_dumps_params里面你传递的不是字典数据,那么需要手动指定safe=False
form表单上传文件
需要注意的事项:
1、method必须是post
2、enctype必须要制定成formdata
3、目前需要考虑的 需要将settings配置文件中的csrf中间件注释掉
后端不再通过request.POST获取文件数据,而是通过request.FILES
file_obj = request.FILES.get('myfile')
file_obj.name # 文件名
with open(file_obj.name,'wb') as f:
for chunk in file_obj.chunks():
f.write(chunk)
request
request.method
request.GET
request.POST
request.FILES
request.body # 获得是原生的二进制的数据
request.path # 只拿url
request.get_full_path() # url+?后面的参数
render能够返回一个html页面,并且还能够为该页面传递数据
render的内部原理
from django.template import Template,Context
def index(request):
temp = Template('<h1>{{ user }}</h1>')
con = Context({"user":{"name":'jason',"password":'123'}})
res = temp.render(con)
print(res)
return HttpResponse(res)
FBV和CBV
视图函数并不是指函数 同样也可以指类
FBV:基于函数的视图(面向函数式编程)
CBV:基于类的视图 (面向对象式编程)
# 问题:基于CBV的视图函数
"""get请求来就会走类里面get方法,post请求来就会走类里面post方法 为什么???""" urls.py中
url(r'^login/',views.MyLogin.as_view()) # 由于函数名加括号的执行优先级最高,所以这一句话写完就会立刻执行as_view()方法
views.py中
from django.views import View class MyLogin(View):
def get(self,request):
print("from MyLogin get方法")
return render(request,'login.html')
def post(self,request):
return HttpResponse("from MyLogin post方法")
研究方向
1.从url入手
url(r'^login/',views.MyLogin.as_view()) 由于函数名加括号执行优先级最高,所以这一句话一写完会立刻执行as_view()方法 @classonlymethod
def as_view(cls, **initkwargs): # cls就是我们自己的写的类 MyLogin
def view(request, *args, **kwargs):
self = cls(**initkwargs) # 实例化产生MyLogin的对象 self = MyLogin(**ininkwargs)
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) # dispatch返回什么 浏览器就会收到什么
# 对象在查找属性或者方法的时候 你一定要默念 先从对象自己这里找 然后从产生对象的类里面找 最后类的父类依次往后
return view 通过源码发现url匹配关系可以变形成
url(r'^login/',views.view) # FBV和CBV在路由匹配上是一致的 都是url后面跟函数的内存地址
2.当浏览器中输入login 会立刻触发view函数的运行
def dispatch(self, request, *args, **kwargs):
# Try to dispatch to the right method; if a method doesn't exist,
# defer to the error handler. Also defer to the error handler if the
# request method isn't on the approved list.
# 我们先以GET为例
if request.method.lower() in self.http_method_names: # 判断当前请求方法是否在默认的八个方法内
# 反射获取我们自己写的类产生的对象的属性或者方法
# 以GET为例 handler = getattr(self,'get','取不到报错的信息')
# handler = get(request)
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs) # 直接调用我们自己的写类里面的get方法
# 源码中先通过判断请求方式是否符合默认的八个请求方法 然后通过反射获取到自定义类中的对应的方法执行
Django settings中的源码
前提:
1、Django除了暴露给用户一个settings.py配置文件之外 自己内部还有一个全局的配置文件
2、我们在使用配置文件的时候,可以直接导入暴露给用户的settings.py也可以使用Django全局的配置文件 并且一般都是后者使用居多
from django.conf import settings
3、Django的启动入口是manage.py
import os
import sys if __name__ == "__main__":
# django在启动的时候 就会往全局的大字典中设置一个键值对 值是暴露给用户的配置文件的路径字符串
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day54.settings") class Settings(object):
def __init__(self, settings_module): # settings_module = 'day54.settings'
# update this dict from global settings (but only for ALL_CAPS settings)
for setting in dir(global_settings): # django全局配置文件
# dir获取django全局配置文件中所有的变量名
if setting.isupper(): # 判断文件中的变量名是否是大写 如果是大写才会执行/生效
setattr(self, setting, getattr(global_settings, setting)) # 给settings对象设置键值对
# 给settings对象设置键值对 settings[配置文件中大写的变量名] = 配置文件中大写的变量名所对应的值 # store the settings module in case someone later cares
self.SETTINGS_MODULE = settings_module # 'day54.settings' mod = importlib.import_module(self.SETTINGS_MODULE) # mod = 模块settings(暴露给用户的配置文件)
for setting in dir(mod): # for循环获取暴露给用户的配置文件中所有的变量名
if setting.isupper(): # 判断变量名是否是大写
setting_value = getattr(mod, setting) # 获取大写的变量名所对应的值
setattr(self, setting, setting_value) # 给settings对象设置键值对
"""
d = {}
d['username'] = 'jason'
d['username'] = 'egon'
用户如果配置了就用用户的
用户如果没有配置就用系统默认的
其实本质就是利用字典的键存在就是替换的原理 实现了用户配置就用用户的用户没配置就用默认的
""" class LazySettings(LazyObject):
def _setup(self, name=None):
# os.environ你可以把它看成是一个全局的大字典
settings_module = os.environ.get(ENVIRONMENT_VARIABLE) # 从大字典中取值键为DJANGO_SETTINGS_MODULE所对应的值:day54.settings
# settings_module = 'day54.settings'
self._wrapped = Settings(settings_module) # Settings('day54.settings') settings = LazySettings() # 单例模式
模版层
模版语法
{{}}变量相关
{%%}逻辑相关
都是为模版来传值的
过滤器:|
前后端取消转义
前端:
|safe
后端:
from django.utils.safestring import mark_safe
zzz = mark_safe('<h1>阿萨德搜啊第三款垃圾袋</h1>')
|safe
|filesizeformat
|date
标签{%%}
{#{% for foo in l %}#}
{# <p>{{ forloop }}</p>#}
{#{% endfor %}#}
{##}
{##}
{#{% if '' %}#}
{#<p>xxx条件为true</p>#}
{# {% else %}#}
{# <p>xxx条件为false</p>#}
{#{% endif %}#} {##}
{#{% for foo in '' %}#}
{# {% if forloop.first %}#}
{# <p>这是我的第一次</p>#}
{# {% elif forloop.last %}#}
{# <p>这是最后一次了啊</p>#}
{# {% else %}#}
{# <p>来啊来啊!!!</p>#}
{# {% endif %}#}
{# {% empty %}#}
{# <p>当for循环的对象为空的时候 会走empty</p>#}
{#{% endfor %}#} {##}
{#<p>#}
{# django模板语法在取值的时候 统一使用句点符(大白话就是 点号 .)#}
{# {% with l.6.3.name as ttt %} 可以给一个比较复杂的取值操作取一个别名 之后在with语句中 就可以使用该别名#}
{# {{ ttt }}#}
{# {{ l.6.3.name }}#}
{# {% endwith %}#}
{#</p>#} {% for foo in d.keys %}
<p>{{ foo }}</p>
{% endfor %}
{% for foo in d.values %}
<p>{{ foo }}</p>
{% endfor %}
{% for foo in d.items %}
<p>{{ foo }}</p>
{% endfor %}
for循环里面的forloop对象
if判断
自定义标签、过滤器、inclusion_tag
自定义固定的三步走战略:
1、必须在你的应用下新建一个叫templatetags文件夹
2、在该文件夹内新建一个任意名称的py文件
3、在该py文件中固定先写入下面两句代码
from django import template
register = template.Library()
自定义过滤器
@register.filter(name='baby')
def index(a,b):
# 该过滤器只做一个加法运算 是|add建议版本
"""
|length
|add
|default
|filesizeformat
|truncatewords
|truncatechars
|safe
|slice :param a:
:param b:
:return:
"""
print('下午刚起床 一脸懵逼')
return a + b
自定义标签,支持传多个值
@register.simple_tag(name='jason')
def xxx(a,b,c,year):
return '%s?%s|%s{%s'%(a,b,c,year)
自定义inclusion_tag
接受用户传入的参数 然后作用于一个html页面,在该页面上渲染数据,之后将渲染好的页面放到用户调用inclusion_tag的地方
@register.inclusion_tag('bigplus.html')
def bigplus(n):
l = []
for i in range(n):
l.append('第%s项'%i)
return {'l':l}
模版的继承
在多个页面整体样式都差不多的情况下,这时候就可以设置一个模版文件了,在该模版文件中,使用block划分多个区域,之后子版本在使用模版的时候 可以通过block块的名字来选定到底需要修改哪一部分区域
模版一般情况下 都应该至少有三个可以被修改的地方
1、子页面自己的css代码
2、子页面自己的html代码
3、子页面自己的js代码
一般情况下 模版上的block越多,页面的可扩展性就越强
模版的导入
{% include 'beautiful.html' %} 当你写了一个特别好看的form表单/列表标签等
可以将它当成一个模块 哪个地方需要 就直接导入使用即可
Django--路由层、视图层、模版层的更多相关文章
- day 45 Django 的初识2 路由层,视图层,模板层
前情提要: 今天继续学习Django 的内容, 今天主要和渲染相关 1>配置路由 >2:写函数 >3 指向url 一:路由层 1:配置静态支持文件 1:路由层的简单配置 >dj ...
- [Django框架之视图层]
[Django框架之视图层] 视图层 Django视图层, 视图就是Django项目下的views.py文件,它的内部是一系列的函数或者是类,用来专门处理客户端访问请求后处理请求并且返回相应的数据,相 ...
- Web框架之Django_03 路由层了解(路有层 无名分组、有名分组、反向解析、路由分发 视图层 JsonResponse,FBV、CBV、文件上传)
摘要: 路由层 无名分组 有名分组 反向解析 路由分发 名称空间 伪静态网页.虚拟环境 视图层 JsonResponse FBV 与 CBV(function base views与class bas ...
- Django 学习 之 视图层(views)
一个视图函数,简称视图,是一个简单的Python 函数,它接受Web请求并且返回Web响应.响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. . . 是任何 ...
- Django的日常-视图层
目录 Django的日常-3 JsonResponse form表单上传文件 CBV的源码分析 视图层 模板传值 过滤器 标签 自定义过滤器和标签 Django的日常-3 JsonResponse 在 ...
- Django基础之视图层
内容概要 小白必会三板斧 request对象方法初识 form表单上传文件 Jsonresponse FBV与CBV 内容详细 1 小白必会三板斧 HttpResponse render redire ...
- Django学习之视图层
视图层 小白必会三板斧 HttpResponse render redirect django视图函数必须要给返回一个HttpResponse对象(render和redirect内部返回的也是一个Ht ...
- django路由匹配层
目录 orm表关系如何建立 一对多 多对多 一对一 django请求生命周期流程图 路由层 路由的简单配置 Django路由匹配规律 分组 无名分组 有名分组 反向解析 路由分发 名称空间 伪静态 虚 ...
- Django 路由层与视图层
1.路由层 1.1无名分组 1.2 有名分组 1.3 反向解析 1.4 路由分发 1.5 名称空间 2.伪静态网页 3.虚拟环境 4.视图层 1.1 JsonResponse 1.2 FBV与CBV ...
- $Django 虚拟环境,2.0、1.0路由层区别,Httprequest对象,视图层(fbv,cbv),文件上传
1 虚拟环境:解决问题同一台机器上可以运行不同版本的django, 1 用pychanrm创建--->files-->newproject--->选择虚拟环境 2 setting ...
随机推荐
- 正则表达式之Matcher类中group方法
前言 同事把一个excel表给我,里面的数据大概有几千的样子吧.自己需要把里面的数据一个一个拿出来做一个http请求,对得到的结果进行过滤,然后再写到上面去.这是就涉及到用脚本来进行操作了,于是自己搞 ...
- map redcue filter sorted函数
sorted 函数 接收一个key函数来实现自定义的排序 # 训练集和验证集的文件命名不一样 # test1: data/test1/8973.jpg # train: data/train/cat. ...
- mysql数据库的水平拆分与垂直拆分
近端时间在面试,发现很多面试官或者面试都把数据的水平拆分合垂直拆分给搞混了,今天特意写了一篇博客来说说水平拆分和垂直拆分希望对程序猿们有所帮助. 数据库水平与垂直拆分: 垂直(纵向)拆分:是指按功能模 ...
- Zabbix-设置自动发现规则实例
一.前文 此篇文章,主要针对自动发现规则中使用snmpv2类型发现 zabbix官方解读,可当参考: https://www.zabbix.com/documentation/4.0/zh/man ...
- springBoot配置elasticsearch搜索
1.本地安装elasticsearch服务,具体过程见上一篇文章(安装和配置elasticsearch服务集群) 2.修改项目中pom文件,引入搜索相关jar包 <!-- elasticsear ...
- GIt到本地小技巧
运行CMD自动到C盘,假如我要把项目clone D盘 ,就要去cd : D:\.. 乱七八糟的重复工作.烦死了. 下面是更加方便的技巧 直接在要GIt clone的路径打上CMD,然后回车.方便多了, ...
- python 33 多进程(一)
目录 多进程 1. 进程创建的两种方式 multiprocessing 2. 进程pid (process id) 3. 验证进程之间的空间隔离 4. 进程对象join方法 5. 进程对象其他属性 6 ...
- Leetcode之二分法专题-154. 寻找旋转排序数组中的最小值 II(Find Minimum in Rotated Sorted Array II)
Leetcode之二分法专题-154. 寻找旋转排序数组中的最小值 II(Find Minimum in Rotated Sorted Array II) 假设按照升序排序的数组在预先未知的某个点上进 ...
- Java 从入门到进阶之路(五)
之前的文章我们介绍了 Java 的循环结构,本章我们来看一下 Java 的数组 数组对于每一门编程语言来说都是重要的数据结构之一,当然不同语言对数组的实现及处理也不尽相同. 数组 - 相同数据类型的元 ...
- 【selenium】- 常见浏览器的启动
本文由小编根据慕课网视频亲自整理,转载请注明出处和作者. 1. Firefox启动 webdriver自带了firefox浏览器的驱动,所以不需要设置它的驱动. 如果firefox没有安装在默认路径, ...