模板语法与Django部分源码

伪静态

将url地址模拟成html结尾看上去是一个静态文件目的是为了增加搜索引擎对网站的爬取和SEO

本地虚拟环境

相当于创建一个新的python环境

## Linux使用virtualenv创建虚拟环境
# 安装扩展
pip3 install virtualenv
pip3 install virtualenvwrapper

# pip使用
pip3 list	        # 列出所有的扩展
pip3 freeze       # 查看所有的扩展及版本,便于导出
pip3 show 扩展名	  # 查看扩展详细信息

# 查找路径
which virtualenvwrapper.sh
which python3
which virtualenv

# 编辑全局环境,当前用户的
vi ~/.bashrc

export WORKON_HOME=/home/lzj/.virtualenvs
source /home/lzj/.local/bin/virtualenvwrapper.sh
export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
export VIRTUALENVWRAPPER_VIRTUALENV=/home/lzj/.local/bin/virtualenv

# 生效
mkdir ~/.virtualenvs
source ~/.bashrc

# 使用
mkvirtualenv test-env	     # 创建test-env 的虚拟环境,默认进入到虚拟环境中
mkvirtualenv --python==	   # 指定python版本路径创建虚拟环境
lsvirtualenv			         # 查看所有的虚拟环境
rmvirtualenv			         # 删除
cdvirtualenv			         # 进入虚拟环境的目录,需要进入到虚拟环境
workon test-env			       # 进入test-env虚拟环境中
deactivate				         # 退出当前虚拟环境

Django 版本差别

django1.x与django2.x 3.x的区别

1.urls.py中的路由匹配方法
  1.x 第一个参数是正则表达式  url()
  2.x和3.x 第一个参数不支持正则表达式写什么匹配什么  path()

  2.x与3.x 如果要用正则表达式需要导入模块 re_path
  from django.urls import path,re_path
  re_path()  相当于 1.x的url()

2.转换器
	 五种常用转换器
    str,匹配除了路径分隔符/之外的非空字符串这是默认的形式
    int,匹配正整数包含0
    slug,匹配字母数字以及横杠下划线组成的字符串
    uuid,匹配格式化的uuid075194d3-6885-417e-a8a8-6c931e272f00
    path,匹配任何非空字符串包含了路径分隔符/)(不能用?)

     	 自定义
    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'),

    ]

三板斧本质

django视图函数必须要返回一个HttpResponse对象
'''
通过查看 HttpResponse render redirect 等源码可以看出都是返回的HttpResponse
'''

JsonResponse

需求: 给前端返回JSON格式数据

方式1: 自己序列化
  # views.py
 	def index(request):
      import json
      d = {'name': 'jason', 'age': 18, 'pwd': '123','desc':'哈哈哈'}
      res = json.dumps(d,ensure_ascii=False)  # 针对有中文的情况下
      return HttpResponse(res)


方式2: JsonResponse
  from django.http import JsonResponse
  def index(request):
      d = {'name': 'jason', 'age': 18, 'pwd': '123','desc':'哈哈哈'}
      return JsonResponse(d)

  # 额外参数补充 查看JsonResponse源码
  json_dumps_params={'ensure_ascii': False}  # 中文编码
  safe=False                                 # 默认情况只序列化字典类型,这个参数可以将非字典类型序列化

上传文件

form表单上传文件注意事项
  1.method必须是post
  2.enctype参数修改为 multipart/form-data

前端:
  <form action="" method="post" enctype="multipart/form-data">
    <p><input type="text" name="userinfo"></p>
    <p><input type="file" name="my_file"></p>
    <input type="submit">
  </form>

后端:
  def get_file(request):
      if request.method == 'POST':
      print(request.POST)
      file_obj = request.FILES.get('my_file')
      print(file_obj.name)
      with open(r'%s' % file_obj.name, 'wb') as f:
            for chunks in file_obj.chunks():  # chunks 会一行一行读取 可以提升效率
                f.write(chunks)
    return render(request, 'index.html')

  # urls.py url(...)

FBV 与 CBV

FBV基于函数的视图

CBV基于类的视图
# views.py
from django.views import View
class MyView(View):
    def get(self, request):
        return HttpResponse('get 请求')

    def post(self, request):
        return HttpResponse('post 请求')
