Django 教程之Templates模板

满和安
2023-12-01


创建模板常用的方法:

  1. 每个APP各自创建自己的模板
  2. 统一放到项目同名的APP中,即blog

我一般喜欢各种解耦,就是为了出现问题好解决,只需处理出问题的地方就好,所以考虑到后期会使用多个模板,简单说就是博客会有多个主题,将HTML页面的设计和后端逻辑设计分离,前后端分离,后台不变,前台随意变更展现。

故在与manage.py同级目录下创建templates目录,目录下创建模板文件夹,可理解为主题文件夹,如default,里面创建templates和static文件夹,静态

配置static目录

static即静态文件, 静态文件处理是每个网站都必备的步骤, django的静态文件处理一般都遵循固定的套路, 这里分debug模式和非debug模式来说

简单说下, settings.py中一般会针对static有两个配置:
STATIC_URL - 可以理解为通过url访问static文件的路径
STATIC_ROOT - 可以理解为你打算在服务器上存储static文件的路径(通过 python manage.py collectstatic命令)
除此之外, 在settings.py同级的urls.py内还需要把STATIC_URL和django的url连接起来, 通常:

from django.contrib.staticfiles.urls import staticfiles_urlpatterns
urlpatterns += staticfiles_urlpatterns()

很简单, 就这么三步.
但这只是适用于常规配置.
怎么个常规法呢, 就是说你只有一个debug=True的环境(开发), 和一个debug=False的环境(生产)
之所以提这个debug, 是因为你应该了解, 把静态文件丢给web server一起处理不是个明智的决定. 通常来说在开发的时候我们可以图方便, 但是上了生产环境, 我们会把静态文件都丢给诸如nginx这样的反向代理来处理, 当然也未必是nginx, 如果你采用了前后端分离, 用k8s分开部署, 也可以在ingress中为不同路径配置请求的服务.
如果认真看了上述的staticfiles_urlpatterns的函数其实也不难发现, django对此的默认配置其实就是只在debug=True的情况下允许访问静态资源, 在False时干脆关掉了这个url path.
这样有点粗暴, 现实开发中也许我们会需要一个staging环境做预发布环境, 也许我们需要在这个环境上书写api文档, 这就意味着你在这个环境上也需要适当访问一些静态资源.
因此就要对上述函数做写改动, 让其在特定环境下也开放static的访问

重写url

也很简单, 只要看一下原函数是怎么写的, 把相应部分改掉

https://www.jianshu.com/p/50b98121b0fb来源:简书著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

配置目录

  1. 打开setting.py文件

  2. 修改STATIC_URL相关内容

    源码

    STATIC_URL = '/static/'
    

    添加路径

    STATICFILES_DIRS = [
        os.path.join(BASE_DIR, 'templates', THEME, "static"),
    ]
    
  3. 模板文件使用 {% load staticfiles %} 运行

不加入load staticfiles来使用静态文件请参考setting设置文件

配置templates目录

  1. 打开setting.py文件

  2. 修改TEMPLATES内容

    源码

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [],
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                ],
            },
        },
    ]
    

    添加THEME标签和DIRS路径

    THEME = 'default'
    
    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'templates', THEME, 'templates')],
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                ],
            },
        },
    ]
    

    APP_DIRS是控制搜索APP内TEMPLATES的开关

  3. 运行

模板语言

模板渲染的官方文档

模板渲染只需记住两种语法方式:{{ 变量 }} 和 {% 标签 %}

{{ 变量 }}

语法:{{ 变量}}

  • 模板会计算这个变量,然后用结果替换掉它本身
  • 变量的命名包括任何字母数字以及下划线 ("_")的组合。 变量名称中不能有空格或标点符号
  • 深度查询据点符(.),字典取值:{{字典}}.键 ,属性或方法取值:{{ tag.name }},列表取值:{{列表}}. 索引

小栗子:

time.html

<html>   
   <body>
      Hello World!!!<p>Today is {{today}}</p>
   </body>   
</html>

view.py

import datetime
from django.shortcuts import render

def time(request):
   today = datetime.datetime.now().date()
   return render(request, "time.html", {"today" : today}) 

blog/urls.py

from django.conf.urls import url
from . import views

urlpatterns = [
    # 首页
    url(r'^$', views.time, name='index'),  # 主页,自然排序
]

{% 标签 %}

{% block sidebar_toc %}
{% include 'sidebar.html' %}
{% endblock %}

