django基础之路由、视图、模板、表单验证

路由

Django 默认项目有根 urls.py,各 app 下分别有自己的 urls.py,既集中又分治,是一种解耦的模式。

from django.urls import include, path

urlpatterns = [
    path('article/', include('article.urls')),
    path('contact/', include('contact.urls')),
]

URL 配置

from django.urls import path
from . import views

urlpatterns = [
    path('articles/2003/', views.special_case_2003),
    path('articles/<int:year>/', views.year_archive),
    path('articles/<int:year>/<int:month>/', views.month_archive),
    path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),
]

urlpatterns = [
    path('<page_slug>-<page_id>/', include([
        path('history/', views.history),
        path('edit/', views.edit),
        path('discuss/', views.discuss),
        path('permissions/', views.permissions),
    ])),
]

URL 配置不检查使用何种 HTTP 请求方法,所有请求方法 POST、GET、HEAD 等都将路由到同一个 URL 的同一个视图。在视图中,才根据具体请求方法的不同,进行不同的处理。

注意:

  • 要从 URL 中取值,使用尖括号。
  • 捕获的值可以选择性地包含转换器类型。

常用路径转换器

  • str

    匹配除了 '/' 之外的非空字符串。如果表达式内不包含转换器,则会默认匹配字符串。

  • int

    匹配 0 或任何正整数。返回一个 int 。

  • slug

    匹配任意由 ASCII 字母或数字以及连字符和下划线组成的短标签。比如,building-your-1st-django-site 。

  • uuid

    匹配一个格式化的 UUID 。为了防止多个 URL 映射到同一个页面,必须包含破折号并且字符都为小写。比如,075194d3-6885-417e-a8a8-6c931e272f00。返回一个 UUID 实例。

  • path

    匹配非空字段,包括路径分隔符 '/' 。它允许你匹配完整的 URL 路径而不是像 str 那样匹配 URL 的一部分。

使用正则表达式

如果路径和转化器语法不能很好的定义你的 URL 模式,你可以可以使用正则表达式。如果要这样做,请使用 re_path() 而不是 path() 。

在 Python 正则表达式中,命名正则表达式组的语法是 (?Ppattern) ,其中 name 是组名,pattern 是要匹配的模式。

from django.urls import path, re_path

from . import views

urlpatterns = [
    path("articles/2003/", views.special_case_2003),
    re_path(r"^articles/(?P<year>[0-9]{4})/$", views.year_archive),
    re_path(r"^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$", views.month_archive),
    re_path(
        r"^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[\w-]+)/$",
        views.article_detail,
    ),
]

无论正则表达式进行哪种匹配,每个捕获的参数都作为字符串发送到视图。
当从使用 path() 切换到 re_path() (反之亦然),要特别注意,视图参数类型可能发生变化

向视图传递额外的参数

urlpatterns = [
    path('blog/<int:year>/', views.year_archive, {'foo': 'bar'}),
]

urlpatterns = [
    path('blog/', include('inner'), {'blog_id': 3}),
]

路由反向解析

命名 URL

urlpatterns = [
path('articles/<int:year>/', views.year_archive, name='news-year-archive'),
]

模板中使用

<a href="{% url 'news-year-archive' 2020 %}">2020 Archive</a>
<a href="{% url 'news-year-archive' year %}">{{ year }} Archive</a>

视图中使用

return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))

实例命名空间 namespace

urlpatterns = [
    path('author/', include('app.urls', namespace='author')),
    path('publisher/', include('app.urls', namespace='publisher')),
]

视图

from django.shortcuts import render,HttpResponse

def index(request):
    if request.resolver_match.namespace == 'author':
        return HttpResponse(reverse('author:index'))
    elif request.resolver_match.namespace == 'publisher':
        return HttpResponse(reverse('publisher:index'))
    else:
        return HttpResponse('其它')

def detail(request):
    if request.resolver_match.namespace == 'author':
        return HttpResponse('这里是作者的页面')
    elif request.resolver_match.namespace == 'publisher':
        return HttpResponse('这里是出版商的页面')
    else:
        return HttpResponse('其它')

模板中使用

{% url 'author:index' %}
{% url 'publisher:index' %}

内置快捷方法

  • render()

    将给定的模板与给定的上下文字典组合在一起,并以渲染的文本返回一个 HttpResponse 对象。

    return render(request, 'myapp/index.html', {'foo': 'bar'}, content_type='application/xhtml+xml')
    
  • redirect()

    返回一个 HttpResponseRedirect,指向传递参数的适当 URL。
    默认情况下发出临时重定向;通过传递 permanent=True 发出永久重定向。

    return redirect('news-year-archive', year=2023)
    
  • get_object_or_404()

    常用于查询某个对象,找到了则进行下一步处理,如果未找到则给用户返回 404 页面

    obj = get_object_or_404(Entry, pk=1)
    obj = get_object_or_404(Book.objects.filter(title__startswith='M'), pk=1)
    obj = get_object_or_404(Book, title__startswith='M', pk=1)
    
  • get_list_or_404()

    get_object_or_404 的多值获取版本

    my_objects = get_list_or_404(MyModel, published=True)
    

异步视图

异步(“async”)函数,通常使用 Python 的 async def 语法定义。Django 会自动检测这些函数,并在异步上下文中运行它们。但是,你需要使用基于 ASGI 的异步服务器来获得它们的性能优势。

import datetime
from django.http import HttpResponse

async def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><body>It is now %s.</body></html>" % now
    return HttpResponse(html)

视图装饰器