# urls.py
   url(r'^mycbv', views.MyView.as_view())

as_view()是View类的静态方法返回的是view函数地址本质还是FBV

CBV 源码

	    def as_view(cls, **initkwargs):
            def view(request, *args, **kwargs):
                self = cls(**initkwargs)  # self = MyView()  生成一个我们自己写的类的对象
                return self.dispatch(request, *args, **kwargs)
            return view
       def dispatch(self, request, *args, **kwargs):
        # 获取当前请求并判断是否属于正常的请求(8个)
        if request.method.lower() in self.http_method_names:
            # get请求  getattr(对象,'get')   handler = 我们自己写的get方法
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)  # 执行我们写的get方法并返回该方法的返回值

      # 面向对象的反射

settings 源码

"""
1.django其实有两个配置文件
	一个是暴露给用户可以自定义的配置文件
		项目根目录下的settings.py
	一个是项目默认的配置文件
		当用户不做任何配置的时候自动加载默认配置
        from django.conf import global_settings(所有全局配置global_settings)
2.配置文件变量名必须是大写
"""
疑问:为什么当用户配置了就使用用户配置的 不配置就是要默认的
from django.conf import settings

settings = LazySettings()

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day05.settings")
ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
class LazySettings(LazyObject):
    def _setup(self, name=None):
        # os.environ看成是一个全局大字典      'day05.settings'
        settings_module = os.environ.get(ENVIRONMENT_VARIABLE)
        self._wrapped = Settings(settings_module)  # Settings('day05.settings')

class Settings(object):
    def __init__(self, settings_module):  # 'day05.settings'
        for setting in dir(global_settings):  # 获取全局配置文件里面所有的变量名
            if setting.isupper():  # 校验是否是纯大写
                setattr(self, setting, getattr(global_settings, setting))
                # 给Settings对象添加全局配置文件中所有的配置信息

        self.SETTINGS_MODULE = settings_module  # 'day05.settings'
        mod = importlib.import_module(self.SETTINGS_MODULE)
        # from day05 import settings  # 导入暴露给用户的自定义配置文件
        for setting in dir(mod):
            if setting.isupper():
                setting_value = getattr(mod, setting)
                setattr(self, setting, setting_value)

模板语法

传值

def index(request):
    i = 666
    f = 1.1
    s = 'hello world'
    l = [11, 22, 33, 44]
    d = {'username': 'jason', 'pwd': 123}
    t = (1, 2, 3)
    se = {11, 22, 33}
    b = True
    # 传值方式1
    # return render(request, 'index.html', {'i': i, 's': s, 'd': d})
    # 传值方式2
    # return render(request, 'index.html', locals())


传值方式1: 利用字典单个传
  return render(request, 'index.html', {'i': i, 's': s, 'd': d})

传值方式2: locals() 将当前名称空间所有变量传递给页面
  return render(request, 'index.html', locals())

区别:
  方式1 传值精确 不会造成资源浪费
  方式2 一次性全部传值 可能会造成资源浪费

补充:传递函数名和类名都会自动加括号调用(模板语法不支持额外的传参)

获取值

模板语法取值只能采用 句点符(.)
列表的索引值和字典的键值都可以通过 . 一直往下取值
{{  }}

# 后端的视图函数
def index(request):
    d = {'username': 'jason', 'pwd': 123, 'hobby': [111, 222, 333, {'desc': '这个是字典下的列表里面的字典'}]}
    return render(request, 'index.html', locals())

# 前端取值
<p>{{ d.hobby.3.desc }}</p>

过滤器

类似于python的内置方法
前端:
<p>统计长度{{ s|length }}</p>
<p>加法运算{{ i|add:1000 }}</p>
<p>字符拼接{{ s|add:'python' }}</p>
<p>日期格式{{ ctime|date:'Y年-m月-d日' }}</p>
<p>默认值{{ b|default:'aaaa' }}</p>
<p>默认值{{ b1|default:'aaaa' }}</p>
<p>文件大小{{ file_size|filesizeformat }}</p>
<p>截取文本(三个点也算){{ s|truncatechars:6 }}</p>
<p>截取文本(三个点不算){{ s|truncatewords:2 }}</p>
<p>safe可以解析字符串内的标签{{ h|safe }}</p>
<p>{{ sss }}</p>
<p>{{ sss1 }}</p>

