昨日内容回顾 路由层 路由匹配 url(正则表达式,视图函数内存地址) 只要正则匹配到了内容,就不再继续往下匹配,而是直接后面的视图函数 匹配首页 url(r‘^$‘,home) 匹配尾页 url(r‘‘,errors) 路由匹配的规律 第一次按照用户输入什么就匹配什么如果匹配不上 第二次django会让浏览器自动再尾部加斜杠再次匹配 还匹配不上就会报错 上述规律不是浏览器的特点,是django的功能 django settings文件中 APPEND_SALSH = True # 自动加斜杠 """为什么setting文件中变量名必须写全大写""" 无名分组 路由匹配成功之后,如果正则表达式中有分组的,那么在调用视图函数的时候 会将括号内正则表达式匹配到的内容当做位置参数传递给后面的视图函数 url(r‘^index/(\d+)/‘,index) def index(request,args): return ‘HttpResponse对象‘ 有名分组 路由匹配成功之后,如果正则表达式中有分组并且起了别名的,那么在调用视图函数的时候 会将括号内正则表达式匹配到的内容当做关键字参数传递给后面的视图函数 url(r‘^index/(?P<year>\d+)/‘,index) def index(request,year): return ‘HttpResponse对象‘ 无名分组与有名分组不能混合使用(*****) 但是两者单独使用的时候可以有多个无名或者有名 反向解析 由来当有很多html页面和后端代码中频繁的使用了指名道姓的ulr(/index/) 那么一旦路由发生了变化 前后端所有的地方都要修改,造成了可维护性较差 反向解析的本质就是通过某个方法获取的一个能够访问对应url的结果 没有涉及到正则表达式符号情况下 url(r‘^index/‘,index,name=‘aaa‘) 前端 {% url ‘aaa‘ %} 后端 from django.shortcuts import HttpResponse,render,redirect,reverse _url = reverse(‘aaa‘) 无名和有名分组的情况 无名 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‘)) """路由分发需要注意的点 1.总路由的中最后千万不要加$符号 """ 名称空间 你在起别名的时候 虽然能够同一个应用下不能重名 但是你没办法实现多个人多个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 第一个参数不再支持正则表达式 写什么就匹配什么 如果你还想使用正则 2.X里面的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}) 如果你传递的不是字典数据,那么需要手动指定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 # 原生的二进制数据 """ RBAC (role based access control) 基于角色的权限管理 当你在做权限管理的时候 需要用到 在web领域权限就是一个个的url 简单判断用户是否有权限访问某个url思路 获取用户想要访问的url 与数据库中该用户可以访问的url进行对比 """ 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()) 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() # 单例模式 作业: 参考django settings源码 实现自己的项目也能够做到 用户配置了就用用户的 用户没有配置 就用全局的 模板层 模板语法 两大类 {{}} 变量相关 {%%} 逻辑相关 为模板传值 过滤器: | 前后端取消转义: 前端: |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() 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的地方 """ # 自定义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块的名字 来选定到底需要修改哪一部分区域 模板一般情况下 应该至少有三个可以被修改的区域 {% block css %} 子页面自己的css代码 {% endblock %} {% block content %} 子页面自己的html代码 {% endblock %} {% block js %} 子页面自己的js代码 {% endblock %} # 模板的继承 使用方式 {% extends ‘home.html‘ %}
{% block css %} <style> h1 { color: red; } </style> {% endblock %}
{% block content %} <h1>登陆页面</h1> <form action=""> <p>username:<input type="text" class="form-control"></p> <p>password:<input type="text" class="form-control"></p> <input type="submit" class="btn btn-danger"> </form> {% endblock %}
{% block js %}
{% endblock %} # 一般情况下 模板上的block越多 页面的可扩展性就越强 模板的导入 {% include ‘beautiful.html‘ %} 当你写了一个特别好看的form表单/列表标签等 可以将它当成一个模块 哪个地方需要 就直接导入使用即可 作业: 1.图书管理系统尝试着使用模板的继承来写 2.自己总结 必知必会13条 返回的结果哪些是querySet对象 1.单表操作 create_time = models.DateField() 关键性的参数 1.auto_now:每次操作数据 都会自动刷新当前操作的时间 2.auto_now_add:在创建数据的时候 会自动将创建时间记录下来 后续的修改不会影响该字段 在django中 你可以写一个单独测试某一个py文件的测试脚本 不需要再频繁的走web请求 模型层的单表操作 增删改查(已经讲过的) 神奇的双下滑查询(这个是没有讲过的 5分钟左右即可) 视图层 欠的FBV与CBV django settings源码 forms组件源码 django admin源码
查看更多关于FBV or CBV django settings 源码 模板层语法 摸板的继承 摸板的导入的详细内容...