在html中进行调用

参考

https://www.cnblogs.com/sss4/p/7071183.html

https://blog.csdn.net/weixin_30267697/article/details/101668183

https://www.w3cschool.cn/django/django-template.html

https://www.e-learn.cn/django/django-template-system

分析

由页面就可以看出来,在刷新网页的时候,头部和底部基本是不变的,侧边栏只有两种变化,一种是主页显示,一种是文章目录,无论是点击分类、标签云、个人说明等等只有内容区域在变化,故

  1. 所有不变的板块编写通用模板,base.html
  2. 导航的header和底部footer区域单独编写,便于管理,嵌套在base.html
  3. 侧边栏单独编写,在存在文章目录的时候进行变更,sidebar.html逻辑判断即可,嵌套在base.html
  4. 主页只是在内容区显示文章列表,包括标题、缩略图、时间等信息,index.html嵌套在base.html
  5. 分类页和标签页相同,搜索指定内容以列表的形式显示在内容区,基于index.html进行筛选
  6. 文章详情页需要单独编写,内容区直接显示,支持markdown,配合侧边栏实现目录,嵌套在base.html

编写模板

这里以基础模板base.html和主页模板index.html为例进行展示,只是展示,其他的请下载源码

在编写模板之前,先来编写URL和VIEW代码,这里使用的是 class-based view ,不懂以后我会提到

目前只是展示,先了解一下

逻辑视图View

from django.views.generic import ListView
from .models import Article

class IndexView(ListView):
    model = Article
    template_name = 'index.html'
    context_object_name = 'article_index'
    paginate_by = 5

路由URL

from django.conf.urls import url
from .views import IndexView

urlpatterns = [
    # 首页
    url(r'^$',IndexView.as_view(),name='index'),  # 主页,自然排序
]

base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, shrink-to-fit=no", user-scalable=no">
    <title>Johnny’s Blog</title>
    <link rel="icon" href="{% static 'images/avatar.png' %}" type="image/x-icon"/>
    <link rel="shortcut icon" href="#">

        <link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">

        <link rel="stylesheet" href="{% static 'css/blog.css' %}">

        <!-- jQuery first, then Tether, then Bootstrap JS. -->
        <script src="{% static 'js/bootstrap.min.js' %}"></script>

        <script src="{% static 'js/blog.js' %}"></script>

</head>

<!-- 非常开心你看到了源码!!~~~~-->
<body>
<div class="container">
    <div class="row blog-box-shadow">
        <div class="col-xl-9 col-lg-12 blog-main" id="pjax-box">
            {% include "header.html" %}
            <!--设置页脚沉底-->
            <div id="wrapper">
                {% block content_detail %}{% endblock %}
                <div id="push"></div>
            </div>
            {% include "footer.html" %}
        </div>
        {% block sidebar_toc %}{% endblock %}
    </div>
</div>

    <!-- 页脚沉底增加样式 -->
    <style>
        html, body {
            height: 100%;
            margin: 0;
        }

        #wrapper {
            min-height: 100%;
            margin-bottom: -60px;
        }

        #footer,
        #push {
            height: 60px;
        }
    </style>

</body>
</html>

index.html

{% extends 'base.html' %}

{% block content_detail %}


<!--article header, show current url page, index or category or tag-->
<!--article_index from views IndexView-->
<header class="blog-post-page-title">
    {% for article in article_index %}
    {% if forloop.first %}
        {% url 'blog:category' article.category as category_url %}
        {% for tag in article.tags.all %}
            {% url 'blog:tag' tag.id as tag_url %}
            {% if tag_url == request.path %}
                <h3>下面是含有标签 “{{ tag.name }}” 的文章</h3>
            {% elif category_url == request.path %}
                <h3>下面是在分类 “{{ article.category }}” 下的文章</h3>
            {% endif %}
        {% endfor %}
    {% endif %}
    {% endfor %}
</header>

