YOLO813

Django初学(1)

    django,准确的说并不是CMS(Content Management System),而是一个web框架,并无法做到像WordPress,drupal这种CMS安装之后网站立刻就搭建起来。想尝试django建站,准备工作还是比较多的,当然,自己写的源码能操作的地方就更多了。以下介绍的内容并非都是python建站必需,使用其他语言建站可能也会使用。

  • 虚拟环境

windows下安装virtualenvwrapper-win,如果使用的是vs code,那么想在代码中使用设置好的虚拟环境可点击左下角python版本进行选择,或者点击enter interpreter path切换。默认的虚拟环境会安装在C盘用户的Envs文件夹下(如果该文件夹不存在会自动创建),如果想要配置虚拟环境的放置目录,可在系统变量(S)下面添加变量名为WORKON_HOME,变量值为D:\Envs(存放路径),记得重启命令行窗口。

  • 代码工具

我目前使用的是vs code,当然pycharm更为好用。vs code目前安装的扩展为Django, HTML Snippets(用于快速书写html标签,前端),python。

  • Django的MVT模式

    M ,模型(Model):编写程序应有的功能,负责业务对象与数据库的映射(ORM)。一般写在app的models.py文件中,我们可以通过from django.db import models,写一个类继承自models.Model以此来创建一张表,我们可以通过自定义的__str__返回查询结果,可通过 class Meta属性定义db_table名称。

    V ,视图(View):负责业务逻辑,并在适当时候调用 Model和 Template。可以简单的理解为当用户在访问某个url时,我们需要返给用户的回应或界面,一般在views.py中通过函数或者类(主要是当get与post请求均存在时方便书写)返回一个HttpResponse对象,当然也可以使用render函数返回模板及参数。

    T ,模板 (Template):负责如何把页面(html)展示给用户。当然前提是你得在settings.py中配置了TEMPLATES的DIRS,网络上的教程基本上都是django2.0之前的教程,都是使用os.path来进行拼接路径,但是我用的是django 3.1(注定要躺坑,但是最新版本肯定是要优化些),里面导入了Path模块,直接使用BASE_DIR进行拼接即可。

  • Django模板DTL、

    DTL(django template language),django自带的模板语言,可以理解为是一种带有特殊语法的HTML文件。在DTL中,所有的标签都是写在{%%}和{%end%}中,例如:

{% for per in person %}
     {% with zs=person.2 %} or {% with person.2 as zs %}
         <li>{{zs}}</li>
     {% endwith %}
{% endfor %}

    而with语句相当于定义一个变量/别名,上述两种方法是一样的效果,唯一需要注意的是如果使用=号,两边就不要加空格了,会报错。

    变量的名称可使用{{variable}}包括。一些常用的标签语法,autoescape接off可关闭关键字转义(如<div>,输出会默认将其转义成&lt;div&gt;),verbatim标签可将DTL模板默认解析那些特殊字符功能关闭掉(例如{}),使用art-template模板时我们想使用art的标签就可以使用该标签,当然,标签有开必有合。

  • DTL中的过滤器

    过滤器可以简单的理解为带参数的函数,在django的模板中,我们可以通过{{}}来调用views视图context传过来的参数,例如,我在views.py中定义如下函数

def name():
    return "zhangxiaofei"
def index():
    context = {
        'name': name
    }
    return render(req, 'index.html', context = context)

    在index.html中我们可以是可以通过{{name}}包裹来调用该函数,但是如果想通过name函数传递参数,django会报错

“could not parse the remainder:......”

    如果函数没法传递参数,那就很鸡肋了,所以DTL中使用过滤器来解决这个问题,过滤器使用管道符起始,最多接受两个参数,官方的过滤器网络介绍很多,如date使用方法如下

{{time_test | date:'Y-M*n-D*d-H-m-s'}}

     我们也可以自定义自己的过滤器,在app下方新建templatetags python包(命名不能修改),新建过滤器文件名(我命名为my_filter.py),通过template.Library()对象注册过滤器,调用filter传入定义的过滤器名称及函数名,最后将过滤器所在的app放入到配置文件settings.py的INSTALLED_APPS中,即可在模板文件使用过滤器(需在模板文件中的头部load 过滤器文件名 {% load my_filter %} ),my_filter.py文件内容如下:

from django import template
from datetime import datetime
register = template.Library()
# 我们也可以在函数上方加入装饰器@register.filter()来得到一个以函数名来命名的过滤器
# 或者在装饰器中自定义过滤器名 @register.filter("name")
def greet(value, word):
    return value + 'hello'+ word
# 如果函数加入了@register.filter()装饰器则无需在下方再注册
register.filter("my_test_filter", greet)

    模拟微信朋友圈时间线展示功能过滤器,“刚刚”,“几分钟前”,“1小时前”

@register.filter('t_slince')
def time_slince(value):
    if not isinstance(value, datetime):
        return value
    now = datetime.now()
    timestamp = (now - value).total_seconds() # datetime.timedelta(days=-1, seconds=86286, microseconds=779884)
    #47.242738
    if timestamp <= 60:
        return "刚刚"
    elif 60< timestamp <= 60*60:
        return "%s分钟前"% int(timestamp/60)
    elif 60*60< timestamp <= 60*60*24:
        return "%s小时前"% int(timestamp/(60*60))
    elif 60*60*24< timestamp <= 60*60*24*30:
        return "%s天前"% int(timestamp/(60*60*24))
    else:
        return value.strftime("%Y/%m/%d %H:%M")
  • 模板结构的继承和包含

    主要是include和extends标签,这两个标签没有闭合,因为引入就可以使用了。

    include标签可以引入其他模板的内容,需要注意的是如果在views视图中定义了某个上下文context的变量,那么这个变量将会是公用的,例如,index中包含了header文件,而index对应的views视图中定义了name变量,如果header中也存在name变量,那么header文件也会读取到index视图中的name变量。那么如果是其它html文件(非index和header)中存在name变量可以读取到值吗?答案是不可以!但是可以在include header文件时利用with 定义变量的方法将name赋值,那么其它html文件就可以取到这个值了(这一点extends中也是一样的)。

# index.html
{% include 'polls/includeTest.html' with withtest='1234' %}

# includeTest.html
<div>{{withtest}}</div>  # 1234

    extends标签为继承,必须放在第一行(如果前面是空白的当然没关系),例如每个页面的菜单栏经常是不变化的,将其抽取出来做一个base.html用于其它文件继承,减少重复代码量,如果想要在index.html中间书写额外的内容,可以在base中开一个口子,例如

# base.html
<!DOCTYPE html>
<html lang="en">
    ...
    {% block body %}
    base中的内容
    {% endblock body %}
    ...
</html>

# index.html
{% extends 'base.html' %}
{% block body %}
首页
{% endblock body %}

    那么在区块body的内容中都是index中的定制内容,而如果还想继承base区块中body的内容,那么在index的body内容中增加如下变量(记住,是双花括号的变量,并非标签)

{{block.super}}

    就是这么便捷,人生苦短,我用python。

  • 静态文件的加载
1.app下新建static文件夹
2.INSTALLED_APPS中安装该app
3.即可使用,例如: <img src="static/1.jpg">
# 前提
settings.py中的STATIC_URL = '/static/'

    但是这种方法不安全,如果settings.py中的STATIC_URL路径一旦做了更改,那么网页中的static路径也需要重构,DTL改进方法如下:

{% load static %}
<img src="{% static '1.jpg' %}">

    默认在所有安装的app下面寻找static文件夹(不要作死的改名)里面为1.jpg的文件,这个会导致一个问题,就是当有两张同名图片时路径会重复导致可能取不到想要的图片,我们还可以更进一步的优化,例如在static文件夹下面再建立app的目录:

templates\static\templates\1.jpg

    如果你觉得有些文件不适合放在app的static文件夹下,可以在settings.py配置如下目录

STATICFILES_DIRS = [BASE_DIR / 'static/']

    即可在全局(app同级目录下)建立static目录,django在已安装app的目录中寻找不到内容时会前往STATICFILES_DIRS 进行寻找。

    我们每次写DTL都需要在前面load static,可以考虑将static变成我们的内置标签,在TEMPLATES 中的OPTIONS增加builtins一行代码,再不用每次手动加载static标签了。

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR/ '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',
            ],
            #添加如下配置
            'builtins':['django.templatetags.static']
        },
    },
]