草庐IT

django框架全解

Generalzy 2023-06-29 原文

目录

简介

MVC与MTV模型

MVC

MVC就是把Web应用分为模型(M),控制器©和视图(V)三层,他们之间以一种插件式的、松耦合的方式连接在一起,模型负责业务对象与数据库的映射(ORM),视图负责与用户的交互(页面),控制器接受用户的输入调用模型和视图完成用户的请求。

MTV

Django的MTV模式本质上和MVC是一样的,也是为了各组件间保持松耦合关系,只是定义上有些许不同,Django的MTV分别是值:

  1. M 代表模型(Model): 负责业务对象和数据库的关系映射(ORM)。
  2. T 代表模板 (Template):负责如何把页面展示给用户(html)。
  3. V 代表视图(View): 负责业务逻辑,并在适当时候调用Model和Template。

除了以上三层之外,还需要一个URL分发器,它的作用是将一个个URL的页面请求分发给不同的View处理,View再调用相应的Model和Template。

创建项目

# 在命令行执行以下指令,会在当前目录生成一个名为appserver的文件夹,该文件夹中包含Django框架的一系列基础文件
django-admin startproject appserver

# 切换到appserver目录下边
cd mysite 
# 创建功能模块user,此处的startapp代表创建application下的一个功能模块。
python manage.py startapp user

# 运行http://127.0.0.1:8000
python manage.py runserver 8000

目录

-manage.py---项目入口,执行一些命令
-项目名
    -settings.py  全局配置信息
    -urls.py      总路由
-app名字
    -migrations   数据库迁移的记录
    -models.py    数据库表模型
    -views.py     视图函数

生命周期

1、路由层(根据不同的地址执行不同的视图函数,详见urls.py)

2、视图层(定义处理业务逻辑的视图函数,详见views.py)

3、模型层 (跟数据库打交道的,详解models.py)

4、模板层(待返回给浏览器的html文件,详见templates)

静态文件配置(无用)

对于前后端分离的项目,静态文件一般用nginx代理,不用特意在webServer框架再配置

STATIC_URL = '/static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static'),
]

前端对应配置:

# 加载静态目录
{% load static %}
<script src="{% static 'js/jQuery3.6.0.js' %}"></script>
<script src="{% static 'js/bootstrap.min.js' %}"></script>
<script src="{% static 'js/sweetalert.min.js' %}"></script>
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
<link rel="shortcut icon" href="{% static "img/favicon.ico" %}">

模板语法:
{{}}用于取值,{% %}用于逻辑

启动django

  1. manage.py是入口,执行了execute_from_command_line(sys.argv)

  2. 进入management_init_.py,执行了:

    cmd : python manage.py runserver 8000
    argv: runserver 8000
    
    def execute_from_command_line(argv=None):
        """Run a ManagementUtility."""
        utility = ManagementUtility(argv)
        utility.execute()
    
  3. execute()方法中校验参数正误,并且执行:self.fetch_command("runserver").run_from_argv(self.argv)

  4. fetch_command(“runserver”)找到了对应的runserver模块的命令:

  5. 执行CommandObj.run_from_argv(self.argv),再跳到self.execute(*args, **cmd_options),再获取到output = self.handle(*args, **options)这个handler是runserver.handle()

  6. 检查ip等信息后,执行self.run(**options),最终执行了好几个类的run方法后到了最后一个run:

def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer):
    server_address = (addr, port)
    if threading:
        httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {})
    else:
        httpd_cls = server_cls
        
    # 它是WSGI服务器与django之间相互通信的唯一枢纽通道,当WSGI服务对象收到socket请求后,会将这个请求传递给django
    httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
    if threading:
        # ThreadingMixIn.daemon_threads indicates how threads will behave on an
        # abrupt shutdown; like quitting the server by the user or restarting
        # by the auto-reloader. True means the server will not wait for thread
        # termination before it quits. This will make auto-reloader faster
        # and will prevent the need to kill the server manually if a thread
        # isn't terminating correctly.
        httpd.daemon_threads = True
    httpd.set_app(wsgi_handler)
    # 启动非堵塞网络监听服务
    httpd.serve_forever()

路由

# urls.py 
from django.conf.urls import url

urlpatterns = [
     url(regex, view, kwargs=None, name=None), 
     # 一个注册接口
     url(r'^register/', account.register, name='register'),
]
#函数url关键参数介绍
# regex:正则表达式,用来匹配url地址的路径部分,
# view:通常为一个视图函数,用来处理业务逻辑
# kwargs:有名分组
# name:反向解析
  1. django的路由匹配是自上而下的迭代,匹配到一个规则就不再向下,而gin框架则是利用前缀树,时间复杂度更小。

  2. 因此,django的首页配置要放到最后。

    	...
        # 充值页面
        url('^magic/', order.pay, name='pay'),
        url('^order/', order.order, name='order'),
        url('^result/', order.pay_result, name='result'),
    
        url(r'^', home.index, name='index'),
    ]
    
  3. 路由以/结尾,不输入/也能匹配到的原因:在配置文件settings.py中有一个参数APPEND_SLASH,该参数有两个值True或False,当APPEND_SLASH=True(如果配置文件中没有该配置,APPEND_SLASH的默认值为True),并且用户请求的url地址的路径部分不是以 / 结尾,Django会拿着路径部分(即index)去路由表中匹配正则表达式,发现匹配不成功,那么Django会在路径后加 /再去路由表中匹配,如果匹配失败则会返回路径未找到,如果匹配成功,则会返回重定向信息给浏览器。django的全局配置在(from django.conf import settings)

分组

适用于:http://127.0.0.1:8000/article/id/,id为某些记录的主键

我还是喜欢用http://127.0.0.1:8000/article?id=id这种restfulapi的形式QAQ

注意:分组是正则表达式的功能。

无名分组

# 路由
url(r'^aritcle/(\d+)/$',views.article),

# 视图函数需要配套接收,匹配成功会调用article(request,id)
def article(request,article_id):
    return HttpResponse('id为 %s 的文章内容...' %article_id)

有名分组

url(r'^aritcle/(?P<article_id>\d+)/$',views.article)

# 视图函数需要配套接收,匹配成功会调用article(request,article_id=id)
def article(request,article_id):
    return HttpResponse('id为 %s 的文章内容...' %article_id)

路由分发

  1. 每个功能模块应该有自己的urls.py文件。
  2. urls过多会导致路由匹配速度下降。
from django.conf.urls import url,include
from django.contrib import admin
# 总路由表
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    
    # 新增两条路由,注意不能以$结尾。
    # include函数就是做分发操作的。
    # 总路由里面写前缀即可。
    # app01.urls是因为app01已经在settings中注册了,否则无法获取app01/urls.py
    url(r'^app01/', include('app01.urls')),
    url(r'^app02/', include('app02.urls')),
]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)),

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'user',  # apps目录已经被加到环境变量了,直接能找到user
    'home',
    'course',
    'order',
]
urlpatterns = [
    path('xadmin/', xadmin.site.urls),
    re_path('media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}),
    path('home/', include('home.urls')),
    path('user/', include('user.urls')),
    path('course/', include('course.urls')),
    path('order/', include('order.urls'))
]

反向解析

url(r'^register/', account.register, name='register'),

编写一条url(regex, view, kwargs=None, name=None)时,可以通过参数name为url地址的路径部分起一个别名,项目中就可以通过别名来获取这个路径

from django.shortcuts import render 
from django.shortcuts import reverse # 用于反向解析
from django.shortcuts import redirect #用于重定向页面
from django.shortcuts import HttpResponse

def login(request):
    if request.method == 'GET':
        # 当为get请求时,返回login.html页面,页面中的{% url 'login_page' %}会被反向解析成路径:/login/
        return render(request, 'login.html')
        
    url = reverse('index_page')  # reverse会将别名'index_page'反向解析成路径:/index/       
    return redirect(url) # 重定向到/index/

# 前端
<a href="{% url 'index' %}"><img src="{% static 'img/head.png' %}" alt="" style="width: 100px"></a>

反向解析结合分组

from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    
    url(r'^aritcle/(\d+)/$',views.article,name='article_page'), # 无名分组
    url(r'^user/(?P<uid>\d+)/$',views.article,name='user_page'), # 有名分组
]
# 1 针对无名分组
在views.py中,反向解析的使用:
url = reverse('article_page',args=(1,)) 
在模版login.html文件中,反向解析的使用
{% url 'article_page' 1 %}

    
# 2 针对有名分组
在views.py中,反向解析的使用:
url = reverse('user_page',kwargs={'uid':1}) 
在模版login.html文件中,反向解析的使用
{% url 'user_page' uid=1 %}

名称空间

如果别名存在重复,那么在反向解析时则会出现覆盖。(推荐给路由起名字时按:name=“模块_功能_view”,一般不会重复)

# 总路由表
urlpatterns = [
    url(r'^admin/', admin.site.urls),
	
    # 传给include功能一个元组,元组的第一个值是路由分发的地址,第二个值则是名称空间起的名字
    url(r'^app01/', include(('app01.urls','app01'))),
    url(r'^app02/', include(('app02.urls','app02'))),
]
# 视图
from django.shortcuts import render
from django.shortcuts import HttpResponse
from django.shortcuts import reverse

def index(request):
    url=reverse('app01:index_page') # 解析的是名称空间app01下的别名'index_page'
    return HttpResponse('app01的index页面,反向解析结果为%s' %url)

1、在视图函数中基于名称空间的反向解析,用法如下
url=reverse('名称空间的名字:待解析的别名')

2、在模版里基于名称空间的反向解析,用法如下
<a href="{% url '名称空间的名字:待解析的别名'%}">哈哈</a>

re_path与path

  1. Django2.0中的re_path与django1.0的url一样。
  2. 在Django2.0中新增了一个path功能,用来解决:数据类型转换问题与正则表达式冗余问题:
urlpatterns = [
    # 问题一:数据类型转换
    # 正则表达式会将请求路径中的年份匹配成功然后以str类型传递函数year_archive,在函数year_archive中如果想以int类型的格式处理年份,则必须进行数据类型转换
    re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),

    # 问题二:正则表达式冗余
    # 下述三个路由中匹配article_id采用了同样的正则表达式,重复编写了三遍,存在冗余问题,并且极不容易管理,因为一旦article_id规则需要改变,则必须同时修改三处代码
    re_path(r'^article/(?P<article_id>[a-zA-Z0-9]+)/detail/$', views.detail_view),
    re_path(r'^articles/(?P<article_id>[a-zA-Z0-9]+)/edit/$', views.edit_view),
    re_path(r'^articles/(?P<article_id>[a-zA-Z0-9]+)/delete/$', views.delete_view),
]


---------------------------------------------------------

urlpatterns = [
    # 问题一的解决方案:
    path('articles/<int:year>/', views.year_archive), # <int:year>相当于一个有名分组,其中int是django提供的转换器,相当于正则表达式,专门用于匹配数字类型,而year则是我们为有名分组命的名,并且int会将匹配成功的结果转换成整型后按照格式(year=整型值)传给函数year_archive


    # 问题二解决方法:用一个int转换器可以替代多处正则表达式
    path('articles/<int:article_id>/detail/', views.detail_view), 
    path('articles/<int:article_id>/edit/', views.edit_view),
    path('articles/<int:article_id>/delete/', views.delete_view),
]

#1、path与re_path或者1.0中的url的不同之处是,传给path的第一个参数不再是正则表达式,而是一个完全匹配的路径,相同之处是第一个参数中的匹配字符均无需加前导斜杠

#2、使用尖括号(<>)从url中捕获值,相当于有名分组

#3、<>中可以包含一个转化器类型(converter type),比如使用 <int:name> 使用了转换器int。若果没有转化器,将匹配任何字符串,当然也包括了 / 字符

默认支持五种转换器
1. str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
2. int,匹配正整数,包含03. slug,匹配字母、数字以及横杠、下划线组成的字符串。
4. uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
5. path,匹配任何非空字符串,包含了路径分隔符(/

自定义转换器

模板如下:

class MonthConverter:
	# 正则
	# 属性名必须为regex
    regex='\d{2}'
	
	# to_python用于将参数类型转换后传递到视图函数
    def to_python(self, value):
        return int(value)
	
	# to_url用于url反向引用
    def to_url(self, value):
    	# # 匹配的regex是两个数字,返回的结果也必须是两个数字
        return value 

视图

视图函数,简称视图,属于Django的视图层,默认定义在views.py文件中,是用来处理web请求信息以及返回响应信息的函数,所以研究视图函数只需熟练掌握两个对象即可:请求对象(HttpRequest)和响应对象(HttpResponse)

HttpRequest

常用方法

个人喜欢Form(data=request.POST)直接导入form,方便校验

.HttpRequest.method
获取请求使用的方法(值为纯大写的字符串格式)。例如:"GET""POST".HttpRequest.GET
值为一个类似于字典的QueryDict对象,封装了GET请求的所有参数,可通过HttpRequest.GET.get('键')获取相对应的值
  
三.HttpRequest.POST
值为一个类似于字典的QueryDict对象,封装了POST请求所包含的表单数据,可通过HttpRequest.POST.get('键')获取相对应的值
   
针对表单中checkbox类型的input标签、select标签提交的数据,键对应的值为多个,需要用:HttpRequest.POST.getlist("hobbies")获取存有多个值的列表,同理也有HttpRequest.GET.getlist("键").HttpRequest.body
ajax可以提交的数据格式有:1、编码格式1 2、编码格式2 3、json,当ajax采用POST方法提交前两种格式的数据时,django的处理方案同上,但是当ajax采用POST方法提交json格式的数据时,django会将接收到的数据存放于HttpRequest.body,此时需要我们自己对HttpRequest.body属性值做反序列化操作。

五.HttpRequest.FILES
HttpRequest.FILES 只有在请求的方法为POST 且提交的<form> 带有enctype="multipart/form-data" 的情况下才会包含数据。否则,FILES 将为一个空的类似于字典的对象。该属性值为一个类似于字典的对象,可以包含多组key:value(对应多个上传的文件)class MultiValueDict(dict). [filename1:[obj1,obj2]]
上传文件:
with open(filePath,"wb") as writer:
	for line in request.FILES.get("filename"):
		writer.write(line).HttpRequest.path
获取url地址的路径部分,只包含路径部分

七.HttpRequest.get_full_path()
获取url地址的完整path,既包含路径又包含参数部分

http://127.0.0.1:8001/order/?name=egon&age=10
HttpRequest.path的值为"/order/"
HttpRequest.get_full_path()的值为"/order/?name=egon&age=10".HttpRequest.META
值为包含了HTTP协议的请求头数据的Python字典,字典中的key及期对应值的解释如下
CONTENT_LENGTH —— 请求的正文的长度(是一个字符串)。
CONTENT_TYPE —— 请求的正文的MIME类型。
HTTP_ACCEPT —— 响应可接收的Content-Type。
HTTP_ACCEPT_ENCODING —— 响应可接收的编码。
HTTP_ACCEPT_LANGUAGE —— 响应可接收的语言。
HTTP_HOST —— 客服端发送数据的目标主机与端口
HTTP_REFERER —— Referring 页面。
HTTP_USER_AGENT —— 客户端使用的软件版本信息
QUERY_STRING —— 单个字符串形式的查询字符串(未解析过的形式)。
REMOTE_ADDR —— 客户端的IP地址。
REMOTE_HOST —— 客户端的主机名。
REMOTE_USER —— 服务器认证后的用户。
REQUEST_METHOD —— 一个字符串,例如"GET""POST"。
SERVER_NAME —— 服务器的主机名。
SERVER_PORT —— 服务器的端口(是一个字符串)。
从上面可以看到,除 CONTENT_LENGTH 和 CONTENT_TYPE 之外,HTTP协议的请求头数据转换为 META 的键时,
都会
1、将所有字母大写
2、将单词的连接符替换为下划线
3、加上前缀HTTP_。
所以,一个叫做 X-Bender 的头部将转换成 META 中的 HTTP_X_BENDER 键。
   
九.HttpRequest.COOKIES
一个标准的Python字典,包含所有的cookie。键和值都为字符串。

十.HttpRequest.session
一个既可读又可写的类似于字典的对象,表示当前的会话。只有当Django 启用会话的支持时才可用。

十一.HttpRequest.user(用户认证组件下使用)
一个 AUTH_USER_MODEL 类型的对象,表示当前登录的用户,也可以自定义为某User对象。

十二.HttpRequest.is_ajax()
如果请求是通过XMLHttpRequest 发起的,则返回True,方法是检查 HTTP_X_REQUESTED_WITH 相应的首部是否是字符串'XMLHttpRequest'

HttpResponse

响应可以是任何形式的内容,比如一个HTML文件的内容,一个重定向,一个404错误,一个XML文档,或者一张图片等。


快捷方式:

# 前后端不分离
from django.shortcuts import HttpResponse,render,redirect
# json
from django.http import JsonResponse

# 实际上返回文件也不应该用最基本的HttpResonse()
# def __init__(self, content=b'', *args, **kwargs):
# 参数传入centent就行
return HttpResponse(png)

return render(request, 'register.html', locals(), status=200)
def render(request, template_name, context=None, content_type=None, status=None, using=None):
	"""
	1. request:request对象
	2. template_name:模板名字(利用配置文件里的templates去反射文件)
	3. context: 本次请求上下文数据,可以传入locals()自动将数据导入
	4. content_type: http协议的Content-Type
	5. status: http协议的状态码
	6. using: ...
	"""
    content = loader.render_to_string(template_name, context, request, using=using)
    return HttpResponse(content, content_type, status)

return redirect('/some/url/')
def redirect(to, *args, permanent=False, **kwargs):
    """
    1. to: 目标url
    2. permanent: 是否永久,决定状态码是301还是302
	301表示旧地址A的资源已经被永久地移除了,即这个资源不可访问了。搜索引擎在抓取新内容的同时也将旧的网址转换为重定向之后的地址;
  302表示旧地址A的资源还在,即这个资源仍然可以访问,这个重定向只是临时地从旧地址A跳转到地址B,搜索引擎会抓取新的内容、并且会保存旧的网址。 从SEO层面考虑,302要好于301.
    """
    redirect_class = HttpResponsePermanentRedirect if permanent else HttpResponseRedirect
    return redirect_class(resolve_url(to, *args, **kwargs))

Json

from django.http import JsonResponse

def my_view(request):
    data=['fuck','off']
    return JsonResponse(data,safe=False)
    # 默认safe=True代表只能序列化字典对象,safe=False代表可以序列化字典以外的对象
    def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,
                 json_dumps_params=None, **kwargs):
        if safe and not isinstance(data, dict):
            raise TypeError(
                'In order to allow non-dict objects to be serialized set the '
                'safe parameter to False.'
            )
        if json_dumps_params is None:
            json_dumps_params = {}
        kwargs.setdefault('content_type', 'application/json')
        data = json.dumps(data, cls=encoder, **json_dumps_params)
        super().__init__(content=data, **kwargs)

json_dumps_params可以传入一些指定参数,如:防止将中文字符串转为ascii,ensure_ascii:False
传入的json_dumps_params会被django内置的json序列化方法捕获到使用。

FBV和CBV

django的视图层由两种形式构成:FBV和CBV

1、FBV基于函数的视图(Function base view),我们之前一直介绍的都是FBV

2、CBV基于类的视图(Class base view)

其实CBV有FBV并无太大差异,视图类在经过as_view()和dispatch()后就变成了视图函数。

from django.urls import path,re_path
from app01 import views

urlpatterns = [
	# 必须调用类下的方法as_view
    re_path(r'^login/',views.LoginView.as_view()),
]

from django.shortcuts import render,HttpResponse,redirect
from django.views import View

class LoginView(View):

	# 菜鸟如我一般不用重写
    def dispatch(self, request, *args, **kwargs): 
    	# 可在该方法内做一些预处理操作
    	# 必须继承父类的dispatch功能
        # 当请求url为:http://127.0.0.1:8008/login/会先触发dispatch的执行
        # 如果http协议的请求方法为GET,则调用下述get方法
        # 如果http协议的请求方法为POST,则调用下述post方法
        return super().dispatch(request, *args, **kwargs)
	
	# 会被反射request.method取到
    def get(self,request):
        return render(request,'login.html')
	
	# # 会被反射request.method取到
    def post(self,request):
        return HttpResponse(res)

原生的as_view()和dispatch()方法比较简单:

def dispatch(self, request, *args, **kwargs):
    if request.method.lower() in ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']:	
    	# 反射获取视图函数
        handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
    else:
    	# 默认method_not_allowed 403 视图函数
        handler = self.http_method_not_allowed
    return handler(request, *args, **kwargs)

@classonlymethod
def as_view(cls, **initkwargs):

	# 略过
    for key in initkwargs:
        if key in cls.http_method_names:
            raise TypeError("You tried to pass in the %s method name as a "
                            "keyword argument to %s(). Don't do that."
                            % (key, cls.__name__))
        if not hasattr(cls, key):
            raise TypeError("%s() received an invalid keyword %r. as_view "
                            "only accepts arguments that are already "
                            "attributes of the class." % (cls.__name__, key))
	
	# 核心
    def view(request, *args, **kwargs):
    	# self = 视图类()
        self = cls(**initkwargs)
        if hasattr(self, 'get') and not hasattr(self, 'head'):
            self.head = self.get
            
        # 赋值request和参数,可以通过self.request获取request对象了
        self.setup(request, *args, **kwargs)
        # 刚赋值,怎么可能取不到呢?除非你手贱重写了setup()
        if not hasattr(self, 'request'):
       		# 询问你是否手贱重写了setup()
            raise AttributeError(
                "%s instance has no 'request' attribute. Did you override "
                "setup() and forget to call super()?" % cls.__name__
            )
        # 调用dispatch()    
        return self.dispatch(request, *args, **kwargs)
    
    # 给view赋值,伪装
    view.view_class = cls
    view.view_initkwargs = initkwargs

    # take name and docstring from class
    update_wrapper(view, cls, updated=())

    # and possible attributes set by decorators
    # like csrf_exempt from dispatch
    update_wrapper(view, cls.dispatch, assigned=())
	
	# 返回装饰器后的view
    return view

模板(前后端分离不用看)

django的模板=HTML代码+模板语法

一、变量:{{ 变量名 }}
	1.1 深度查询:句点符的应用
    1.2 过滤器
二、标签:{% 标签名 %}
三、自定义标签和过滤器
四、模板的导入和继承

变量

return render(request,'test.html',{'msg':msg,'dic':dic,'obj':obj,'li':li})#locals()会将函数内定义的名字与值转换为字典中的k与v
return render(request,'test.html',locals()) 
<p>{{ msg }}</p>
<p>{{ dic }}</p>
<p>{{ obj }}</p>
<p>{{ li }}</p>

<!--调用字符串对象的upper方法,注意不要加括号-->
<p>{{ msg.upper }}</p>
<!--取字典中k1对应的值-->
<p>{{ dic.k1 }}</p>
<!--取对象的name属性-->
<p>{{ obj.name }}</p>
<!--取列表的第2个元素,然后变成大写-->
<p>{{ li.1.upper }}</p>
<!--取列表的第3个元素,并取该元素的age属性-->
<p>{{ li.2.age }}</p>

过滤器

可以理解为Linux的管道符,将前面的结果传给后面运算

{{ 变量名|过滤器名:传给过滤器的参数 }}

#1、default
#作用:如果一个变量值是False或者为空,使用default后指定的默认值,否则,使用变量本身的值
{{ value|default:"nothing" }}

#2、length
#作用:返回值的长度。它对字符串、列表、字典等容器类型都起作用
{{ value|length }}

#3、filesizeformat
#作用:将值的格式化为一个"人类可读的"文件尺寸(如13KB、4.1 MB、102bytes等等)
{{ value|filesizeformat }}

#4、date
#作用:将日期按照指定的格式输出,如果value=datetime.datetime.now(),按照格式Y-m-d则输出2019-02-02
{{ value|date:"Y-m-d" }}  

#5、slice
#作用:对输出的字符串进行切片操作,顾头不顾尾
{{ value|slice:"0:2" }} 

#6、truncatechars
#作用:如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾,注意8个字符也包含末尾的3个点
{{ value|truncatechars:8 }}

#7、truncatewords
#作用:同truncatechars,但truncatewords是按照单词截断,注意末尾的3个点不算作单词,
{{ value|truncatewords:2 }}

#8、safe
#作用:出于安全考虑,Django的模板会对HTML标签、JS等语法标签进行自动转义,例如value="<script>alert(123)</script>",模板变量{{ value }}会被渲染成&lt;script&gt;alert(123)&lt;/script&gt;交给浏览器后会被解析成普通字符”<script>alert(123)</script>“,失去了js代码的语法意义,但如果我们就想让模板变量{{ value }}被渲染的结果有语法意义,那么就用到了过滤器safe,比如value='<a href="https://www.baidu.com">点我啊</a>',在被safe过滤器处理后就成为了真正的超链接,不加safe过滤器则会当做普通字符显示’<a href="https://www.baidu.com">点我啊</a>‘
{{ value|safe }}
过滤器描述示例
upper以大写方式输出{{ user.name | upper }}
add给value加上一个数值{{ user.age | add:”5” }}
addslashes单引号加上转义号{{ val | addslashes }}
capfirst第一个字母大写{{ ‘good’| capfirst }} 返回”Good”
center输出指定长度的字符串,把变量居中{{ “abcd”| center:”50” }}
cut删除指定字符串{{ “You are not a Englishman” | cut:”not” }}
default_if_none如果值为None, 则使用默认值代替{{ val | default_if_none:"default" }}
dictsort按某字段排序,变量必须是一个dictionary{% for moment in moments | dictsort:”id” %}
dictsortreversed按某字段倒序排序,变量必须是dictionary{% for moment in moments | dictsortreversed:”id” %}
divisibleby判断是否可以被数字整除{{ 224 | divisibleby:10}}
escape按HTML转义,比如将”<”转换为”&lt”{{ html | escape }}
first返回列表的第1个元素,变量必须是一个列表{{ list | first }}
floatformat转换为指定精度的小数,默认保留1位小数{{ 3.1415926 | floatformat:3 }} 返回 3.142 四舍五入
get_digit从个位数开始截取指定位置的数字{{ 123456 | get_digit:’1’}}
join用指定分隔符连接列表{{ [‘abc’,’45’] | join:’’ }} 返回 abc45
length_is检查列表,字符串长度是否符合指定的值{{ ‘hello’| length_is:’3’ }}
linebreaks用p标签或br标签包裹变量{{ “Hi\n\nDavid”|linebreaks }} 返回

Hi

David

linebreaksbr用br标签代替换行符{{ hi\r\n\r\n | linebreaksbr }}
linenumbers为变量中的每一行加上行号{{ val | linenumbers }}
ljust输出指定长度的字符串,变量左对齐{{‘ab’|ljust:5}}返回 ‘ab ’
lower字符串变小写{{ "AB" | lower }}
make_list将字符串转换为列表{{ "150" | make_list }}
random返回列表的随机一项{{ list | random }}
removetags删除字符串中指定的HTML标记{{value | removetags: “h1 h2”}}
rjust输出指定长度的字符串,变量右对齐{{‘ab’|rjust:5}}返回 ‘ab ’
slugify在字符串中留下减号和下划线,其它符号删除,空格用减号替换{{ '5-2=3and5 2=3' }}
time返回日期的时间部分{{ time_str | time }}
truncatewords_html保留其中的HTML标签{{ 'p This is a pen p' | truncatewords_html: 5 }}
urlencode将字符串中的特殊字符转换为url兼容表达方式{{ ‘http://www.aaa.com/foo?a=b&b=c’ | urlencode}}
urlize将变量字符串中的url由纯文本变为链接{{ url | urlize }}
yesno将布尔变量转换为字符串yes, no 或maybe{{ True | yesno }}
## 标签 标签是为了在模板中完成一些特殊功能,语法为{% 标签名 %},一些标签还需要搭配结束标签 {% endtag %}

循环

#1、遍历每一个元素:
{% for person in person_list %}
    <p>{{ person.name }}</p>
{% endfor %}

#2、可以利用{% for obj in list reversed %}反向循环。

#3、遍历一个字典:
{% for key,val in dic.items %}
    <p>{{ key }}:{{ val }}</p>
{% endfor %}

#4、循环序号可以通过{{ forloop }}显示 
{% for name in names %}
    <p>{{ forloop.counter0 }} {{ name }}</p>
{% endfor %}
forloop.counter            当前循环的索引值(从1开始)
forloop.counter0           当前循环的索引值(从0开始)
forloop.revcounter         当前循环的倒序索引值(从1开始)
forloop.revcounter0        当前循环的倒序索引值(从0开始)
forloop.first              当前循环是第一次循环则返回True,否则返回False
forloop.last               当前循环是最后一次循环则返回True,否则返回False
forloop.parentloop         本层循环的外层循环

#5、for标签可以带有一个可选的{% empty %} 从句,在变量person_list为空或者没有被找到时,则执行empty子句
{% for person in person_list %}
    <p>{{ person.name }}</p>
{% empty %}
    <p>sorry,no person here</p>
{% endfor %}

分支

# 1、注意:
{% if 条件 %}条件为真时if的子句才会生效,条件也可以是一个变量,if会对变量进行求值,在变量值为空、或者视图没有为其传值的情况下均为False

# 2、具体语法
{% if num > 100 or num < 0 %}
    <p>无效</p>
{% elif num > 80 and num < 100 %}
    <p>优秀</p>
{% else %}
    <p>凑活吧</p>
{% endif %}

#3、if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断。

csrf

前后端不分离需要在表单加入{% csrf_token %}

<form>
{% csrf_token %}
</form>

# 1、在GET请求到form表单时,标签{% csrf_token%}会被渲染成一个隐藏的input标签,该标签包含了由服务端生成的一串随机字符串,如<input type="hidden" name="csrfmiddlewaretoken" value="dmje28mFo...OvnZ5">
# 2、在使用form表单提交POST请求时,会提交上述随机字符串,服务端在接收到该POST请求时会对比该随机字符串,对比成功则处理该POST请求,否则拒绝,以此来确定客户端的身份

with

# with标签用来为一个复杂的变量名起别名,如果变量的值来自于数据库,在起别名后只需要使用别名即可,无需每次都向数据库发送请求来重新获取变量的值
{% with li.1.upper as v %}
    {{ v }}
{% endwith %}

自定义过滤器和标签

  1. 将app注册到settings.py
  2. 在文件夹app中创建子文件夹templatetags(文件夹名只能是templatetags)
  3. 创建Py 文件,自定义过滤器和标签
from django import template
# 注意变量名必须为register,不可改变
register = template.Library() 

#1、自定义过滤器
@register.filter
# 自定义的过滤器只能定义最多两个参数,针对{{ value1 | filter_multi:value2 }}
# 参数传递为v1=value1,v2=value2
def my_multi_filter(v1 ,v2): 
    return  v1 * v2

#2、自定义标签
@register.simple_tag
# # 自定义的标签可以定义多个参数
def my_multi_tag(v1, v2): 
    return v1 * v2

#3、自定义标签扩展之mark_safe
# 注释:用内置的标签safe来让标签内容有语法意义,如果想让自定义标签处理的结果也有语法意义,则不能使用内置标签safe了,需要使用mark_safe,可以实现与内置标签safe同样的功能
from django.utils.safestring import mark_safe
@register.simple_tag
def my_input_tag(id, name):
    res = "<input type='text' id='%s' name='%s' />" % (id, name)
    return mark_safe(res)
  1. 使用
<!--必须先加载存有自定义过滤器和标签的文件-->
{% load inclusion_tags %}

# 过滤器
<!--salary的值为10,经过滤器my_multi_filter的处理结果为120-->
{{ salary|my_multi_filter:12 }}

# 标签
<!--结果为2-->
{% my_multi_tag 1 2 %}

# 标签
结果为一个input标签,该表的属性id="inp1" name="username"
注意:input的属性值均为字符串类型,所以my_input_tag后的两个值均为字符串类型
{% my_input_tag "inp1" "username" %} 



# 对比
#1、自定义过滤器只能传两个参数,而自定义标签却可以传多个参数
#2、过滤器可以用于if判断,而标签不能
{% if salary|my_multi_filter:12 > 200 %}
    <p>优秀</p>
{% else %}
    <p>垃圾</p>
{% endif %}

模板的导入和继承

模板文件彼此之间可能会有大量冗余代码,为此django提供了专门的语法来解决这个问题,主要围绕三种标签的使用:include标签、extends标签、block标签。

#作用:在一个模板文件中,引入/重用另外一个模板文件的内容,
{% include '模版名称' %}

<div class="row">
    <div class="col-md-3">
        <!--在base.html引入advertise.html文件的内容-->
        {% include "advertise.html" %}
    </div>
    <div class="col-md-9"></div>
</div>

模板的继承\派生之extends标签、block标签

#作用:在一个模板文件中,引入/重用另外一个模板文件的内容
# include有的功能extends全都有
# extends可以搭配一个block标签,用于在继承的基础上定制新的内容
{% extends "模版名称" %}

# 定义base.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>{% block tilte %}{% endblock %}</title>
    {% load static %}
    <script src="{% static 'js/jQuery3.6.0.js' %}"></script>
    <script src="{% static 'js/bootstrap.min.js' %}"></script>
    <script src="{% static 'js/sweetalert.min.js' %}"></script>
    <link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
    <link rel="shortcut icon" href="{% static "img/favicon.ico" %}" />
    <style>
        .navbar-default{
            border-radius: 0;
        }
        .account{
            width: 400px;
            margin-top: 30px;
            margin-left: auto;
            margin-right: auto;
            border: 1px solid #f0f0f0;
            padding: 10px 30px 30px 30px;
            -webkit-box-shadow: 5px 10px 10px rgba(0,0,0,.05);
            box-shadow: 5px 10px 10px rgba(0,0,0,.05);
        }
        .account .title{
            font-size: 25px;
            font-weight: bold;
            text-align: center;
        }
        .account .form-group{
            margin-bottom: 20px;
        }
    </style>
    {% block css %}{% endblock %}
</head>
<body>
    <nav class="navbar navbar-default">
      <div class="container">
        <!-- Brand and toggle get grouped for better mobile display -->
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class
                    

有关django框架全解的更多相关文章

  1. TimeSformer:抛弃CNN的Transformer视频理解框架 - 2

    Transformers开始在视频识别领域的“猪突猛进”,各种改进和魔改层出不穷。由此作者将开启VideoTransformer系列的讲解,本篇主要介绍了FBAI团队的TimeSformer,这也是第一篇使用纯Transformer结构在视频识别上的文章。如果觉得有用,就请点赞、收藏、关注!paper:https://arxiv.org/abs/2102.05095code(offical):https://github.com/facebookresearch/TimeSformeraccept:ICML2021author:FacebookAI一、前言Transformers(VIT)在图

  2. ruby - sinatra 框架的 MVC 模式 - 2

    我想开始使用“Sinatra”框架进行编码,但我找不到该框架的“MVC”模式。是“MVC-Sinatra”模式或框架吗? 最佳答案 您可能想查看Padrino这是一个围绕Sinatra构建的框架,可为您的项目提供更“类似Rails”的感觉,但没有那么多隐藏的魔法。这是使用Sinatra可以做什么的一个很好的例子。虽然如果您需要开始使用这很好,但我个人建议您将它用作学习工具,以对您来说最有意义的方式使用Sinatra构建您自己的应用程序。写一些测试/期望,写一些代码,通过测试-重复:)至于ORM,你还应该结帐Sequel其中(imho

  3. ruby-on-rails - 正确了解 Rails 框架的最佳方式是什么? - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。我一直在Rails上做两个项目,它们运行良好,但在这个过程中重新发明了轮子,自来水(和热水)和止痛药,正如我随后了解到的那样,这些已经存在于框架中。那么基本上,正确了解框架中所有智能部分的最佳方法是什么,这将节省时间而不是自己构建已经实现的功能?从第1页开始阅读文档?是否有公开所有内容的特定示例应用程序?一个特定的开源项目?所有的rails交通?还是完全

  4. ruby - 自动将院子文档框架添加到现有的 Rails 遗留代码中 - 2

    关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。关闭4年前。Improvethisquestion我希望能够将模板化的YARD文档样式注释插入到我现有的Rails遗留应用程序中。目前它的评论很少。我想要具有指定参数的类header和方法header(通过从我假定的方法签名中提取)和返回值的占位符。在PHP代码中,我有一些工具可以检查代码并在适当的位置创建插入到代码中的文档header注释。在带有Ducktyping等的Ruby中,我确信诸如@params等类型之类

  5. ruby-on-rails - 具有六边形架构和 DCI 模式的框架和数据库适配器 - 2

    我尝试用Ruby设计一个基于Web的应用程序。我开发了一个简单的核心应用程序,在没有框架和数据库的情况下在六边形架构中实现DCI范例。核心六边形中有小六边形和网络,数据库,日志等适配器。每个六边形都在没有数据库和框架的情况下自行运行。在这种方法中,我如何提供与数据库模型和实体类的关系作为独立于数据库的关系。我想在将来将框架从Rails更改为Sinatra或数据库。事实上,我如何在这个核心Hexagon中实现完全隔离的rails和mongodb的数据库适配器或框架适配器。有什么想法吗? 最佳答案 ROM呢?(Ruby对象映射器)。还有

  6. ruby-on-rails - 在 Ruby on Rails 中验证 Django 密码给出不匹配的密码 - 2

    我正在用RubyonRails重写Django应用程序,并希望为用户保留旧密码。Django使用PBKDF2SHA1作为加密机制。所以我有一个加密密码是这个pbkdf2_sha256$10000$YsnGfP4rZ1IZ$Tpf4922MoNEjuJQA9EG2Elptyt3dMAyzBPUgmunFOW4=原密码是2bulls在Ruby中,我使用PBKDF256gem和base64进行检查。Base64.encode64PBKDF256.dk("2bulls","YsnGfP4rZ1IZ",10000,32)我很期待Tpf4922MoNEjuJQA9EG2Elptyt3dMAyzBP

  7. python - Ruby 是否有相当于 Python 的扭曲框架作为网络抽象层? - 2

    据我了解,Python的扭曲框架为网络通信提供了更高级别的抽象(?)。我正在寻找在Rails应用程序中使用与twisted等效的Ruby。 最佳答案 看看EventMachine.它不像Twisted那样广泛,但它是围绕事件驱动网络编程的相同概念构建的。 关于python-Ruby是否有相当于Python的扭曲框架作为网络抽象层?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/9

  8. ruby-on-rails - 使用 Rails 以外的 Ruby 框架是否有任何潜在的缺点? - 2

    我想使用比Rails(Sinatra/Ramaze/Camping)更轻的框架,但我担心这样做我将无法使用许多以插件形式为Rails定制的共享库.这是一个主要问题,还是这些插件中的大多数都可以跨不同的Ruby框架使用?使用Ruby框架而不是Rails是否还有其他潜在的缺点? 最佳答案 您仍然可以使用gems在你提到的所有框架中,很多东西都是可重用的。想要交换一个新的ORM,没问题。想要一个花哨的shmacy语法高亮,没问题。Rails一直在大力插入摆脱旧的插件模型,转而使用gems。如果其他框架之一符合您的需求,最好使用它。请记住,

  9. 基于python的短视频智能推荐/django的影视网站/视频推荐系统 - 2

    摘要本论文主要论述了如何使用Python技术开发一个短视频智能推荐,本系统将严格按照软件开发流程进行各个阶段的工作,采用B/S架构,面向对象编程思想进行项目开发。在引言中,作者将论述短视频智能推荐的当前背景以及系统开发的目的,后续章节将严格按照软件开发流程,对系统进行各个阶段分析设计。 短视频智能推荐的主要使用者分为管理员和用户,实现功能包括管理员:首页、个人中心、用户管理、热门视频管理、用户上传管理、系统管理,用户:首页、个人中心、用户上传管理、我的收藏管理,前台首页;首页、热门视频、用户上传、公告信息、个人中心、后台管理等功能。由于本网站的功能模块设计比较全面,所以使得整个短视频智能推荐信

  10. ruby - 应该 validate_format_of 。 not_with 在框架中有问题(或者在我的理解中) - 2

    我将以下代码放入RSpec测试中:it{shouldvalidate_format_of(:email).not_with('test@test')}并设置实际的类:validates:email,:presence=>true,:format=>/\b[A-Z0-9._%-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4}\b/i当我运行测试时,我得到:失败:1)用户失败/错误:它{应该validate_format_of(:email).not_with('test@test')}当电子邮件设置为“test@test”时,预期错误包括“can'tbeblank”,得到错误

随机推荐