<!--article body, include img summary create_date update_date category-->
<div class="blog-main-post">
    <div class="index-post-br"></div>
    {% for article in article_index %}
    <article class="blog-post-block">
        {% if article.img_link %}
            <header>
                <div class="blog-post-block-img">
                    <img src="/media/{{ article.img_link }}">
                </div>
            </header>
        {% endif %}
        <div class="blog-post-block-padding">
            <a href="{% url 'blog:article' article.id %}" >{{ article.title }} </a>
            <section>
                {{ article.summary }}
            </section>
            <footer>
                 <span>
                     <i class="fa fa-folder-o"></i>
                    <a href="{% url 'blog:category' article.category %}" itemprop="url" rel="index">{{ article.category }}</a>
                 </span>

                 <span>
                    <time datetime="{{ article.create_date }}"><i class="fa fa-clock-o"></i>创建于{{ article.create_date }}</time>
                    {% if article.update_date > article.create_date %}
                    <time datetime="{{ article.update_date }}"><i class="fa fa-clock-o"></i> 更新于{{ article.update_date }}</time>
                    {% endif %}
                 </span>
            </footer>
        </div>
    </article>
{% endfor %}

<!--article paginated, set paginated paginate on views-->
<!--is_paginated first last left right left_has_more right_has_more from views IndexView-->
{% if is_paginated %}
<nav id="pagination" class="blog-pagination" >
    {% if first %}
        <span class="page-number current" href="?page=1">1</span>
    {% endif %}
    {% if left %}
        {% if left_has_more %}
            <span class="space">...</span>
        {% endif %}
        {% for i in left %}
        <a class="extend next" rel="next" href="?page={{ i }}">{{ i }}</a>
        {% endfor %}
    {% endif %}
    <a class="page-number " href="?page={{ page_obj.number }}">{{ page_obj.number }}</a>
    {% if right %}
        {% for i in right %}
        <a class="extend next" rel="next" href="?page={{ i }}">{{ i }}</a>
        {% endfor %}
        {% if right_has_more %}
        <span class="space">...</span>
        {% endif %}
    {% endif %}
    {% if last %}
        <a class='page-number' href="?page={{ paginator.num_pages }}">{{ paginator.num_pages }}</a>
    {% endif %}
</nav>
{% endif %}
</div>
{% endblock %}

{% block sidebar_toc %}
{% include 'sidebar.html' %}

{% endblock %}


自定义标签和过滤器

https://www.cnblogs.com/qicun/p/9961819.html

标签,是为了做一些功能。过滤器,是对斜杠前面的数据做过滤。

为什么要自定义标签和过滤器? 因为自带的不够用,需要结合需求,来自定义。

说明

  1. 应用必须在settings.py中INSTALLED_APPS下诸恶
  2. 新建templatetags目录,必须在应用根目录下
  3. templatetags目录为python package,包含__init__.py
  4. templatetags目录下创建py文件,名称任意
  5. 自定义的 tags 和 filters 会保存在模块名为 templatetags 的目录内。模块文件的名字即稍候你用来加载 tags 的名字,所以小心不要采用一个可能与其它应用自定义的 tags 和 filters 冲突的名字。
  6. 用法 比如py文件为apptags.py
from django import template

register = template.Library()

缺点:不能作为IF条件
优点:参数可以无数个
@register.simple_tag
def get_Tag_list():
    """返回标签列表"""
    return Tag.objects.all()
    
    
缺点:只能有两个参数
优点:可以用于IF判断。    
@register.filter
def get_Tag_list():
    """返回标签列表"""
    return Tag.objects.all()

在HTML文件中进行引用,必须使用as,否则不行,不知道原因

{% load 'apptags.py' %}
<div class="container">
    {% get_tag_list as tag %}
    {% for i in tag %}
    <p class="text-center">{{ i.create_date }}</p>
    {% endfor %}
</div>

在settings中的INSTALLED_APPS配置当前app(之前已经配置),不然django无法找到自定义的simple_tag

在app中创建templatetags模块(模块名只能是templatetags)

创建任意 .py 文件,如:my_tags.py

# 注册自定义标签函数
register = template.Library()

@register.simple_tag
def get_tag_list():
    """
    获取标签的QuerySet对象=
    :return: 返回文章所有标签
    """
    return Tag.objects.all()

在使用自定义simple_tag和filter的html文件中导入之前创建的 my_tags.py

{% load my_tags %} 

使用simple_tag和filter(如何调用)

-------------------------------.html{% load xxx %}        # num=12{{ num|filter_multi:2 }} #24 {{ num|filter_multi:"[22,333,4444]" }} {% simple_tag_multi 2 5 %}  参数不限,但不能放在if for语句中{% simple_tag_multi num 5 %}

注意:filter可以用在if、for等语句后,simple_tag不可以

{% if num|filter_multi:30 > 100 %}    {{ num|filter_multi:30 }}{% endif %}
 类似资料: