django 入门笔记:视图及模版

django 及 rest_framework 笔记链接如下:
django 入门笔记:环境及项目搭建
django 入门笔记:数据模型
django 入门笔记:视图及模版
django 入门笔记:Admin 管理系统及表单
django 入门笔记:通用视图类重构视图
django_rest_framework 入门笔记:Serializer
django_rest_framework 入门笔记:视图函数重构
django_rest_framework 入门笔记:分页,多条件筛选及权限认证设置
django 自带 user 字段扩展及头像上传](https://www.jianshu.com/p/d45a687c3f41)

前面部分将数据库的操作讲述了一遍,注意部分我们终于可以看到些真实的东西了,而不是数据...数据...数据...

创建 django 视图
普通视图
  1. 首先在应用文件夹下创建 urls.py 文件,用来配置视图的 url,然后我们需要在项目下的 urls.py 文件中将该应用的 urls 配置进去
    # 在项目下 urls.py 文件配置应用的 urls.py 文件
    from django.conf.urls import url, include
    from django.contrib import admin
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        # include 作用:在 django 匹配 url 时候匹配完 blog/ 后,再次匹配下层地址,所以在 blog/ 
        # 后面不可以添加 "$" 符号,不然会导致不能匹配到地址,namespace 为了区分不同应用下同名的模版
        url(r'^blog/', include('blog.urls', namespace="blog")),
    ]
    
  2. 在应用文件夹下的 views.py 文件中加入视图
    from django.http import HttpResponse
    
    def home(request):
        return HttpResponse("Hello django")
    
  3. 在应用下的 urls.py 文件中将视图文件配置进去
    from django.conf.urls import url
    from . import views
    
    # 加上 app_name, 值同 include 中 namespace 的值,否则可能会找不到 url
    app_name = 'blog'
    urlpatterns = [
     # 当模版引用本地 url 时候需要用到 name 字段值,例如
     # <a href="{% url 'blog:home' %}"><b>Home</b></a>
        url(r'^home$', views.home, name=home),
    ]
    
  4. 命令行将代码运行
    python manage.py runserver 192.168.x.xxx:8080
    
    然后可以通过网址 "http://192.168.x.xxx:8080/blog/index" 访问编写的界面,应该是下面这个样子的(原谅我偷懒没有改 ip)
    第一个 django 界面
  1. 当 url 中带入参数进行传递时,例如

    def hours_ahead(request, offset):
     try:
         offset = int(offset)
     except ValueError as e:
         print(e)
     dt = datetime.datetime.now() + datetime.timedelta(hours=offset)
     return HttpResponse("{} hours later is {}".format(offset, dt))
    

    那么我们在 url 配置的时候需要将 offset 参数传入到 url 中去,需要涉及到正则表达式

    urlpatterns = [
     # ?P<offset> 为传递的参数字段名,紧随其后的是参数值的匹配正则
     # 可以通过 http://192.168.x.xxx:8080/time/ahead/(offset)/ 来访问相应网址
        url(r'^time/ahead/(?P<offset>\d{1, 2})/$', view.hours_ahead, name="time_ahead")
    ]
    
    带参数

    reverse() 在配置 url 时候的大用处(这里先提下,项目中会接触到)

    # 假设我们有个网址为 192.168.x.xxx:8080/post/1/ 其中 1 为 post 的 id 根据 id 不同显示不同 post
    # 网址的正则为 url(r'post/(?P<pk>[0-9]+)/$', view.post, name="post_detail")
    class Post(models.Model):
     title = models.CharField("标题", max_length=100)
     
     def get_post_url(self):
         # reverse 会自动指向 'blog:post_detail' 所指向的 url,kwargs 为传入的参数值
         return reverse('blog:post_detail', kwargs={'pk': self.pk})
    

    上面我们提到了正则表达式,这里把 python 常用的正则语法列一下,方便学习

    语法 说明 表达式 匹配
    字符串 匹配自身 abc abc
    . 匹配换行符外任意字符 a.c abc
    \ 转义字符,使字符改变原来意思 a.c a.c
    [] 字符集,对应位可以是字符集任意字符 a[bc]d acd
    \d 数字:[0-9] o\do o2o
    \D 非数字 a\Dc a,c
    \s 空白字符[<Space>, \t,\r,\n,\f,\v] a\sc a c
    \S 非空白字符 a\Sc abc
    \w 单词字符:[A-Za-z0-9_] a\wc abc
    \W 非单词字符 a\Wc a c
    * 匹配前一个字符串 0 或者无限次 c[acv]* c
    + 匹配前一个字符串 1 或者无限次 c[acv]+ ca
    ? 匹配前一个字符串 0 或者 1 次 cc? c
    {m} 匹配前一个字符串 m 次 ac{2} acc
    {m, n} 匹配前一个字符串 m 到 n 次 ac{1, 3} acc
    ^ 匹配字符串开头,必须以紧随的字符开头 ^abc abc
    $ 匹配字符串末尾 abc$ abc
    | 表示左右表达式任意匹配一个 abc|def def

书写界面的时候,我们不可能每次都去 view 界面写,而且在 view 界面写也不能给页面增加特效,接着就需要发挥模版的作用了

使用模版创建视图
  1. 首先在项目根目录下创建 templates 文件夹,用来放视图模版,然后在项目下的 settings.py 文件中注册 templates 文件夹,使 django 能够在 templates 文件夹中找到相应的模版,在 TEMPLATES 中的 DIRS 列表中加入如下代码

    'DIRS': [os.path.join(BASE_DIR, 'templates')],
    
  2. 在 templates 文件夹下再创建放应用模版的文件夹 例如 blog ,然后在 blog 创建 index.html 作为 index 视图的模版

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>{{ title }}</title>
    </head>
    <body>
    <h1>{{ welcome }}</h1>
    </body>
    </html>
    
  3. 修改视图文件函数

    from django.shortcuts import render
    
    def index(request):
     # context 中的参数名和模版中 {{ }} 包裹的相同
     return render(request, 'blog\index.html', context={
            'title': "My Blog Home",
            'welcome': "Welcome to My Blog"
     })
     
    # 或者可以用以下方法来写
    def index(request):
     title = "My Blog Home"
     welcome = "Welcome to My Blog"
     return render(request, 'blog\index.html', locals())
    

    然后我们就可以看到如下的界面,django 会把 view 的值传到模版中去

    第一次使用模版

    使用模版的话,我们就需要了解一下模版内置的标签和过滤器,这对我们日后的开发可以提高很多效率

  4. django 内置模版标签

    1. {% extends %} 继承模版标签

    2. 用两个大括号括起来的文字 (例如 {{ post_title }}) 称为变量 (variable),这意味着在此处插入指定变量的值

    3. {% if %} [{% else %} 可省略] {% end if%} 标签

      • {% if %} 标签接受 and, or 或者 not 关键字来对多个变量做判断,或者对变量取反 (not);
      • 不允许在同一个标签中同时使用 and 和 or,但可以多次使用同一个逻辑操作符;
      • 不支持用圆括号来组合比较操作;
      • 没有 {% elif %} 标签,只能 {% if %} 嵌套达到效果;
      • 一定要用 {% endif %} 关闭每一个 {% if %} 标签

      eg:

      {% if {{ str }} %}
          <p>Value is not null</p>
      {% else %}
          <p>Value is null</p>
      {% endif %}
      
    4. {% for %} [{% empty %} 可省略] {% endfor %} 标签

      • 给标签增加一个 reversed 使得该列表被反向迭代 eg: {% for s in s_list reversed%}

      • 可以嵌套使用 {% for %} 标签

      • 执行循环之前通常先检测列表的大小,因此 for 标签支持一个可选的 {% empty %} 分句

      • 不支持 break 和 continue,退出循环时候,可以改变正在迭代的变量,让其仅仅包含需要迭代的项目。

      • 每个 {% for %} 循环里有一个称为 forloop 的模板变量,这个变量存在一些表示循环进度信息的属性,模板解析器碰到{% endfor %}标签后,forloop就不可访问了

        forloop.counter/counter0

        循环的执行次数的整数计数器,从1/0开始计数

        forloop.revcounter/revcounter0

        循环执行后的剩余项数量,首次执行为总数/总数减一,最后置为1/0

        forloop.first/last 首次/最后一次迭代为 True

        forloop.parentloop 当前循环的上一级循环的 forloop 对象的引用(嵌套循环情况下)

      eg:

      {% for country in countries %}
          <table>
          {% for city in country %}
              <tr>
              <td>Country {{ forloop.parentloop.counter }}</td>
              <td>City {{ forloop.counter }}</td>
              <td>{{ city }}</td>
              </tr>
          {% endfor %}
          </table>
      {% empty%}
          <p>There is no country</p>
      {% endfor %}
      

      {% ifequal/ifnotequal%} [{% else %}可省略] {% endifqual/ifnotequal%} 标签

      比较两个变量的值并且显示一些结果,支持可选的 {% else%} 标签;只有模板变量,字符串,整数和小数可以作为 {% ifequal %} 标签的参数

    5. {% autoescape %}{% endautoescape %} 关闭代码块中的自动转义,父类已经关闭则子类也关闭

  5. django 常用内置模版过滤器
    模板过滤器是在变量被显示前修改它的值的一个简单方法,以 "|" 拼接,过滤器的参数跟随冒号之后并且总是以双引号包含,例如 {{ value|add:"2" }} 返回值为 value + 2 的值

    add:"n",对象相加,如果是数字则是数字加法,列表则是列表的和,无法相加为空。

    addslashes,增加反斜杠,处理 Javascript 文本非常有用

    truncatewords:"n",显示变量前 n 个字符

    pluralize:"y, ies",单词的复数形式,可以通过参数设置复数形式

    date:"xxx",按指定的格式字符串参数格式化 date 或者 datetime 对象,例如 {{ pub| date:"F j, Y" }} length,返回变量的长度;对于列表,返回列表元素的个数。对于字符串,返回字符串中字符的个数

    safe,当系统设置 autoescaping 打开的时候,该过滤器使得输出不进行 escape 转换

    striptags,删除 value 中的所有 HTML 标签

    .......

  6. django 自定义过滤器和标签

    1. 在应用目录下创建 templatetags 文件夹,同时建立空文件 __ init __.py 和过滤器文件 例如 custom_filter.py
    2. 在 custom_filter.py 文件中添加过滤器
    from django import template
    from blog.models import Category
    # register 是 template.Library 的实例,是所有注册标签和过滤器的数据结构
    register = template.Libary()
    
    # 自定义过滤器
    @register.filter
    def get_value(dic, key_name):
     return dic.get(key_name)
     
    @register.filter
    def get_attr(d, m):
     if hasattr(d, m):
         return getattr(d, m)
        
    # 自定义标签
    @register.simple_tag
    def get_all_category
     return Category.objects.all()
    

    引用自定义过滤器时需要先导入再使用

    {% load custom_filter %}
    <html lang="en">
    <body>
     <h1>{{ articles|get_value:"article"|get_attr:"id" }}</h1>
        {% get_all_category as category_list%}
        <ul>
            {% for category in category_list%}
             <li>
                    <a href="#">{{ category.name }}</a>
             </li>
            {% empty %}
             There is no category!
            {% endfor%}
        </ul>
    </body>
    </html>
    

最终所展现的效果是这样的(这边只放一部分效果,整体效果可以下载项目自行运行查看)
使用过滤器添加分类列表
静态文件处理

静态文件主要包括我们需要用到的 css,js 文件等,使用静态文件我们只需要以下两步即可

  1. 在应用目录下创建 static 文件夹,可以将常用的 css 文件,js 文件等放入该文件夹
  2. 在需要引用静态文件的模版中做如下处理
    {# 引入静态文件,只有加载标签模版后才能使用 {% static %} 标签 #}
    {% load staticfiles %}
    {# 在需要引入的地方引入相应文件,例如在 static 文件夹下有个 blog 文件夹,需要引用其 #}
    {# 中的 css/bootstrap.min.css 文件可以通过如下方式进行引入 #}
    <link rel="stylesheet" href="{% static 'blog/css/bootstrap.min.css' %}">
    

最后附上整个项目的地址:blog_project

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容