Django开发--step4 详情界面url的获取

在我们开发的博客系统中,每一篇博客的连接都是不同的,比如第一篇博客的url /post/1 第二篇是/post/2

一、设置文章详细页的URL

在urlpatterns上添加一句  app_name=‘blog'

这句话的作用是告诉Django这个urls.py模块时属于blogapp这个应用的

在blogapp/urls.py中添加

url(r'^post/(?P<pk>[0-9]+)/$', views.detail, name='detail'),

(?P<pk>[0-9]+)表示命名捕获组,作用是把用户访问的url里吧括号内匹配的字符串捕获作为关键字参数传给其对应的视图函数detail

在上述这个正则表达式中,匹配的数字会在detail视图函数被调用时进行传递,实际的视图函数

detail(request, pk=255)

为了方便生成上述的URL 我们在Post类中定义一个get_absolute_url方法

    # 自定义 get_absolute_url 方法, 加载Post类的最后
    # 记得从 django.urls 中导入 reverse 函数
    def get_absolute_url(self):
        return reverse('blog:detail', kwargs={'pk': self.pk})

关于reverse函数

 reverse 函数,它的第一个参数的值是 'blog:detail',意思是 blog 应用下的 name=detail 的函数,由于我们在上面通过 app_name = 'blog' 告诉了 Django 这个 URL 模块是属于 blog 应用的,因此 Django 能够顺利地找到 blog 应用下 name 为 detail 的视图函数,于是 reverse 函数会去解析这个视图函数对应的 URL,我们这里 detail 对应的规则就是 post/(?P<pk>[0-9]+)/ 这个正则表达式,而正则表达式部分会被后面传入的参数 pk 替换,所以,如果 Post 的 id(或者 pk,这里 pk 和 id 是等价的) 是 255 的话,那么 get_absolute_url 函数返回的就是 /post/255/ ,这样 Post 自己就生成了自己的 URL。

 

二、编写视图函数

关于detail的视图函数

def detail(request, pk):
    post = get_object_or_404(Post, pk=pk)
    return render(request, 'blog/detail.html', context={'post': post})

pk与文章的id是等价的,从 django.shortcuts 模块导入的 get_object_or_404 方法,其作用就是当传入的 pk 对应的 Post 在数据库存在时,就返回对应的 post,如果不存在,就给用户返回一个 404 错误,表明用户请求的文章不存在。

 

三、模板继承

在templates下创建base.html

由于在index和detail中,只有main标签内内容是不同的,所有我们可以把相同的部分抽取出来,复制index.html 中的内容到base.html中在 main 标签处,删掉main标签中之前的内容

...
<main class="col-md-8">
    {% block main %}
    {% endblock main %}
</main>
<aside class="col-md-4">
  {% block toc %}
  {% endblock toc %}
  ...
</aside>
...

其中,block也是模板标签,作用是占位,该block的名字是main

然后在index.html中,我们就可以删去之前的东西,在最顶部加入

{% extends 'base.html' %}

来继承base.html

另外在 {% block main %}{% endblock main %} 包裹的地方填上 index 页面应该显示的内容:


{% extends 'base.html' %}

{% block main %}
    {% for post in post_list %}
        <article class="post post-1">
          ...
        </article>
    {% empty %}
        <div class="no-post">暂时还没有发布的文章!</div>
    {% endfor %}
{% endblock main %}

 

四、Markdown与代码高亮

Markdown 是一种 HTML 文本标记语言,只要遵循它约定的语法格式,Markdown 的渲染器就能够把我们写的文章转换为标准的 HTML 文档,从而让我们的文章呈现更加丰富的格式,例如标题、列表、代码块等等 HTML 元素。

安装Python Markdown

激活虚拟环境,使用命令 :pip install markdown

然后,对 post 的 body 的值做一下渲染,把 Markdown 文本转为 HTML 文本再传递给模板:在视图函数中

import markdown
from django.shortcuts import render, get_object_or_404
from .models import Post

def detail(request, pk):
    post = get_object_or_404(Post, pk=pk)
    # 记得在顶部引入 markdown 模块
    post.body = markdown.markdown(post.body,
                                  extensions=[
                                     'markdown.extensions.extra',
                                     'markdown.extensions.codehilite',
                                     'markdown.extensions.toc',
                                  ])
    return render(request, 'blog/detail.html', context={'post': post})

注意这里我们给 markdown 渲染函数传递了额外的参数 extensions,它是对 Markdown 语法的拓展,这里我们使用了三个拓展,分别是 extra、codehilite、toc。extra 本身包含很多拓展,而 codehilite 是语法高亮拓展,这为我们后面的实现代码高亮功能提供基础,而 toc 则允许我们自动生成目录。

