python-django-02-django生命周期(URL、视图、模板)

一、路由控制

URL配置(URLconf)就是 Django 所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表;客户端就是以这种方式告诉Django,对于客户端发来的某个URL调用哪一段逻辑代码对应执行

1.1、URL分组

1.1.1、简单配置

# 与django 1不同的是 django 2 3使用的是path
    -第一个参数是正则表达式(如果要精准匹配:'^publish/$')
    -第二个参数是视图函数(不要加括号)
    -url(r'^admin/', admin.site.urls),

# django 3
from django.urls import path
from bm import views

urlpatterns = [
    path("test/", views.test),
    path("/test", views.hello, {"id":1})
]

def hello(request,id): pass     # 从路由层就能直接将id传给hello,一个默认值 

1.1.2、无名分组

  • 按位置传参, 正则匹配
  • 分组之后,会把分组出来的数据,当位置参数,传到视图函数,所以,视图函数需要定义形参
  1. django1 写法
# django 1写法
    -url(r'^publish/([0-9]{4})/([0-9]{2})$', views.publish),
    -def publish(request,*args):   视图函数可以这样接收
  1. django2\3
# django 2、3写法
from django.urls import path, re_path

urlpatterns = [
	# url http://xx/port/这里可以定义最少0个-4个的数字
#    re_path('^port/([0-9]{0,4})$', views.port),
    # 匹配数字的url
    re_path("^test2/(\d+)$", views.port),
    # 匹配字母数字及下划线,啥样的格式皆可
	re_path("^test3/(\w+)$", views.test3)
]

# 后端的port可以接收到 url中传递的无名分组
def port(request, num):
    print(num)
    return HttpResponse("port")

1.1.3、有名分组

  • 按关键字传参
  • 有名分组之后,会把分组出来的数据,当关键字参数,传到视图函数,所以,视图函数需要定义形参,形参名字要跟分组的名字对应,与顺序无关
  • 有名分组,函数接收需要 关键字参数, 语法: (?P 这里写正则 )
  1. django1
-url(r'^publish/(?P<year>[0-9]{4})/(?P<mounth>[0-9]{2})/$', views.publish),
-def publish(request, mounth,year):
*****有名分组和无名分组,不要混用
  1. django2\3

    from django.urls import path, re_path
    from test_url import views
    
    urlpatterns = [
        re_path("^test4/(?P<one>\d+)", views.test4),
    ]
    
    # 浏览器中Url: /test4/1111
    def test4(request, **kwargs):
        print(kwargs)		# {'one': '1111'}
        return HttpResponse("test4")
    

1.1.4、PATH 转化器

Django默认支持以下5个转化器: 语法:path('test/<int:name>', test)

  • str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
  • int,匹配正整数,包含0。
  • slug,匹配字母、数字以及横杠、下划线组成的字符串。
  • uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
  • path,匹配任何非空字符串,包含了路径分隔符(/)(不能用?)
urlpatterns = [
    # path("test5/<int:key1>", views.test5),
    path("test5/<path:key1>", views.test5),	# 如 {'key1': '321/adf1/vheid'}
    # path("test5/<str:key1>", views.test5),
]

1.1.5、append_flash

# settings.py中添加这个,就不会自动在url后添加 / 了
APPEND_FLASH = False

1.2、反向解析(url,reverse)

如果在html页面中直接死写url,那么后期在修改函数名时会造成代码修改过多,过于复杂的局面,此时使用反向解析就很有必要了

1.2.1、无参数

# 从html页面 test6 中点击跳转, 逐步跳到 test8 反向解析 

# 1、 m:url
urlpatterns = [
    re_path("test6/$", views.test6, name="test6"),
    re_path("test7/$", views.test7, name="test7"),
    re_path("test8/$", views.test8, name="test8"),
]

# 2、 v:视图
from django.shortcuts import render, HttpResponse, reverse, redirect
    def test6(request):
        return render(request, "test6.html")

    def test7(request):
        # 也可以直接在这里打印
        return redirect(reverse("test8"))

    def test8(request):
        return HttpResponse("test7 在跳 test8")
    
# 3、 t:模板
    <a href='{% url "test7" %}'>点我跳转</a>