from django.views.decorators.http import require_http_methods,require_GET,require_POST,require_safe,condition
from django.views.decorators.vary import vary_on_cookie,vary_on_headers
from django.views.decorators.cache import cache_control,never_cache
from django.views.decorators.gzip import gzip_page

    # 只有 GET 或者 POST 请求可以访问这个视图
    @require_http_methods(["GET", "POST"])
    def my_view(request):
        pass

    # 只允许 GET 请求访问
    @require_GET()

    # 只允许 POST 请求访问
    @require_POST()

    # 只允许安全的请求类型,也就是 GET 和 HEAD 访问
    @require_safe()

    # 控制特殊视图中的缓存行为,来生成 ETag 和 Last-Modified 头部
    @condition(etag_func=None, last_modified_func=None)

    # 根据特殊请求头的缓存控制
    @vary_on_cookie(func=None)

    # 根据特殊请求头的缓存控制,Vary 头定义了缓存机制在构建其缓存密钥时应该考虑哪些请求报头。
    @vary_on_headers(*headers)

    # 控制服务器及客户端的缓存,通过添加所有关键字参数来修补响应的 Cache-Control 头
    @cache_control(**kwargs)

    # 控制服务器及客户端的缓存,会为当前日期/时间添加一个 Expires 头部,添加 Cache-Control: max-age=0, no-cache, no-store, must-revalidate 头到一个响应来标识禁止缓存该页面。
    @never_cache(view_func)

    # 对视图的响应内容进行压缩
    @gzip_page()

HttpRequest 对象

def my_view(request):
    if request.method == 'GET':
        do_something()
    elif request.method == 'POST':
        do_something_else()

属性:

除非另有说明,否则所有属性都应视为只读。

  • HttpRequest.scheme

    字符串类型,表示请求的协议种类,'http'或'https'。

  • HttpRequest.body

    bytes 类型,表示原始 HTTP 请求的正文。

  • HttpRequest.path

    字符串类型,表示当前请求页面的完整路径,但是不包括协议名和域名。

  • HttpRequest.path_info

    在某些 Web 服务器配置下,主机名后的 URL 部分被分成脚本前缀部分和路径信息部分。path_info 属性将始终包含路径信息部分,不论使用的 Web 服务器是什么。
    使用它代替 path 可以让代码在测试和开发环境中更容易地切换。

  • HttpRequest.method

    字符串类型,表示请求使用的 HTTP 方法。默认为大写。

  • HttpRequest.encoding

    字符串类型,表示提交的数据的编码方式(如果为 None 则表示使用 DEFAULT_CHARSET 设置)。
    这个属性是可写的,可以通过修改它来改变表单数据的编码。

  • HttpRequest.content_type

    表示从 CONTENT_TYPE 头解析的请求的 MIME 类型。

  • HttpRequest.content_params

    包含在 CONTENT_TYPE 标题中的键/值参数字典。

  • HttpRequest.GET

    一个类似于字典的对象,包含 GET 请求中的所有参数

  • HttpRequest.POST

    包含所有 POST 表单数据的键值对字典。

  • HttpRequest.COOKIES

    包含所有 Cookie 信息的字典。

  • HttpRequest.FILES

    一个类似于字典的对象,包含所有上传的文件数据。

    HttpRequest.FILES 中的每个键为<input type="file" name="" />中的 name 属性值。 HttpRequest.FILES 中的每个值是一个 UploadedFile 对象。

  • HttpRequest.META

    包含所有 HTTP 头部信息的字典。 可用的头部信息取决于客户端和服务器

    • CONTENT_LENGTH —— 请求正文的长度(以字符串计)。
    • CONTENT_TYPE —— 请求正文的 MIME 类型。
    • HTTP_ACCEPT —— 可接收的响应 Content-Type。
    • HTTP_ACCEPT_ENCODING —— 可接收的响应编码类型。
    • HTTP_ACCEPT_LANGUAGE —— 可接收的响应语言种类。
    • HTTP_HOST —— 客服端发送的 Host 头部。
    • HTTP_REFERER —— Referring 页面。
    • HTTP_USER_AGENT —— 客户端的 user-agent 字符串。
    • QUERY_STRING —— 查询字符串。
    • REMOTE_ADDR —— 客户端的 IP 地址。想要获取客户端的 ip 信息,就在这里!
    • REMOTE_HOST —— 客户端的主机名。
    • REMOTE_USER —— 服务器认证后的用户,如果可用。
    • REQUEST_METHOD —— 表示请求方法的字符串,例如"GET" 或"POST"。
    • SERVER_NAME —— 服务器的主机名。
    • SERVER_PORT —— 服务器的端口(字符串)。
  • HttpRequest.headers

    一个不区分大小写、类似 dict 的对象,包含请求中 HTTP 头部的所有信息。
    request.headers['user-agent']

  • HttpRequest.resolver_match

    对请求中的 URL 进行解析,获取一些相关的信息,比如 namespace。

中间件带来的属性

  • HttpRequest.session

    来自 SessionMiddleware 中间件:一个可读写的,类似字典的对象,表示当前会话。

  • HttpRequest.site

    来自 CurrentSiteMiddleware 中间件:get_current_site()方法返回的 Site 或 RequestSite 的实例,代表当前站点是哪个。
    Django 是支持多站点的,如果你同时上线了几个站点,就需要为每个站点设置一个站点 id。

  • HttpRequest.user

    来自 AuthenticationMiddleware 中间件:表示当前登录的用户的 AUTH_USER_MODEL 的实例,这个模型是 Django 内置的 Auth 模块下的 User 模型。如果用户当前未登录,则 user 将被设置为 AnonymousUser 的实例。
    可以使用 is_authenticated 方法判断当前用户是否合法用户

    if request.user.is_authenticated:
      pass
    else:
      pass
    

方法

  • HttpRequest.get_host()

    获取请求的原始主机

  • HttpRequest.get_port()

    返回请求的始发端口

  • HttpRequest.get_full_path()

    返回包含完整参数列表的 path。例如:/music/bands/the_beatles/?print=true

  • HttpRequest.build_absolute_uri(location)

    返回 location 的绝对 URI 形式。 如果 location 没有提供,则使用 request.get_full_path()的值。

QueryDict

QueryDict 是对 HTTP 请求数据包中携带的数据的封装

HttpRequest.GET 和 HttpRequest.POST 都是一个 django.http.QueryDict 的实例
QueryDict 的键值是可以重复的

q=QueryDict.fromkeys(['a', 'a', 'b'], value='val') # <QueryDict: {'a': ['val', 'val'], 'b': ['val']}>

q=QueryDict('a=1&a=2&c=3') # <QueryDict: {'a': ['1', '2'], 'c': ['3']}>
q.lists() # [('a', ['1', '2', '3'])]

HttpResponse 对象

使用方法

# 返回一个字符串
response = HttpResponse("Text only, please.", content_type="text/plain")

response = HttpResponse()
response.write("<p>Here's the text of the Web page.</p>")

# 设置头部字段
response = HttpResponse()
response['Age'] = 120

# 附件形式
response = HttpResponse(my_data, content_type='application/vnd.ms-excel')
response['Content-Disposition'] = 'attachment; filename="foo.xls"'

属性

  • content

    响应的内容。bytes 类型。

  • charset

    编码的字符集。 如果没指定,将会从 content_type 中解析出来。

  • status_code

    响应的状态码,比如 200。

  • reason_phrase

    响应的 HTTP 原因短语。 使用标准原因短语。

  • streaming

    这个属性的值总是 False。由于这个属性的存在,使得中间件能够区别对待流式响应和常规响应。

  • closed

    如果响应已关闭,那么这个属性的值为 True。

JsonResponse 类

JsonResponse 是 HttpResponse 的一个子类,是 Django 提供的用于创建 JSON 编码类型响应的快捷类。

response = JsonResponse({'foo': 'bar'}) # b'{"foo": "bar"}'

若要序列化非 dict 对象,必须设置 safe 参数为 False:

response = JsonResponse([1, 2, 3], safe=False)

StreamingHttpResponse 类

StreamingHttpResponse 类被用来从 Django 响应一个流式对象到浏览器。如果生成的响应太长或者是占用的内存较大,这么做更有效率。 例如,生成大型的 CSV 文件。
StreamingHttpResponse 不是 HttpResponse 的子类(而是兄弟类)

FileResponse

文件类型响应。通常用于给浏览器返回一个文件附件。
FileResponse 是 StreamingHttpResponse 的子类,为二进制文件专门做了优化。
FileResponse 需要通过二进制模式打开文件,文件会被自动关闭,所以不需要在上下文管理器中打开

response = FileResponse(open('myfile.png', 'rb'))

如果 as_attachment=True,则 Content-Disposition 被设置为 attachment,,告诉浏览器这是一个附件,以文件形式下载。否则 Content-Disposition 会被设置为 inline (浏览器默认行为)。

response = FileResponse(open('myfile.png', 'rb'),as_attachment=True,filename='a.png')

文件上传

当 Django 处理文件上传时,文件数据最终会被放置在 request.FILES。

from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import UploadFileForm

def handle_uploaded_file(f):
    with open("some/file/name.txt", "wb+") as destination:
        for chunk in f.chunks():
            destination.write(chunk)

def upload_file(request):
    if request.method == "POST":
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            handle_uploaded_file(request.FILES["file"])
            return HttpResponseRedirect("/success/url/")
    else:
        form = UploadFileForm()
    return render(request, "upload.html", {"form": form})

基于类的视图

from django.urls import path
from django.views.generic import TemplateView

urlpatterns = [
    path("about/", TemplateView.as_view(template_name="about.html")),
]

# 或者
class AboutView(TemplateView):
    template_name = "about.html"

urlpatterns = [
    path("about/", AboutView.as_view()),
]

使用通用视图

from django.views.generic import ListView
from books.models import Publisher

class PublisherListView(ListView):
    # model = Publisher # 等同于  queryset = Publisher.objects.all()
    queryset = Publisher.objects.order_by("-create_date")
    context_object_name = "favorite_publishers"
    template_name = "publishers.html"

动态过滤

# urls.py
from django.urls import path
from books.views import PublisherBookListView

urlpatterns = [
    path("books/<publisher>/", PublisherBookListView.as_view()),
]

# views.py
from django.shortcuts import get_object_or_404
from django.views.generic import ListView
from books.models import Book, Publisher


class PublisherBookListView(ListView):
    template_name = "books/books_by_publisher.html"

    def get_queryset(self):
        self.publisher = get_object_or_404(Publisher, name=self.kwargs["publisher"])
        return Book.objects.filter(publisher=self.publisher)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context["publisher"] = self.publisher
        return context

模板

变量

{{ variable }}