在文章中插入图片,目前能做的且推荐做的是使用外链引入图片。比如将图片上传到七牛云这样的云存储服务器,然后通过 Markdown 的图片语法将图片引入。Markdown 引入图片的语法为:![图片说明](图片链接)

当前查看效果,页面中并没有像我们预期的那样,而全是HTML标签,接下来,我们加入过滤器

关于safe标签:

 Django 出于安全方面的考虑,任何的 HTML 代码在 Django 的模板中都会被转义(即显示原始的 HTML 代码,而不是经浏览器渲染后的格式)。为了解除转义,只需在模板标签使用 safe 过滤器即可,告诉 Django,这段文本是安全的,在模板中找到展示博客文章主体的 {{ post.body }} 部分,为其加上 safe 过滤器,{{ post.body|safe }},大功告成。

 

代码高亮

安装Pygmants 激活虚拟环境 运行 pip install Pygments安装即可

然后在base.html中,引入

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

就可以了

 

测试代码高亮与Markdown的代码

# 一级标题

## 二级标题

### 三级标题

~~~{.python}
def detail():
    return 'like'
~~~
```python
@requires_authorization
def somefunc(param1='', param2=0):
    '''A docstring'''
    if param1 > param2: # interesting
        print 'Greater'
    return (param2 - param1 + 1) or None

class SomeClass:
    pass

>>> message = '''interpreter
... prompt'''
```

JavaScript 示例:

``` javascript
/**
* nth element in the fibonacci series.
* @param n >= 0
* @return the nth element, >= 0.
*/
function fib(n) {
  var a = 1, b = 1;
  var tmp;
  while (--n >= 0) {
    tmp = a;
    a += b;
    b = tmp;
  }
  return a;
}

document.write(fib(10));
```


- 列表项1
- 列表项2
- 列表项3

> 这是一段引用

![测试图片](https://wx2.sinaimg.cn/mw690/006ZeP2Nly1fsnfk733fsj30qo0zkgvh.jpg)

 

五、使用自定义模板标签

在页面中,有“最新文章”这个展示区

自己定义一个模板标签,例如名为 get_recent_posts 的模板标签,它可以这样工作:我们只要在模板中写入 {% get_recent_posts as recent_post_list %},那么模板中就会有一个从数据库获取的最新文章列表,并通过 as 语句保存到 recent_post_list 模板变量里。这样我们就可以通过 {% for %} {% endfor%} 模板标签来循环这个变量,显示最新文章列表了,这和我们在编写博客首页面视图函数是类似的。首页视图函数中从数据库获取文章列表并保存到 post_list 变量,然后把这个 post_list 变量传给模板,模板使用 for 模板标签循环这个文章列表变量,从而展示一篇篇文章。这里唯一的不同是我们从数据库获取文章列表的操作不是在视图函数中进行,而是在模板中通过自定义的 {% get_recent_posts %} 模板标签进行。当然,自定义标签需要符合Django的规范。

在blogapp下创建一个templatetags文件夹,然后在这个文件夹下创建一个__init__.py

之后再在当前目录下创建一个blog_tags.py的文件夹

模板标签本质上还是Python函数

最终 blog_app.py的代码是:

from django import template
from ..models import Post, Category

register = template.Library()  # 实例化的template.Library类

# 最新文章模板标签  num代表获取前num篇  
# 将函数装饰为register.simple_tag,这样就可以在模板中使用{% get_recent_posts %}调用这个函数了
@register.simple_tag
def get_recent_posts(num=5):
    return Post.objects.all().order_by('-created_time')[:num]

# 归档模板标签
@register.simple_tag
def archives():
    return Post.objects.dates('created_time', 'month', order='DESC')

# 分类模板标签
@register.simple_tag
def get_categories():
    return Category.objects.all()

自定义模板标签的使用:

首先在base.html中加入 

{% load blog_tags %}

最新文章处

<div class="widget widget-recent-posts">
                    <h3 class="widget-title">最新文章</h3>
                    {% get_recent_posts as recent_post_list %}
                    <ul>
                        {% for post in recent_post_list %}
                        <li>
                            <a href="{{ post.get_absolute_url }}">{{ post.title }}</a>
                        </li>
                        {% empty %}
                        暂无文章
                        {% endfor %}
                    </ul>
                </div>

分类与归档处,也进行同样结构的修改

<h3 class="widget-title">分类</h3>
                    {% get_categories as category_list %}
                    <ul>
                        {% for category in category_list%}
                        <li>
                            <a href="#">{{ category.name }}<span class="post-count">(13)</span></a>
                        </li>
                        {% empty %}
                        暂无分类
                        {% endfor %}
                    </ul>

就可以了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值