1.2.2、无名分组

# 1、 m:url
urlpatterns = [
    re_path("test6/", views.test6, name="test6"),
    re_path("test7/(\d+)", views.test7, name="test7"),
    re_path("test8/(\d+)/$", views.test8, name="test8"),
]

# 2、 v:视图, 要是有多个参数,也是一样传
from django.shortcuts import render, HttpResponse, reverse, redirect
    def test6(request):
        return render(request, "test6.html")

    def test7(request, *args):
        # 注意 args=(参数,) 或 args=(参数1,参数2,.....)	# 注意要有逗号
        return redirect(reverse("test8", args=(args[0],)))

    def test8(request, *args):
        return HttpResponse("test7 在跳 test8")

# 3、 t:模板
    <a href='{% url "test7" 2022 %}'>点我跳转</a>

1.2.3、有名分组

# 1、 m:url
    urlpatterns = [
        re_path("test6/", views.test6, name="test6"),
        re_path("test7/(?P<arg1>\d+)/(?P<arg2>\d+)", views.test7, name="test7"),
        re_path("test8/(\d+)/(\d+)/$", views.test8, name="test8"),
        re_path("test9/(?P<arg1>\d+)/(?P<arg2>\d+)", views.test9, name="test9"),
    ]
    
# 2、 v:视图
def test6(request):
    return render(request, "test6.html")


def test7(request, **kwargs):
    # print(kwargs)   # {'arg1': '2022', 'arg2': '2023'}
    # return redirect(reverse("test8", args=(1111,222,)))		
    return redirect(reverse("test9", kwargs=kwargs))

# 注意 test8跟test9的区别, 位置参数跟关键字参数
def test8(request, *args):
    return HttpResponse("test7 在跳 test8")

# 返回values至前端
def test9(request, **kwargs):
    return HttpResponse(kwargs.values())

# 3、 t:模板
	<a href='{% url "test7" arg1=2022 arg2=2023 %}'>点我跳转</a>
# 也可以 <a href='{% url "test7" 2022 2023 %}'>点我跳转</a>

总结

#  URL
from django.urls import path, re_path
无参数:   re_path("test6/", views.test6, name="test6"),
有名分组: re_path("test7/(?P<arg1>\d+)/(?P<arg2>\d+)", views.test7, name="test7"),
无名分组: re_path("test8/(\d+)/(\d+)/$", views.test8, name="test8"),

# 视图
导入模块: from django.shortcuts import  reverse
return redirect(reverse("test8", args=(1111,222,)))
return redirect(reverse("test9", kwargs={”key1":"value1",”key2":"value2",}))

# 模板层:
无参数:    {% url 'test6' %}
无名分组的:{% url 'test7' 2021 2022 %}
有名分组:  {% url 'test7' 2021 2022 %}  还可以 {% url 'ddd' arg1=2021 arg2=2022 %}

1.3、路由分发-include

from django.urls import path, re_path, include

# 将多个app在根url下统一进行分发
urlpatterns = [
    re_path('^app01/', include('app01.urls')),
    re_path('^app02/', include('app02.urls')),
]

# app01应用下创建urls.py文件
from django.urls import path, re_path, include
from test_url import views

urlpatterns = [
    re_path("test6/", views.test6, name="test6"),
]

# 在不同的app里创建urls.py
# 在不同的app的urls里配置路由关系	
# ***重点***总路由,不能加结束符$

1.4、名称空间

namespace, django2 后已删除, 官方说明

Support for setting a URL instance namespace without an application namespace is removed.

-url(r'^blog/',include('blog.urls',namespace='blog')),

-子路由:url(r'^publish/$', views.publish,name='test'),

-反向解析:
    -视图层:url = reverse('blog:test')
    -模板层:{% url 'app01:test'%}

***一般不要用***
    子路由:url(r'^publish/$', views.publish,name='app01_test'),

django2 后使用就变成了 app_name

from django.urls import path, re_path, include

# 将多个app在根url下统一进行分发
urlpatterns = [
    path('app01/', include('app01.urls')),
]

# 当有多个相同的名称时, 就可以使用 app_name, 在app01.urls中定义
app_name="app01"
urlpatterns = [
    path('test/', views.test, name="test"),
]