后端views.py
def index(request):
    i = 666
    f = 1.1
    s = 'hello world'
    l = [11, 22, 33, 44]
    d = {'username': 'jason', 'pwd': 123, 'hobby': [111, 222, 333, {'desc': '这个是字典下的列表里面的字典'}]}
    t = (1, 2, 3)
    se = {11, 22, 33}
    b = True
    b1 = False
    ctime = datetime.today()
    file_size = 5012341
    h = '<h1>哈哈哈</h1>'
    sss = '<h2>老子要挣大钱</h2>'
    from django.utils.safestring import mark_safe
    sss1 = mark_safe('<h2>老子要挣大钱</h2>')
    return render(request, 'index.html', locals())

# 后端写好的标签字符串也可以在前端解析
  方式1: 后端字符串变量|safe
  方式2:
    from django.utils.safestring import mark_safe
    sss1 = mark_safe('<h2>老子要挣大钱</h2>')  # 前端直接使用该变量值就可以解析

标签

类似于python的逻辑控制
# if语句
{% if file_size %}
    <p>有值</p>
{% else %}
    <p>无值</p>
{% endif %}

# forloop是内置对象 有first  last等 可以提供循环的判断
{% for foo in l %}
    <p>{{ forloop }}</p>
{% endfor %}

# for和if判断结合
{% for foo in s %}
    {% if forloop.first %}
        <p>这是第一次</p>
    {% elif forloop.last %}
        <p>这是最后一次</p>
    {% else %}
        <p>{{ foo }}</p>
    {% endif %}
     {% empty %}
        <p>传入的数据是空的</p>
{% endfor %}

# empty 当循环的值时空的时候就会走 这条后的逻辑

{{}}    # 变量相关
{% %}   # 逻辑相关

# 相当于取别名,而且该别名只在 with 块内生效
{% with d.hobby.3.desc as desc %}
    {{ desc }}
{% endwith %}

自定义

类似于python里面的自定义函数
1.应用下创建一个名字必须为 templatetags 文件夹
2.上述文件夹内创建一个任意名称的py文件
3.在该文件内固定先书写以下两行代码
	from django import template
  register = template.Library()

# templatetags/mytag.py
# 自定义过滤器
@register.filter(name='myfilter')
def index(a, b):  # 只能接收两个参数,需要传入多个参数可以让这两个参数按照一定字符分割'a|b|c'
    return a + b

# 自定义标签
@register.simple_tag(name='mysimple')
def func1(a, b, c, d):
    return '%s ** %s | %s > %s' % (a, b, c, d)

# 自定义inclusion_tag
@register.inclusion_tag('login.html', name='my_inclusion_tag')
def func2(n):
    l = []
    for i in range(1, n + 1):
        l.append('第%s页' % i)
    return locals()

# login.html
<ul>
    {% for foo in l %}
        <li>{{ foo }}</li>
    {% endfor %}
</ul>

# 前端使用
{% load mytag %}                   # 先加载mytag.py的名称
{{ i|myfilter:100 }}               # i 参数来自后端 100 是第二个参数 然后相加
{% mysimple 2 'xxx' 8 'jjj' %}     # 传入四个参数
{% my_inclusion_tag 10 %}          # 将 my_inclusion_tag 生成的 login.html 传给当前html
{% my_inclusion_tag 8 %}

模板导入

类似于python的模块可以将局部页面直接导入即可

# 模板页面内容
<h1>这是一个form表单</h1>

# 想要引用模板文件,用如下方式
{% include 'myform.html' %}

# 这种导入和上述的 inclusion_tag 有点像,但是这种方式是导入的静态写死的页面

模板继承

在html页面内使用 block 划定指定区域
母版
    {% block 区域名称 %}
    {% endblock %}

子版
	{% extends 'home.html' %}
  {% block 区域名称 %}
  		可以替换成自己页面
      同时还可以继承使用母版   {{ block.super }}
	{% endblock %}

母版在划定区域的时候一般划成三个区域
	css
  html
  js

  {% block css %}
  {% endblock %}

  {% block content %}
  {% endblock %}

  {% block js %}
  {% endblock %}

image-20220224195506829

image-20220224195530524

image-20220224195619269

image-20220224195632402

image-20220224195650917

image-20220224195723636