过滤器

  • default

    为 false 或者空变量提供默认值

    {{ value|default:"nothing" }}

    default_if_none
    如果(且仅当)value 为 None,则使用给定的默认值。

    {{ value|default_if_none:"nothing" }}

  • length

    返回值的长度。它对字符串和列表都起作用。

    {{ value|length }}

  • filesizeformat

    格式化为'人类可读'文件大小单位(即'13 KB',4.1 MB','102 bytes'等)。

    {{ value|filesizeformat }}

  • add

    把 add 后的参数加给 value。

    {{ value|add:"2" }} # 4->6
    {{ first|add:second }} # first=[1, 2, 3],second=[4, 5, 6], 将会输出[1, 2, 3, 4, 5, 6].
    
  • addslashes

    在引号前面加上斜杆。

    {{ value|addslashes }}

  • capfirst

    大写变量的第一个字母。 如果第一个字符不是字母,该过滤器将不会生效。

    {{ value|capfirst }}

  • lower

    将字符串转换为全部小写。

    {{ value|lower }}

  • title

    将所有单词的首字母大写,其它字母小写。

    {{ value|title }}

  • upper

    将字符串转换为全部大写的形式:

    {{ value|upper }}

  • center

    在给定的宽度范围内居中.

    {{ value|center:"15" }}

  • ljust

    给定宽度下左对齐。

    {{ value|ljust:"10" }}

  • rjust

    右对齐给定宽度字段中的值。

    {{ value|rjust:"10" }}

  • cut

    移除 value 中所有的与给定参数相同的字符串。

    {{ value|cut:" " }}

  • date

    根据给定格式对一个日期变量进行格式化。

    {{ value|date:"D d M Y" }}
    {{ value|time:"H:i" }}
    
  • time

    根据给定的格式,格式化时间。

    {{ value|time:"H:i" }}

  • timesince

    将日期格式设为自该日期起的时间(例如:4 天)。

    {{ blog_date|timesince:comment_date }}

  • timeuntil

    类似于 timesince,它测量从现在开始直到给定日期或日期时间的时间。

    {{ conference_date|timeuntil:from_date }}

  • make_list

    将对象转换为字符的列表。对于字符串,直接拆分为单个字符的列表。对于整数,在创建列表之前将参数强制转换为 unicode 字符串。

    {{ value|make_list }}

    如果 value 是字符串"Joel",输出将是列表['J', 'o' , 'e', 'l']。
    如果 value 为 123,输出为列表['1', '2', '3']。

  • dictsort

    接受一个包含字典元素的列表,并返回按参数中给出的键排序后的列表。

    {{ value|dictsort:"name" }}
    
    #  dictsort 也可以按指定索引对多维列表进行排序
    {% for book in books|dictsort:"author.age" %}
        {{ book.title }} ({{ book.author.name }})
    {% endfor %}
    
    {{ value|dictsort:0 }}
    
  • dictsortreversed

    dictsort 的反序功能。

  • divisibleby

    如果 value 可以被参数整除,则返回 True。

    {{ value|divisibleby:"3" }}

  • escape

    转义字符串的 HTML。

  • escapejs

    转义用于 JavaScript 字符串的字符。确保在使用模板生成 JavaScript/JSON 时避免语法错误。

    {{ value|escapejs }}

  • first

    返回列表中的第一项。

    {{ value|first }}

    如果 value 是列表['a', 'b', 'c'] ,输出将为'a'。

  • last

    返回列表中的最后一个项目。类似 first 过滤器。

    {{ value|last }}

  • random

    返回给定列表中的随机项。

    {{ value|random }}

  • floatformat

    当不使用参数时,将浮点数舍入到小数点后一位,但前提是要显示小数部分。

    {{ value | floatformat }}

    • 34.23234 -> 34.2
    • 34.00000 -> 34
    • 34.26000 -> 34.3

    如果与数字整数参数一起使用,将数字四舍五入为小数位数。

    {{ value | floatformat:3 }}

    • 34.23234 -> 34.232
    • 34.00000 -> 34.000
    • 34.26000 -> 34.260

    传递 0 作为参数,它将使 float 浮动到最接近的整数。

    {{ value | floatformat:"0" }}

    • 34.23234 -> 34
    • 34.00000 -> 34
    • 39.56000 -> 40

    传递给 floatformat 的参数为负,则会将一个数字四舍五入到小数点后的位置

    {{ value | floatformat:"-3" }}

    • 34.23234 -> 34.232
    • 34.00000 -> 34
    • 34.26000 -> 34.260
  • get_digit

    给定一个整数,返回所请求的数字,1 表示最右边的数字,2 表示第二个最右边的数字,以此类推。

    {{ value|get_digit:"2" }}

    如果 value 为 123456789,则输出 8。

  • iriencode

    将 IRI(国际化资源标识符)转换为适合包含在 URL 中的字符串。

    {{ value|iriencode }}

    如果 value 是?test=1&me=2,输出则是?test=1&me=2。

  • urlencode

    转义要在 URL 中使用的值。

    {{ value|urlencode }}

  • join

    使用字符串连接列表,类似 Python 的 str.join(list)

    {{ value|join:" // " }}

    如果 value 是列表['a', 'b', 'c'] ,输出为 a // b // c。

  • pluralize

    如果值不是 1,则返回一个复数形式,通常在后面添加's'表示。

    message{{ num_messages|pluralize }}

    cherr{{ num_cherries|pluralize:"y,ies" }}

  • linebreaks

    替换纯文本中的换行符为

    标签。

    {{ value|linebreaks }}

    如果 value 是 Joel\nis a slug,输出将为

    Joel
    is a slug

  • linebreaksbr

    替换纯文本中的换行符为
    标签。

    {{ value|linebreaksbr }}

    如果 value 是 Joel\nis a slug,输出将为 Joel
    is a slug。

  • linenumbers

    显示带行号的文本。

    {{ value|linenumbers }}

  • safe

    将字符串标记为安全,不需要转义。

  • safeseq

    将 safe 过滤器应用于序列的每个元素。 与对序列进行其他过滤操作(例如 join)一起使用时非常有用。

    {{ some_list|safeseq|join:", " }}

  • slice

    返回列表的一部分。也就是切片,与 Python 的列表切片相同的语法。

    {{ some_list|slice:":2" }} # 如果 some_list 是['a', 'b', 'c'] ,输出将为['a', 'b']。

  • slugify

    转换为 ASCII。空格转换为连字符。删除不是字母数字,下划线或连字符的字符。转换为小写。还会去除前导和尾随空格。

    {{ value|slugify }}

    如果 value 是 Joel is a slug,输出为 joel-is-a-slug。

  • stringformat

    根据参数,格式化变量。

    {{ value|stringformat:"E" }}

    如果 value 为 10,输出将为 1.000000E+01。

  • striptags

    尽可能的去除 HTML 中的标签。

    {{ value|striptags }}

  • truncatechars

    如果字符串包含的字符总个数多于指定的字符数量,那么会被截断掉后面的部分。截断的字符串将以“...”结尾。

    {{ value|truncatechars:9 }}

  • truncatechars_html

    类似于 truncatechars,但是会保留 HTML 标记。

    {{ value|truncatechars_html:9 }}

  • truncatewords

    在一定数量的字数后截断字符串。与 truncatechars 不同的是,这个以字的个数计数,而不是字符计数。

    {{ value|truncatewords:2 }}

  • truncatewords_html

    类似于 truncatewords,但是保留 HTML 标记。

    {{ value|truncatewords_html:2 }}

  • urlize

    将文字中的网址和电子邮件地址转换为可点击的链接。

    {{ value|urlize }}

  • urlizetrunc

    将网址和电子邮件地址转换为可点击的链接,就像 urlize,但截断长度超过给定字符数限制的网址。

    {{ value|urlizetrunc:15 }}

  • wordcount

    返回单词的个数。

    {{ value|wordcount }}

  • wordwrap

    以指定的行长度,换行单词。

    {{ value|wordwrap:5 }}

  • yesno

    将 True,False 和 None,映射成字符串‘yes’,‘no’,‘maybe’。

    {{ value|yesno:"yeah,no,maybe" }}

    也可以自定义返回的字符串,比如:

    {{ value|yesno:"man,woman,ladyboy" }}

标签

  • for 循环标签

    {% for athlete in athlete_list %}
        <li>{{ athlete.name }}</li>
    {% endfor %}
    
    {% for athlete in athlete_list reversed %}
        <li>{{ athlete.name }}</li>
        <li>{{ forloop.counter }}</li> # 循环的当前索引值,从 1 开始计数;
        <li>{{ forloop.counter0 }}</li> # 循环的当前索引值,从 0 开始计数;
        <li>{{ forloop.revcounter }}</li> #循环结束的次数(从 1 开始)
        <li>{{ forloop.revcounter0 }}</li> #循环结束的次数(从 0 开始)
        <li>{{ forloop.first }}</li> # 判断当前是否循环的第一次
        <li>{{ forloop.last }}</li> # 判断当前是否循环的最后一次
        <li>{{ forloop.parentloop }}</li> #对于嵌套循环,返回父循环所在的循环次数。
    {% endfor %}
    
    {% for athlete in athlete_list %}
        <li>{{ athlete.name }}</li>
    {% empty %}
        <li>Sorry, no athletes in this list.</li>
    {% endfor %}
    
  • if,elif 和 else 标签

    {% if athlete_list %}
        Number of athletes: {{ athlete_list|length }}
    {% elif athlete_in_locker_room_list %}
      Athletes should be out of the locker room soon!
    {% else %}
      No athletes.
    {% endif %}
    
  • csrf_token

    {% csrf_token %}

  • cycle

    {% for o in some_list %}
        <tr class="{% cycle 'row1' 'row2'%}">
        ...
        </tr>
    {% endfor %}
    
    '''
    <tr>
    <td class="row1">...</td>
    <td class="row1">...</td>
    </tr>
    <tr>
    <td class="row2">...</td>
    <td class="row2">...</td>
    </tr>
    '''
    
  • block

    block 标签可以被子模板覆盖。

  • extends

    表示当前模板继承自一个父模板。

  • filter

    通过一个或多个过滤器对内容过滤。需要结束标签 endfilter。

    {% filter force_escape|lower %}
      This text will be HTML-escaped, and will appear in all lowercase.
    {% endfilter %}
    
  • firstof

    输出第一个不为 False 参数。 如果传入的所有变量都为 False,就什么也不输出。

    {% firstof var1 var2 var3 %}

  • ifchanged

    检查一个值是否在上一次的迭代中被改变了
    {% ifchanged %}标签通常用在循环里。它有两个用处:检查已经渲染过的内容的当前状态。并且只会显示发生改变的内容。

    {% for match in matches %}
        <div style="background-color:
            {% ifchanged match.ballot_id %}
                {% cycle "red" "blue" %}
            {% else %}
            gray
            {% endifchanged %}
        ">{{ match }}</div>
    {% endfor %}
    
  • include

    加载指定的模板并以标签内的参数渲染

    {% include "foo/bar.html" %}
    {% include "name_snippet.html" with person="Jane" greeting="Hello" %}
    {% include "name_snippet.html" with greeting="Hi" only %}
    
  • load

    加载自定义模板标签。

    {% load foo bar from somelibrary %}

  • lorem

    这个标签是用来在模版中提供文字样本以供测试用的。

      {% lorem %} # 将输出常见的“lorem ipsum”段落。
      {% lorem 3 p %} # 输出常用的“lorem ipsum”段落和两个随机段落,每段包裹在 HTML`<p>`标签中。
      {% lorem 2 w random %} # 将输出两个随机拉丁字。
    
  • regroup

    用对象间共有的属性重组列表。

    cities = [
    {'name': 'Mumbai', 'population': '19,000,000', 'country': 'India'},
    {'name': 'Calcutta', 'population': '15,000,000', 'country': 'India'},
    {'name': 'New York', 'population': '20,000,000', 'country': 'USA'},
    {'name': 'Chicago', 'population': '7,000,000', 'country': 'USA'},
    {'name': 'Tokyo', 'population': '33,000,000', 'country': 'Japan'},
    ]
    
    {% regroup cities by country as country_list %}
      <ul>
      {% for country in country_list %}
          <li>{{ country.grouper }}
          <ul>
              {% for city in country.list %}
                  <li>{{ city.name }}: {{ city.population }}</li>
              {% endfor %}
          </ul>
          </li>
      {% endfor %}
      </ul>
    '''
    India
    Mumbai: 19,000,000
    Calcutta: 15,000,000
    USA
    New York: 20,000,000
    Chicago: 7,000,000
    Japan
    Tokyo: 33,000,000
    '''
    
  • resetcycle

    重置先前的循环,以便在下一次循环时从其第一个项目重新启动。
    如果没有参数,{% resetcycle %}将重置最后一个{% cycle %}。

    {% for coach in coach_list %}
      <h1>{{ coach.name }}</h1>
      {% for athlete in coach.athlete_set.all %}
          <p class="{% cycle 'odd' 'even' %}">{{ athlete.name }}</p>
      {% endfor %}
      {% resetcycle %}
    {% endfor %}
    
    '''
    <h1>José Mourinho</h1>
    <p class="odd">Thibaut Courtois</p>
    <p class="even">John Terry</p>
    <p class="odd">Eden Hazard</p>
    <h1>Carlo Ancelotti</h1>
    <p class="odd">Manuel Neuer</p>
    <p class="even">Thomas Müller</p>
    '''
    
    {% for item in list %}
      <p class="{% cycle 'odd' 'even' as stripe %} {% cycle 'major' 'minor' 'minor' 'minor' 'minor' as tick %}">
          {{ item.data }}
      </p>
      {% ifchanged item.category %}
          <h1>{{ item.category }}</h1>
          {% if not forloop.first %}{% resetcycle tick %}{% endif %}
      {% endifchanged %}
    {% endfor %}
    
    在这个例子中,我们有交替的奇数/偶数行和每五行出现一次的'major'行。当类别更改时,只有五行周期被重置。
    
  • spaceless

    删除 HTML 标签之间的空白,包括制表符和换行。仅会删除 tags 之间的空格,不会删除标签和文本之间的。

    {% spaceless %}
      <p>
          <a href="foo/">Foo</a>
      </p>
    {% endspaceless %}
    # <p><a href="foo/">Foo</a></p>
    
  • with

    使用一个简单地名字缓存一个复杂的变量,当你需要使用一个代价较大的方法(比如访问数据库)很多次的时候这是非常有用的。

    {% with total=business.employees.count %}
      {{ total }} employee{{ total|pluralize }}
    {% endwith %}
    
    #可以分配多个变量:
    {% with alpha=1 beta=2 %}
    ...
    {% endwith %}
    
  • url

    返回与给定视图和可选参数匹配的绝对路径引用(不带域名的 URL)

    {% url 'some-url-name' arg1=v1 arg2=v2 %}

    {% url 'some-url-name' v1 v2 %}

  • now

    显示当前的日期或时间。可以指定显示的格式。

    {% now "jS F Y H:i" %}

注释

{# greeting #}hello # hello

{% comment "Optional note" %}
    <p>Commented out text with {{ create_date|date:"c" }}</p>
{% endcomment %}

模板继承

base.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <link rel="stylesheet" href="style.css" />
    <title>{% block title %}My amazing site{% endblock %}</title>
  </head>
  <body>
    <div id="sidebar">
      {% block sidebar %}
      <ul>
        <li><a href="/">Home</a></li>
        <li><a href="/blog/">Blog</a></li>
      </ul>
      {% endblock %}
    </div>
    <div id="content">{% block content %}{% endblock %}</div>
  </body>
</html>

blog_index.html

{% extends "base.html" %}
{% block title %}My amazing blog{% endblock %}
{% block content %}
    {% for entry in blog_entries %}
        <h2>{{ entry.title }}</h2>
        <p>{{ entry.body }}</p>
    {% endfor %}
{% endblock %}

自动转义

  • 单个变量

    {{ data }}

    自动转义后输出到页面上

    {{ data|safe }}

    关闭变量上的自动转义

  • 模板块

    {% autoescape off %}
        Hello {{ name }}
    {% endautoescape %}
    

表单

Django 会处理涉及表单的三个不同部分:

  • 准备并重组数据,以便下一步的渲染
  • 为数据创建 HTML 表单
  • 接收并处理客户端提交的表单及数据

Django 的 Form 类

Django 表单系统的核心组件是 Form 类。它与 Django 模型描述对象的逻辑结构、行为以及它呈现给我们内容的形式的方式大致相同, Form 类描述一张表单并决定它如何工作及呈现。
类似于模型类的字段映射到数据库字段的方式,表单类的字段会映射到 HTML 表单的 <input> 元素。 ModelForm 通过 Form 映射模型类的字段到 HTML 表单的 <input> 元素,Django admin 就基于此。
表单字段本身也是类;他们管理表单数据并在提交表单时执行验证。

from django import forms

class NameForm(forms.Form):
    your_name = forms.CharField(label="Your name", max_length=100)

字段的最大长度由 max_length 来定义。它做了两件事情。首先它在 HTML 的 <input> 上增加了 maxlength="100" 。其次它还会在 Django 收到浏览器传过来的表单时,对数据长度进行验证(也就是服务器端验证)。

<label for="your_name">Your name: </label> <input id="your_name" type="text" name="your_name" maxlength="100" required />

视图

from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import NameForm

def get_name(request):
    if request.method == "POST":
        form = NameForm(request.POST) # 绑定数据到表单
        if form.is_valid():
            data=form.cleaned_data() # 通过验证的表单数据
            pass
            return HttpResponseRedirect("/thanks/")
    else:
        form = NameForm()

    return render(request, "name.html", {"form": form})

模板

<form action="/your-name/" method="post">
  {% csrf_token %} {{ form }}
  <input type="submit" value="Submit" />
</form>

所有的表单字段及其属性都将通过 Django 模板语言从 {{ form }} 中被解包成 HTML 标记。

内置 Field 类

  • BooleanField

    空值:False,如果字段有 required=True,则验证该值是否为 True

  • CharField

    字符串

    具有以下可选的验证参数:

    • max_length

    • min_length

    • strip

      如果 True (默认),该值将被去掉前导和尾部的空白。

    • empty_value

      用来表示“空”的值。默认为空字符串。

  • DateField

    可选的参数:

    • input_formats
  • DateTimeField

    可选的参数:

    • input_formats
  • TimeField

    可选的参数:

    • input_formats
  • IntegerField

    可选参数:

    • max_value
    • min_value
    • step_size
  • DecimalField

    可选参数:

    • max_value

    • min_value

    • max_digits

      值中允许的最大位数(小数点前的数字加上小数点后的数字,去掉前导零)。

    • decimal_places

      允许的最大小数位数。

    • step_size

      限制有效输入为 step_size 的整数倍。如果还提供了 min_value,则将其添加为偏移量以确定步长是否匹配。

  • FloatField

    可选参数:

    • max_value
    • min_value
    • step_size
  • DurationField

  • EmailField

  • URLField

  • UUIDField

    接受作为 UUID 构造函数的 hex 参数的任何字符串格式。

  • FileField

    可选的验证参数:

    • max_length

      文件名的长度

    • allow_empty_file

      文件内容可为空

  • ImageField

    在字段被清理和验证后,UploadedFile 对象将具有一个额外的 image 属性,其中包含 Pillow 的 Image 实例,用于检查文件是否为有效的图像。Pillow 在验证图像后关闭底层文件描述符,因此虽然可以访问非图像数据属性,如 format、height 和 width,但不能在不重新打开文件的情况下使用访问底层图像数据的方法,比如 getdata() 或 getpixel()。

  • FilePathField

    额外的参数;只有 path 是必须的。

    • path

      你想要列出的内容的目录的绝对路径。该目录必须存在。

    • recursive

      如果 False (默认),只提供 path 的直接内容作为选择。如果 True,目录将被递归递进,所有的子目录将被列为选择。

    • match

      正则表达式模式;只允许将名称与此表达式相匹配的文件作为选择。

    • allow_files

      可选。 可选 True 或 False。 默认值是 True。 指定是否应该包含指定位置的文件。 此项或 allow_folders 必须为 True。

    • allow_folders

      可选。 可选 True 或 False。 默认为 False。 指定是否应包括指定位置的文件夹。 此项或 allow_files 必须为 True。

  • GenericIPAddressField

    可选的参数:

    • protocol

      将有效输入限制为指定协议。接受的值是 both (默认)、IPv4 或 IPv6。匹配是不区分大小写的。

  • SlugField

    可选的参数:

    • allow_unicode

      一个布尔值,指示该字段除了接受 ASCII 字母外,还接受 Unicode 字母。默认值为 False。

    • empty_value

      用来表示“空”的值。默认为空字符串。

  • ChoiceField

    额外的参数:

    • choices

      此参数接受与模型字段的 choices 参数相同的格式。

  • JSONField

  • MultipleChoiceField

  • NullBooleanField

  • RegexField

核心字段参数

  • required

    默认情况下,每个 Field 类都假定该值是必需的,因此如果传递一个空值 -- 无论是 None 还是空字符串("")-- 那么 clean() 将引发一个 ValidationError 异常:

  • label

    指定该字段的“人类友好”标签

  • label_suffix

    覆盖表单的 label_suffix

  • initial

    指定在未绑定的 Form 中渲染这个 Field 时要使用的初始值

  • widget

    指定一个 Widget 类,以便在渲染这个 Field 时使用。

  • help_text

    指定描述性文本

  • error_messages

    覆盖字段将引发的默认错误消息

  • validators

    提供一个验证函数列表

  • localize

    本地化

  • disabled

    disabled 布尔参数设置为 True 时,使用 disabled HTML 属性禁用表单字段,使其不能被用户编辑。即使用户篡改了提交给服务器的字段值,也会被忽略,而采用表单初始数据的值。

验证器

自定义验证器

def validate_gte_18(value):
    if value < 18:
        raise ValidationError({'age': '年龄小于 18 岁'})

指定验证器

class MyModel(models.Model):
    age = models.IntegerField(validators=[validate_gte_18])

class MyForm(forms.Form):
    age = forms.IntegerField(validators=[validate_gte_18])

模型的验证器不会在调用 save()方法的时候自动执行

表单的验证器会在调用 save()方法的时候自动执行

from django.core.exceptions import ValidationError
try:
    article.full_clean()
except ValidationError as e:
    print(e.message_dict)

内置验证器

  • RegexValidator
  • EmailValidator
  • URLValidator
  • validate_email
  • validate_slug
  • validate_unicode_slug
  • validate_ipv4_address
  • validate_ipv6_address
  • validate_ipv46_address
  • validate_comma_separated_integer_list
  • int_list_validator
  • MaxValueValidator
  • MinValueValidator
  • MaxLengthValidator
  • MinLengthValidator
  • DecimalValidator
  • FileExtensionValidator
  • validate_image_file_extension

Django 管理站点

Django 最强大的部分之一是自动管理界面。它从你的模型中读取元数据,提供一个快速的、以模型为中心的界面,受信任的用户可以管理你网站上的内容。管理的推荐使用范围仅限于一个组织的内部管理工具。它不打算用于围绕你的整个前端构建。

ModelAdmin

ModelAdmin 类是管理界面中模型的表示。通常,这些都存储在你的应用程序中一个名为 admin.py 的文件中。

from django.contrib import admin
from myapp.models import Author

class AuthorAdmin(admin.ModelAdmin):
    pass

admin.site.register(Author, AuthorAdmin)

register 装饰器

用于注册你的 ModelAdmin 类

from django.contrib import admin
from .models import Author

@admin.register(Author)
class AuthorAdmin(admin.ModelAdmin):
    pass

ModelAdmin 选项

  • list_display

    指定哪些字段显示在管理的变更列表页面

    class PersonAdmin(admin.ModelAdmin):
          list_display = ["upper_case_name",'Age']
    
          @admin.display(description="Name")
          def upper_case_name(self, obj):
              return f"{obj.first_name} {obj.last_name}".upper()
    
    
  • list_display_links

    控制 list_display 中的字段是否以及哪些字段应该被链接到对象的 “更改” 页面。

  • list_editable

    设置为模型上允许在更改列表页上编辑的字段名称列表。也就是说,在 list_editable 中列出的字段将作为表单部件显示在变更列表页上,允许用户一次编辑和保存多行。
    list_editable 中的任何字段都必须在 list_display 中。
    同一字段不能同时列在 list_editable 和 list_display_links 中 。

  • list_filter

    设置 list_filter 以在管理员的更改列表页面右侧边栏上激活过滤器。
    在最简单的情况下,list_filter 接受一个字段名称的列表或元组以激活过滤

  • list_max_show_all

    控制 “全部显示” 的管理员更改列表页面上可以出现多少个项目。只有当总结果数小于或等于此配置时,管理才会在更改列表中显示 “全部显示” 链接。默认情况下,这个配置为 200。

  • list_per_page

    控制每个分页的管理变更列表页面上出现多少个项目。默认情况下,设置为 100。

  • list_select_related

    告诉 Django 在检索管理变更列表页的对象列表时使用 select_related()。这样可以省去一堆数据库查询。
    该值应是布尔值、列表或元组。默认值是 False。

  • ordering

    指定对象列表在 Django 管理视图中的排序方式。

  • search_fields

    设置 search_fields,在管理更改列表页面上启用搜索框。这应该被设置为字段名的列表,每当有人在该文本框中提交搜索查询时,就会被搜索到。

  • search_help_text

    设置 search_help_text,为搜索框指定一个描述性文本,显示在它的下面。

  • sortable_by

    默认情况下,变更列表页面允许按 list_display 中指定的所有模型字段进行排序。

  • actions

    指定要在变更列表页上提供的动作列表。

  • date_hierarchy

    将 date_hierarchy 设置为你的模型中 DateField 或 DateTimeField 的名称,变化列表页将包括一个基于日期的向下扩展。
    date_hierarchy = "pub_date"

  • empty_value_display

    指定覆盖记录字段为空(None、空字符串等)的默认显示值。默认值是 - (破折号)。

  • exclude

    指定要从表单中排除的字段名列表。

  • fields

    使用 fields 选项在 “添加” 和 “更改” 页面的表单中进行简单的布局修改,比如只显示可用字段的子集,修改它们的顺序,或者将它们分成几行。
    fields = [("url", "title"), "content"]
    url 和 title 字段将显示在同一行,content 字段将显示在它们下面的一行
    如果 fields 或 fieldsets 选项都不存在,Django 将默认在一个单一的字段集中显示每个非 AutoField 且有 editable=True 的字段,顺序与模型中定义的字段相同。

  • fieldsets

    设置 fieldsets 来控制管理员 “添加” 和 “更改” 页面的布局。
    fieldsets 是一个包含多个 2-元组的列表,每个 2-元组表示管理员表单页面上的一个 <fieldset>
    这些 2-元组的格式是 (name, field_options),其中 name 是表示 fieldset 标题的字符串,而 field_options 是关于 fieldset 的信息的字典,包括要在其中显示的字段列表。

  • filter_horizontal

    显示一个可搜索的 <select multiple>的 ManyToManyField。未选择和选择的选项并排出现在两个框中。

  • filter_vertical

    与 filter_horizontal 相同,但使用垂直显示过滤界面,未选择的选项框出现在选择选项框的上方。

  • form

    指定自定义的 ModelForm

  • formfield_overrides

    覆盖一些 Field 选项

    from django.contrib import admin
    from django.db import models
    from myapp.models import MyModel
    from myapp.widgets import RichTextEditorWidget
    
    class MyModelAdmin(admin.ModelAdmin):
        formfield_overrides = {
          models.TextField: {"widget": RichTextEditorWidget},
        }
    
  • inlines

  • preserve_filters

    默认情况下,在创建、编辑或删除对象后,应用的过滤器会被保存在列表视图中。您可以通过将此属性设置为 False 来清除过滤器。

  • radio_fields

    默认情况下,Django 的管理对于 ForeignKey 或设置了 choices 的字段使用选择框界面(<select>)。如果字段存在于 radio_fields 中,Django 将使用单选按钮接口代替。

  • autocomplete_fields

    自动完成输入

  • raw_id_fields

    默认情况下,Django 的管理员对 ForeignKey 的字段使用选择框接口(<select>)。
    raw_id_fields 是你想改变为 ForeignKey 或 ManyToManyField 的 Input 部件的字段列表。
    raw_id_fields 部件在字段旁边显示一个放大镜按钮,允许用户搜索和选择一个值。

  • readonly_fields

    该选项中的任何字段将按原样显示其数据,不可编辑

  • save_as

    设置 save_as,在管理更改表格时启用 “另存为新” 功能。

  • save_as_continue

    当 save_as=True 时,保存新对象后默认重定向到该对象的变更视图。如果设置 save_as_continue=False,则重定向到变更列表视图。
    默认情况下,save_as_continue 被设置为 True。

  • save_on_top

    设置 save_on_top 来在你的管理更改表格的顶部添加保存按钮。
    通常情况下,保存按钮只出现在表格的底部。如果设置 save_on_top,按钮将同时出现在顶部和底部。
    默认情况下,save_on_top 被设置为 False。

posted @ 2023-12-20 16:28  carol2014  阅读(18)  评论(0)    收藏  举报