在视图中定直接就可以使用  return redirect(reverse("app01:test")), 跟名称空间一样

匹配demo

# 直接匹配根目录     		re_path("^$", views.index),
# 匹配不到的页面返回404	   re_path("", views.errors)

二、视图层

views.py, 通过include可以对应不同的视图层

2.1、视图层对象

2.1.1、HttpRequest

# 前台Post传过来的数据,包装到POST字典中		request.POST

# 前台浏览器窗口里携带的数据,包装到GET字典中	 request.GET

# 前台请求的方式 							request.method

# post提交的数据,body体的内容,前台会封装成:name=lqz&age=18&sex=1		request.body

# 取出请求的路径,取不到数据部分				 print(request.path)

# 取出请求的路径,能取到数据部分
# print(request.get_full_path()) \ print(request.META)

2.1.2、JsonResponse

如果想要前台端分离,那么就可以直接使用JsonReponse来直接传递

form django.http import JsonResponse

def jsontest(request):
    # JsonResponse 实际部署
    # 字典形式返回
    # import json
    # dic = {"id": 1, "teacher": "xiong"}
    # return HttpResponse(json.dumps(dic))

    # dic = {"id": 1, "teacher": "xiong"}
    # return JsonResponse(dic)

    # 列表
    # import json
    jlist = ['xiong', 'wen']
    # return HttpResponse(json.dumps(jlist))

    # return JsonResponse(jlist)     # 默认jsonresponse不支持直接转化列表
    return JsonResponse(jlist, safe=False)   # 可以设置safe为false就能直接在前台展示 

2.2、CBV、FBV

2.2.1、CBV

# CBV: 基于类的视图
urlpatterns = [
    path("fbvtest/", Vtest.as_view()),
]

class Vtest(View):
    def get(self, request):
        return HttpResponse("get")

    def post(self, request):
        return HttpResponse("post")

# 源码分析 Vtest.as_view()
	1、到as_view
    @classonlymethod	# 类方法
    def as_view(cls, **initkwargs):
        def view(request, *args, **kwargs):	# 闭包函数
            self = cls(**initkwargs)
            self.setup(request, *args, **kwargs)
			。。。
            return self.dispatch(request, *args, **kwargs)	# 分发

    2、分发到 dispatch
	# return self.dispatch(request, *args, **kwargs)	
        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.
        if request.method.lower() in self.http_method_names:
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)
    
    3、类的方法
    # request.method.lower() in self.http_method_names
    	http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head',。。]
		# 如果有这样方法 则直接返回 return handler(request, *args, **kwargs)
        handler就相当于是 get(request, *args, **kwargs)
        
	4、返回handler,  self.http_method_names 对应的方法
    Vtest.as_view() = return self.dispatch = return handler
	最终就相当是  Vtest.http_method_names(request, *args, **kwargs))

2.2.2、FBV

# FBV:  基于函数的视图

re_path('list/(?P<name>(\w)+)$', applist, name="applist"),

def applist(request):
    if request.method == "GET":
	    return redirect(reverse('applist', kwargs={"name": "xiong"}))
    if request.method == "POST":
        return HttpResponse("hello post")

2.3、文件上传

  1. CBV
# 视图层
class Upfile(View):

    def get(self, request):
        return render(request, "files/upfiles.html")

    def post(self, request):
        # type(request.FILES)
        # from django.utils.datastructures import MultiValueDict
        print(type(request.FILES.get("get_file")))

        # django.core.files.uploadedfile.InMemoryUploadedFile
        from django.core.files.uploadedfile import InMemoryUploadedFile

        get_file = request.FILES.get("get_file")
        print(get_file.content_type.rsplit("/")[1])   # 获取类型

        abs_file = os.path.join(BASE_DIR, "media", get_file.name)
        with open(abs_file, "wb") as file:
            for line in get_file.chunks():
                file.write(line)

        return HttpResponse("ok")

# URL层
urlpatterns = [
    path("upfile/", views.Upfile.as_view(), name="file_upfile")
]

# 模板
<form action="{% url "file_upfile" %}" method="post" enctype="multipart/form-data">
    <p>上传文件:<input type="file" name="get_file"></p>
    <p><input type="submit" value="提交"></p>
</form>
  1. FBV
# views.py
def fileupload(request):
    if request.method == "GET":
        return render(request, 'fileup.html')
    if request.method == "POST":
        upfile = request.FILES.get('upfile')
        # from django.core.files.uploadedfile import InMemoryUploadedFile
        savefile = os.path.dirname(os.path.dirname((os.path.abspath(__file__))))
        savefiledir = os.path.join(savefile, 'media', upfile.name)
        with open(savefiledir, 'wb') as file:
            for line in upfile.chunks():
                file.write(line)
        return HttpResponse("ok")

# urls层
urlpatterns = [
    path('admin/', admin.site.urls),
    path('fileupload/', views.fileupload),
]

template html
<form action="/fileupload/" method="post" enctype="multipart/form-data">
    <div><input type="file" name="upfile"></div>
    <div><input type="submit" value="提交"></div>
</form>

2.3.1、源码分析

# 需要格外注意的是  这里的格式一定要是 enctype="multipart/form-data">
# python 只处理了 application/x-www-form-urlencoded,multipart/form-data这两种格式上传文件

print(type(request.FILES.get("get_file")))
# from django.core.files.uploadedfile import InMemoryUploadedFile

class InMemoryUploadedFile(UploadedFile):
    """
    A file uploaded into memory (i.e. stream-to-memory).
    """
    def __init__(self, file, field_name, name, content_type, size, charset, content_type_extra=None):
        super().__init__(file, name, content_type, size, charset, content_type_extra)
        self.field_name = field_name

    def open(self, mode=None):
        self.file.seek(0)
        return self

    def chunks(self, chunk_size=None):
        self.file.seek(0)
        yield self.read()

三、模板层

模板层参考

  • 对页面设计进行的任何改变都必须对 Python 代码进行相应的修改。 站点设计的修改往往比底层 Python 代码的修改要频繁得多,因此如果可以在不进行 Python 代码修改的情况下变更设计,那将会方便得多。

  • Python 代码编写和 HTML 设计是两项不同的工作,大多数专业的网站开发环境都将他们分配给不同的人员(甚至不同部门)来完成。 设计者和HTML/CSS的编码人员不应该被要求去编辑Python的代码来完成他们的工作。

  • 程序员编写 Python代码和设计人员制作模板两项工作同时进行的效率是最高的,远胜于让一个人等待另一个人完成对某个既包含 Python又包含 HTML 的文件的编辑工作。

  • 基于这些原因,我们可以将页面的设计和Python的代码分离开会更干净简洁更容易维护。 我们可以使用 Django的 *模板系统* (Template System)来实现这种模式

3.1、变量&过滤器&标签

3.1.1、变量

# 通过 locals() 可以将 函数内的所有属性都传到前端
class Temptest(View):
    def get(self, request):
        strs = "xiong"
        tu = (1,2,3,4)
        dic = {"name": "xiong", "ll": ["tom", "col", "local"]}
        lis = ["tom", "ren", "requ"]

        def test():
            return "hello"

        class Tests:
            def __init__(self, name, age):
                self.name = name
                self.age = age

            def get_age(self):
                return self.age

            @classmethod
            def get_tests(cls):
                return "我是类方法"

        t = Tests("xiong", 100)
        gtime = datetime.datetime.now()
        return render(request, "files/temps.html", locals())


# 模板变量  {# 模板层的注释,在前端页面中不会被查询访问到 #}
<p>字符串: {{ strs }}</p>
<p>元组: {{ tu }}</p>
<p>字典加列表: {{ dic }}</p>		# 字典加列表: {'name': 'xiong', 'll': ['tom', 'col']}
<p>列表: {{ lis }}</p>		  # 列表: ['tom', 'ren', 'requ']
<p>函数: {{ test }}</p>   {# 相当于是 直接 print(test()) #}

<p>: {{ t }}</p>
{#  <files.views.Temptest.get.<locals>.Tests object at 0x0。。> #}

<hr>
<p>从字典中取列表: {{ dic.ll }}</p>    {# 通过句点符来取出 #}
<p>从类取方法: {{ t.get_age }}</p>	 {# 不需要加括号就可以直接执行 #}
<p>从类中取类方法: {{ t.get_tests }}</p>

3.1.2、模板-过滤器

# 语法: <第一个参数:过滤器属性:第二个参数>

<p>获取长度: {{ strs|length }}</p>				 	# 获取长度: 5
<p>列表默认值: {{ lis|default:"none" }}</p>			# 列表默认值: ['tom', 'ren', 'requ']
<p>filesizeformat: {{ 122222|filesizeformat }}</p> # 转换大小文件: 119.4 KB
 
# 从第3个字符串开始算truncatechars: hello w…
<p>truncatechars: {{ "hello world world"|truncatechars:8 }}</p> 
    
<p>get_time: {{ gtime|date }}</p>			# get_time: Jan. 11, 2021
<p>get_time: {{ gtime|date:"Y-m-d" }}</p>	# get_time: 2021-01-11

{#  后端传到前端的页面需要加上safe但与之相对的会有css攻击风险 #}
<p>{{ page|safe}} </p>		# 如果无法判断页面是否安全, 则不要使用

3.1.3、过滤器-扩展

在这里插入图片描述

3.1.4、标签

模版语法:标签 {% %}, for, if, with 都需要有结束,前面加一个end

  1. for

    {% for foo in lab_dic %}
        {# {{ forloop }}#}
       前台打印结果: {# {'parentloop': {}, 'counter0': 0, 'counter': 1, 'revcounter': 2, 'revcounter0': 1, 'first': True, 'last': False}#}
    
        {#  revcounter 倒序查看从1开始   counter 从1开始  后面加个零表示从0开始 #}
        <p>{{ forloop.revcounter }} --> {{ forloop.counter }} --> {{ foo.name }}</p>
    {% endfor %}
    
    {# 测试empty 但字典或列表为空才执行 #}
    {% for foo in lab_null_for %}
        <p>{{ foo }}</p>
    {% empty %}
        <p>空值</p>
    {% endfor %}
    
  2. if

    {# 判断是否非空, 如果是空的打印if  如果不是打印lab_null_for #}
    {% if not lab_null_for %}
        <p>空的</p>
    {% else %}
        <p>{{ lab_null_for }}</p>
    {% endif %}
    
  3. with

    {#  打印别名, 在with如果有多行一样的代码,定义成别名可简化代码量 #}
    {% with lab_dic.1.name as dic %}
        <p>打印with别名, 直接获取列表中字典第二个的name:  {{ dic }}</p>
    {% endwith %}
    # 需要包含在with中才能被打印
    

3.2、模板-自定义

过滤器、标签前几步的步骤都一样, 需要注意的是: 标签不能用在if判断,过滤器可以用在if判断

  1. 先在setting.py下注册app
  2. 在app下创建 templatetags文件夹,如 test/templatetags/my_filter.py
  3. 新建一个py文件 如 my_filter.py

3.2.1、自定义过滤器-filter

  1. 仿length过滤器

    # 自定义一个仿length的过滤器
    from django.template import Library
    
    register = Library()
    
    @register.filter(name="clength")
    def custom_length(value):
        if value is not None:
            if isinstance(value,int):
                value = str(value)
            return len(str(value))
        raise TypeError("类型错误或为空")
    
  2. 仿add过滤器,支持数字、字符串

    @register.filter()
    def custom_add(value1, value2):
        try:
            return int(value1) + int(value2)
        except ValueError:
            return str(value1) + str(value2)
        except:
            return "类型或其它错误"
    
  3. html中调用

    # html中使用
    # 一、先load
    	{% load my_filter %}	# 需要注意的是这里应使用模板的方法导入
    # 二、使用
    	{{ name|clength }}		# name是从views.py中传入
        {{ name|custom_add:123 }}	
        
    # 如果长度name是整形或为空则判断错误,其它类型基本能判断出来
    # 添加name,如果是列表或字典\set类型,则会返回类型错误, 类型错误会先内部转换
    
  4. views.py

    def custest(request):
        # name="xiong"
        name = 123
        return render(request, "custom/custom_index.html", locals())
    

3.2.2、自定义标签-simple_tag

  1. 拼接3个参数

    @register.simple_tag()
    def custom_simple(value1, value2, value3):
        return value1 + value2 + value3
    
    # 模板中引用, 页面中的结果就是 xiong+++nnnnn
    {% custom_simple "xiong" "+++" "nnnnn" %}
    
  2. 返回html

    from django.template import Library
    from django.utils.safestring import mark_safe
    
    register = Library()
    
    @register.simple_tag
    def my_input(id, arg):
        result = "<input type='text' id='%s' class='%s' />" %(id, arg,)
        return mark_safe(result)	# 界面效果就是一个Input框
    	# return result  # <input type='text' id='123' class='321' />
    
    

3.2.3、html代码片段

inclusion_tag 与simple_tag有点类型但不太一样,这个是直接返回html页面

  1. 创建标签属性

    from django.template import Library
    
    register = Library()
    
    # def inclusion_tag(self, filename, func=None, takes_context=None, name=None):
    # 只传一个filename
    @register.inclusion_tag("test.html")
    def my_inclusion(num):
        # 这里应该做一个判断
        li = ["hello {}".format(i) for i in range(int(num))]
        return {"li": li}		{"li":[1,2,3,4,5]}
    
  2. 创建test.html, 注意这个文件应该放在 template目录下

    <ul>
        {% for foo in li %}
            <li>{{ foo }}</li>
        {% endfor %}
    </ul>
    
  3. 引用

    {% load my_html %}
    {% my_inclusion 10 %}	# 10行
    
  4. 效果

    hello 0
    hello 1
    hello 2
    

3.3、模板-导入&继承

3.3.1、母板及继承关系

  1. 视图&url
# url访问
urlpatterns = [
    path("temp/", views.temp)
]

# 视图
def temp(request):
    return render(request, "custom/temp_test.html")
  1. 模板母板 base.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/bootstrap.css">
    <style>
        .header {
            height: 100px;
            background-color: #c6cef6;
        }
    </style>
</head>
<body>

<div class="header"></div>
<div class="container-fluid">
    <div class="row">
        <div class="col-md-2">
            {% include 'custom/left.html' %}	{# 引入模板、继承left.html #}
        </div>

        <div class="col-md-9">
            {% block context %}			# 子模版可能会覆盖掉模版中的这些位置
                <p>hello world</p>		# 母板中的内容,在子模板引用会被覆盖
            {% endblock %}
        </div>
    </div>
</div>

</body>
</html>
  1. 模板导入 custom/left.html
在母板中的这一句:{% include 'custom/left.html' %},导入的内容

<div class="card" style="width: 18rem;">
    <p></p>
    <ul class="list-group list-group-flush">
        <li class="list-group-item">Cras justo odio</li>
        <li class="list-group-item">Dapibus ac facilisis in</li>
        <li class="list-group-item">Vestibulum at eros</li>
    </ul>
</div>
  1. url中定义的custom/temp_test.html
{% extends 'custom/base.html' %}	# 继承母板

{% block context %}				    # 母板中传递的盒子数据,可以在这里定义
    <p>1111111111111</p>
    <p>1111111111111</p>
    {{ block.super }}				# 母板中的某些内容,可以被继承过来使用
{% endblock context %}				# 如果有多个盒子可以直接使用 block

3.3.2、模板-静态文件

  1. 静态文件相关的配置

    # 定义别名, 这个只是STATICFILES_DIRS定义之后路径的别名 如/static/css/ 而实际可能是/hello/static/css
    STATIC_URL = '/static/'
    # 实际的静态文件路径, 以逗号分割可以有多个路径
    STATICFILES_DIRS = [
        os.path.join(BASE_DIR, 'static')
    ]
    
  2. html页面中的静态引入方式

    # 三种 
    # 当定义的别名更改时,这个路径也得更改
    直接引用: <link rel="stylesheet" href="/static/css/my.css">
    
    标签引用一  毕竟得先引用标签, 然后在模版中引用,这些当别名更改后,路径也会随static_url更改
        {% load static %}  
        <link rel="stylesheet" href="{% static 'css/my.css' %}">
    
    标签引用二    意思同上
    	{% load static %}  
        <link rel="stylesheet" href="{% get_static_prefix %}css/my.css">
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值