首页展示的是所有文章的列表,当用户看到感兴趣的文章时,他点击文章的标题或者继续阅读的按钮,应该跳转到文章的详情页面来阅读文章的详细内容。现在让我们来开发博客的详情页面,有了前面的基础,开发流程都是一样的了:首先配置 URL,即把相关的 URL 和视图函数绑定在一起,然后实现视图函数,编写模板并让视图函数渲染模板。
设计文章详情页的 URL
回顾一下我们首页视图的 URL,在 blog\urls.py 文件里,我们写了:
blog/urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
]
首页视图匹配的 URL 去掉域名后其实就是一个空的字符串。对文章详情视图而言,每篇文章对应着不同的 URL。比如我们可以把文章详情页面对应的视图设计成这个样子:当用户访问 <网站域名>/post/1/ 时,显示的是第一篇文章的内容,而当用户访问 <网站域名>/post/2/ 时,显示的是第二篇文章的内容,这里数字代表了第几篇文章,也就是数据库中 Post 记录的 id 值。下面依照这个规则来绑定 URL 和视图:
blog/urls.py
from django.conf.urls import url
from . import views
app_name = 'blog'
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^post/(?P<pk>[0-9]+)/$', views.detail, name='detail'),
]
Django 使用正则表达式来匹配用户访问的网址。这里 r'^post/(?P<pk>[0-9]+)/$'
整个正则表达式刚好匹配我们上面定义的 URL 规则。这条正则表达式的含义是,以 post/ 开头,后跟一个至少一位数的数字,并且以 / 符号结尾,如 post/1/、 post/255/ 等都是符合规则的,[0-9]+ 表示一位或者多位数。此外这里 (?P<pk>[0-9]+)
表示命名捕获组,其作用是从用户访问的 URL 里把括号内匹配的字符串捕获并作为关键字参数传给其对应的视图函数 detail
。比如当用户访问 post/255/ 时(注意 Django 并不关心域名,而只关心去掉域名后的相对 URL),被括起来的部分 (?P<pk>[0-9]+)
匹配 255,那么这个 255 会在调用视图函数 detail 时被传递进去,实际上视图函数的调用就是这个样子:detail(request, pk=255)
。我们这里必须从 URL 里捕获文章的 id,因为只有这样我们才能知道用户访问的究竟是哪篇文章。
可能上述的正则表达式你有点难以理解,关于正则表达式的部分并非 Django 相关的内容,而是 Python 的内容。Django 只是在这里使用了 Python 处理正则表达式的 re 模块。因此如果想更好地理解 Python 中正则表达式的相关知识,请自行查看 Python 官方文档中 re 模块的文档。
此外我们通过 app_name='blog'
告诉 Django 这个 urls.py 模块是属于 blog 应用的,这种技术叫做视图函数命名空间。我们看到 blog\urls.py 目前有两个视图函数,并且通过 name 属性给这些视图函数取了个别名,分别是 index、detail。但是一个复杂的 Django 项目可能不止这些视图函数,例如一些第三方应用中也可能有叫 index、detail 的视图函数,那么怎么把它们区分开来,防止冲突呢?方法就是通过 app_name 来指定命名空间,命名空间具体如何使用将在下面介绍。如果你忘了在 blog\urls.py 中添加这一句,接下来你可能会得到一个 NoMatchReversed 异常。
为了方便地生成上述的 URL,我们在 Post
类里定义一个 get_absolute_url
方法,注意 Post
本身是一个 Python 类,在类中我们是可以定义任何方法的。
blog/models.py
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
from django.utils.six import python_2_unicode_compatible
@python_2_unicode_compatible
class Post(models.Model):
...
def __str__(self):
return self.title
# 自定义 get_absolute_url 方法
# 记得从 django.urls 中导入 reverse 函数
def get_absolute_url(self):
return reverse('blog:detail', kwargs={'pk': self.pk})
注意到 URL 配置中的 url(r'^post/(?P<pk>[0-9]+)/$', views.detail, name='detail')
,我们设定的 name='detail'
在这里派上了用场。看到这个 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 视图函数
接下来就是实现我们的 detail
视图函数了:
blog/views.py
from django.shortcuts import render, get_object_or_404
from .models import Post
def index(request):
# ...
def detail(request, pk):
post = get_object_or_404(Post, pk=pk)
return render(request, 'blog/detail.html', context={'post': post})
视图函数很简单,它根据我们从 URL 捕获的文章 id(也就是 pk,这里 pk 和 id 是等价的)获取数据库中文章 id 为该值的记录,然后传递给模板。注意这里我们用到了从 django.shortcuts 模块导入的
get_object_or_404
方法,其作用就是当传入的 pk 对应的 Post 在数据库存在时,就返回对应的 post
,如果不存在,就给用户返回一个 404 错误,表明用户请求的文章不存在。
编写详情页模板
接下来就是书写模板文件,从下载的博客模板(如果你还没有下载,请 点击这里 下载)中把 single.html 拷贝到 templates\blog 目录下(和 index.html 在同一级目录),然后改名为 detail.html。此时你的目录结构应该像这个样子:
blogproject\
manage.py
blogproject\
__init__.py
settings.py
...
blog/
__init__.py
models.py
,,,
templates\
blog\
index.html
detail.html
在 index 页面博客文章列表的标题和继续阅读按钮写上超链接跳转的链接,即文章 post
对应的详情页的 URL,让用户点击后可以跳转到 detail 页面:
templates/blog/index.html
<article class="post post-1">
<header class="entry-header">
<h1 class="entry-title">
<a href="{{ post.get_absolute_url }}">{{ post.title }}</a>
</h1>
...
</header>
<div class="entry-content clearfix">
...
<div class="read-more cl-effect-14">
<a href="{{ post.get_absolute_url }}" class="more-link">继续阅读 <span class="meta-nav">→</span></a>
</div>
</div>
</article>
{% empty %}
<div class="no-post">暂时还没有发布的文章!</div>
{% endfor %}
这里我们修改两个地方,第一个是文章标题处:
<h1 class="entry-title">
<a href="{{ post.get_absolute_url }}">{{ post.title }}</a>
</h1>
我们把 a 标签的 href 属性的值改成了 {{ post.get_absolute_url }}。回顾一下模板变量的用法,由于 get_absolute_url 这个方法(我们定义在 Post 类中的)返回的是 post
对应的 URL,因此这里 {{ post.get_absolute_url }} 最终会被替换成该 post
自身的 URL。
同样,第二处修改的是继续阅读按钮的链接:
<a href="{{ post.get_absolute_url }}" class="more-link">继续阅读 <span class="meta-nav">→</span>
</a>
这样当我们点击首页文章的标题或者继续阅读按钮后就会跳转到该篇文章对应的详情页面了。然而如果你尝试跳转到详情页后,你会发现样式是乱的。这在 真正的 Django 博客首页 时讲过,由于我们是直接复制的模板,还没有正确地处理静态文件。我们可以按照介绍过的方法修改静态文件的引入路径,但很快你会发现在任何页面都是需要引入这些静态文件,如果每个页面都要修改会很麻烦,而且代码都是重复的。下面就介绍 Django 模板继承的方法来帮我们消除这些重复操作。
模板继承
我们看到 index.html 文件和 detail.html 文件除了 main 标签包裹的部分不同外,其它地方都是相同的,我们可以把相同的部分抽取出来,放到 base.html 里。首先在 templates 目录下新建一个 base.html 文件,这时候你的项目目录应该变成了这个样子:
blogproject\
manage.py
blogproject\
__init__.py
settings.py
...
blog\
__init__.py
models.py
,,,
templates\
base.html
blog\
index.html
detail.html
把 index.html 的内容全部拷贝到 base.html 文件里,然后删掉 main 标签包裹的内容,替换成如下的内容。
templates/base.html
...
<main class="col-md-8">
{% block main %}
{% endblock main %}
</main>
<aside class="col-md-4">
{% block toc %}
{% endblock toc %}
...
</aside>
...
这里 block 也是一个模板标签,其作用是占位。比如这里的 {% block main %}{% endblock main %} 是一个占位框,main 是我们给这个 block 取的名字。下面我们会看到 block 标签的作用。同时我们也在 aside 标签下加了一个 {% block toc %}{% endblock toc %} 占位框,因为 detail.html 中 aside 标签下会多一个目录栏。当 {% block toc %}{% endblock toc %} 中没有任何内容时,{% block toc %}{% endblock toc %} 在模板中不会显示。但当其中有内容是,模板就会显示 block 中的内容。
在 index.html 里,我们在文件最顶部使用 {% extends 'base.html' %}
继承 base.html,这样就把 base.html 里的代码继承了过来,另外在 {% block main %}{% endblock main %} 包裹的地方填上 index 页面应该显示的内容:
templates/blog/index.html
{% extends 'base.html' %}
{% block main %}
{% for post in post_list %}
<article class="post post-1">
...
</article>
{% empty %}
<div class="no-post">暂时还没有发布的文章!</div>
{% endfor %}
<!-- 简单分页效果
<div class="pagination-simple">
<a href="#">上一页</a>
<span class="current">第 6 页 / 共 11 页</span>
<a href="#">下一页</a>
</div>
-->
<div class="pagination">
...
</div>
{% endblock main %}
这样 base.html 里的代码加上 {% block main %}{% endblock main %} 里的代码就和最开始 index.html 里的代码一样了。这就是模板继承的作用,公共部分的代码放在 base.html 里,而其它页面不同的部分通过替换 {% block main %}{% endblock main %} 占位标签里的内容即可。
如果你对这种模板继承还是有点糊涂,可以把这种继承和 Python 中类的继承类比。base.html 就是父类,index.html 就是子类。index.html 继承了 base.html 中的全部内容,同时它自身还有一些内容,这些内容就通过 “覆写” {% block main %}{% endblock main %}(把 block 看做是父类的属性)的内容添加即可。
detail 页面处理起来就简单了,同样继承 base.html ,在 {% block main %}{% endblock main %} 里填充 detail.html 页面应该显示的内容,以及在 {% block toc %}{% endblock toc %} 中填写 base.html 中没有的目录部分的内容。不过目前的目录只是占位数据,我们在以后会实现如何从文章中自动摘取目录。
templates/blog/detail.html
{% extends 'base.html' %}
{% block main %}
<article class="post post-1">
...
</article>
<section class="comment-area">
...
</section>
{% endblock main %}
{% block toc %}
<div class="widget widget-content">
<h3 class="widget-title">文章目录</h3>
<ul>
<li>
<a href="#">教程特点</a>
</li>
<li>
<a href="#">谁适合这个教程</a>
</li>
<li>
<a href="#">在线预览</a>
</li>
<li>
<a href="#">资源列表</a>
</li>
<li>
<a href="#">获取帮助</a>
</li>
</ul>
</div>
{% endblock toc %}
修改 article 标签下的一些内容,让其显示文章的实际数据:
<article class="post post-{{ post.pk }}">
<header class="entry-header">
<h1 class="entry-title">{{ post.title }}</h1>
<div class="entry-meta">
<span class="post-category"><a href="#">{{ post.category.name }}</a></span>
<span class="post-date"><a href="#"><time class="entry-date"
datetime="{{ post.created_time }}">{{ post.created_time }}</time></a></span>
<span class="post-author"><a href="#">{{ post.author }}</a></span>
<span class="comments-link"><a href="#">4 评论</a></span>
<span class="views-count"><a href="#">588 阅读</a></span>
</div>
</header>
<div class="entry-content clearfix">
{{ post.body }}
</div>
</article>
再次从首页点击一篇文章的标题或者继续阅读按钮跳转到详情页面,可以看到预期效果了!
总结
本章节的代码位于:Step8: blog detail view。
如果遇到问题,请通过下面的方式寻求帮助。
- 在下方评论区留言。
- 将问题的详细描述通过邮件发送到 djangostudyteam@163.com,一般会在 24 小时内回复。
- 在 Pythonzhcn 社区的新手问答版块 发布帖子。
-- EOF --
博主,你的图片没法显示了
博主你好,我这边在详情页这一步有点迷茫, 导入 from django.urls import reverse 这个得时候 一直显示报错是 哪里没有对吗, 这个 django.urls 是指向得哪个??
django.urls 是 django 目录下的 urls.py 模块,报的什么错呢?
markdown语法的文章存入数据库后,在页面加载一次后就变成了html形式的,怎么办?
我找到原因了,在我们继承DetailView的类中,get_object方法我们对post.body处理时改变了数据库中的内容
test
你好,想请教下,像目前教程左侧的列表怎么实现呢,没有开发经验,不太懂
文章受益匪浅!用的Django2和Python3.7,看的还是有些痛苦滴!😂
你好博主,我想请教一下,我后台admin发布文章,但文章无法分段(我在admin后台编辑的时候是分了段的),且行文中出现了<p><br>等等html标签,这是怎么回事哈?
我也遇到同样的问题,请问解决了吗
<aside class="col-md-4">
{% block toc %}
{% endblock toc %}
...
</aside>
注意此段只需要占位符而已,而不像main内容用占位符去替换,对比了代码找了半天才查出问题
跳转到详情页面后,文章的标题,作者,文章内容,类别等均没有显示,就是用{{}}里的代码块不起作用。排除detail.html代码出错可能,因为我下载了本节代码测试也是一样的效果。这是什么原因呢?
视图函数:
url.py
models.py
解决了,原来是视图函数的detail 函数的Post后面没有写完整,相当于没有创建实例
想了半天没想通网页url中提取的 255(pk)是怎么来的,想了半天,才发现应该是
def get_absolute_url(self): return reverse('blog:detail',kwargs={'pk': self.pk})
中的模块自带的self.pk给出的ID记录...
前面一直想提取ID需要链接,可是没链接提取不了id,陷入死循环,啊哈哈
还有几个问题哈,如果我删除了一个post,继续增加post,会发现删除的那个post的pk好像会占用一个位置,也就是说一共只有三个post但是第四个post还是pk=4。
如果我要查看sqlite3数据库里面的东西该如何查看呢,在学校一直用的mysql,有可视化工具,可是这个我都不知道数据库在哪里
用数据库可视化软件打开 db.sqlite3 就可以了,和mysql管理是一样的。pk主键是递增的,一旦设定就无法更改,所以数字只会递增,删除掉一些记录后主键就会不连续,这是主键的特点。
博主你好,看了你这个教程受益颇多,但是这里还是有一个问题,在生成post列表显示index里面时,post.pk并没有值啊
确保模板中正确地引用:{{ post.pk }},确保post变量的确是文章记录,比如post.title 有值。
你需要在detail.html中加一个for循环进行提取,要不然是没有post.pk值的,我使用的mysql数据库,亲试有效
test
你好,我想请问下点击继续为什么不是跳转到此文章具体内容(后台添加的文章),而是我们自己写的detail.html,还有看不懂那个reverse是怎么能够展示文章内容,该怎么查找相关知识呢?
我是初学者,试着回答一下。
1. 在index页面,点击继续后,实现代码应该是下面这段
<div class="read-more cl-effect-14"> <a href="{{post.get_absolute_url}}" class="more-link">继续阅读 <span class="meta-nav">→</span></a></div>
那么会发送请求request,跳到相应的博客url。
2. 上面的request请求会被视图函数detail(views.py里面的)处理,如下:
def detail(request, pk):
post = get_object_or_404(Post, pk=pk)
return render(request, 'blog/detail.html', context={'post': post})
接着就跳到detail页面,并把相应的post对象当做模板变量传到render函数里面,就把detail页面渲染出来了。
太棒了你,谢谢,解决了我的疑问
还有个问题,那这样要怎么能够获取到后台的数据页面展示出来
def detail(request, pk):
post = get_object_or_404(Post, pk=pk) #这句已经能够从数据库里面把Post类的对象取出来了,即博客数据
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}) #这句就把之前的对象传到detail.html页面去显示了
你好,请问出现
url(r'post/(?P<pk>[0-9]+)/', views.detail, name='detail'),
SyntaxError: invalid syntax
是什么问题?谢谢。
修正一下:
url(r'^post/(?P<pk>[0-9]+)/$', views.detail, name='detail'),
但还是错误
url(r'^post/(?P<pk>[0-9]+)/$', views.detail, name='detail'),
看看是不是一样
没看出来有错误,可能不是这里的原因。
改成 re_url(r'post/(?P<pk>[0-9]+)/', views.detail, name='detail'),
前边的from 。。。。import url 改为from 。。。。import url ,re_url
index file miss this line ({% load static %}) and then cause some error.
Thanks so much. Really!
假设用户点击一个网页:/post/255/,这里的255是怎么生成的,点这个网页的时候这255就生成了吗?用户在打开一个网页的时候肯定要生成一个URL给django匹配,比较纳闷这个用户点击的URL是怎么来的(我知道流程:点击一个网页,django传到URL里匹配,匹配到调用相应视图函数,视图函数再渲染模板)
我们通常在 a 标签的 href 属性设置用户要访问的 URL。教程中就有示例,例如点击标题跳转。
博主你好, 有个疑问想请帮忙解答下。
按照你博客写的我在 blog/urls.py 下配置了 url(r'^post/(?P<pk>[0-9]+)/$', views.detail, name='detail'),
然后在Model 里面的Post类下面get_absolute_url 函数reverse方法 return reverse('blog:detail', kwargs={'pk': self.pk}) 是无法成功匹配到正则的。
改成如下,却又可以:
blogproject/urls.py 下配置 url(r'^post/(?P<pk>[0-9]+)/$', views.detail, name='detail'), 然后reverse方法 return reverse('detail', kwargs={'pk': self.pk}) 内除去appname匹配正则正常了。
我也是 ,按你的这样改就可以了,不明所以
博主你好,,我在详情页加了两个标签上一篇和下一篇文章,,,请问怎么获取前一篇和下一篇的url以及标题呢
测试
博主您好
我现在不想只是显示个id,想url后面部分自定义成文章标题的拼音:
/post/255/ →/post/wenzhangxiangqing/
我看了下django-uuslug,
这是要动数据库模型吗?有没有简单一点的方法呢?
你要在model中添加slug字段,并且修改相应的 url patern
好了 感谢!
你在urls里调用了相应数据表的title吗?
博主你好!
我想把url后面部分自定义成中文编码!
/post/255/ →/post/%E6%88%91%E7%9A%84%E5%8D%9A%E5%AE%A2/
一定要动数据库才能行吗,有没有简单点的方法
还有请问博主(?P<pk>[0-9]+)为什么不是[0-9]+而一定要在前面写上?P<pk>这是为什么?
这是浏览器编码,django无能为力的,有些浏览器会显示中文,有些则是显示这种编码。
看看 python re 正则模块的命名捕获组。
请问一下,这个错误到底哪里解决啊,代码也对了半天实在是无解了。
TypeError at /_reverse_with_prefix() argument after ** must be a mapping, not setRequest Method:GETRequest URL:http://127.0.0.1:8000/Django Version:2.0.3Exception Type:TypeErrorException Value:_reverse_with_prefix() argument after ** must be a mapping, not setException Location:/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/django/urls/base.py in reverse, line 88Python Executable:/Library/Frameworks/Python.framework/Versions/3.6/bin/python3Python Version:3.6.4Python Path:['/Users/Evenhb/Documents/python_test/Django/myblog', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python36.zip', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/lib-dynload', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages']Server time:星期六, 7 四月 2018 17:58:35 +0800Error during template renderingIn template /Users/Evenhb/Documents/python_test/Django/myblog/templates/base.html, error at line 0
请帖出相关的错误代码。
我后来在其他地方发现一个更好解决获取url路径的方法.老师教的这种在models中添加一个方法来获取也是一种思想,但是我感觉可以直接在模板中就获取了.用url 'blog:detail' 这种方法也可以直接获取到对应应用中的视图
哈哈哈,看了好几遍终于看懂了。博主有好几句话很重要却很容易让我给忽略了,建议认真看逐句分析理解,虽然有一段确实绕,对新手的我,收获很多。感谢博主的分享。
我在运行这个到这里的时候发生
AttributeError at /blog/post/3/'list' object has no attribute 'body'
Request Method:GET
Request URL:http://127.0.0.1:8000/blog/post/3/
Django Version:1.11
Exception Type:AttributeErrorException Value:'list' object has no attribute 'body'Exception Location:/Users/bai/pyproject/pdjango/myblogs/blog/views.py in detail, line 20Python Executable:/Users/bai/anaconda3/bin/python
Python Version:3.6.0Python
Path:['/Users/bai/pyproject/pdjango/myblogs', '/Users/bai/anaconda3/lib/python36.zip', '/Users/bai/anaconda3/lib/python3.6', '/Users/bai/anaconda3/lib/python3.6/lib-dynload', '/Users/bai/anaconda3/lib/python3.6/site-packages', '/Users/bai/anaconda3/lib/python3.6/site-packages/Sphinx-1.5.1-py3.6.egg', '/Users/bai/anaconda3/lib/python3.6/site-packages/aeosa', '/Users/bai/anaconda3/lib/python3.6/site-packages/setuptools-27.2.0-py3.6.egg']
Server time:星期五, 26 一月 2018 19:34:56 +0800
这个是什么原因啊?
说明你返回的 post 是一个 list,请检查返回的值确保正确。
没有url,可以用path实现url(r'^post/(?P<pk>[0-9]+)/$', views.detail, name='detail'),这个吗
可以,path('post/<int:pk>/', views.detail, name='detail'),
--URL 命名空间还是有点搞不清
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^author-polls/', include('polls.urls', namespace='author-polls', app_name='polls'))
网上很多是 {% url 'author:index' %} ,这样使用但是 app_name到底有什么用呢
在这里 https://segmentfault.com/q/1010000002802975 你在外层的 urlpatterns 用了 include 吧?用 include() 的时候,请不要加 $
请问什么 使用 include()时 不要加 $ ?
本人环境Mac py3.6.3 Django1.11.6 按照教程里面代码,如下
在blogproject/urls.py 里面 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^$', include('blog.urls')),]在blog/urls.py里面 urlpatterns = [ url(r'^$', views.index, name='index'), url(r'^post/(?P<pk>[0-9]+)/$', views.detail, name='detail'),] 会报错:Error during template renderingIn template /Users/dev/temp_python/temp02-django/blogproject/templates/blog/index.html, error at line 74Reverse for 'detail' with keyword arguments '{'pk': 1}' not found. 1 pattern(s) tried: ['$post/(?P<pk>[0-9]+)/$']64<div class="copyrights">Modified by <a href="http://zmrenwu.com/">追梦人物的博客</a></div>6566<div class="content-body">67 <div class="container">68 <div class="row">69 <main class="col-md-8">70 {% for post in post_list %}71 <article class="post post-{{ post.pk }}">72 <header class="entry-header">73 <h1 class="entry-title">74 <a href="{{ post.get_absolute_url }}">{{ post.title }}</a>
解决方法是 ,在blogproject/urls.py 里面改为 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'', include('blog.urls')), ]在blogproject/urls.py 去掉对 ^$ 对空字符串的匹配直接使用空字符串 '' (双单引号内不含空格) 则程序正常运行。。。
本人环境Mac py3.6.3 Django1.11.6 按照教程里面代码,如下
在blogproject/urls.py 里面 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^$', include('blog.urls')),]在blog/urls.py里面 urlpatterns = [ url(r'^$', views.index, name='index'), url(r'^post/(?P<pk>[0-9]+)/$', views.detail, name='detail'),]
会报错:
Error during template renderingIn template /Users/dev/temp_python/temp02-django/blogproject/templates/blog/index.html, error at line 74Reverse for 'detail' with keyword arguments '{'pk': 1}' not found. 1 pattern(s) tried: ['$post/(?P<pk>[0-9]+)/$']64<div class="copyrights">Modified by <a href="http://zmrenwu.com/">追梦人物的博客</a></div>6566<div class="content-body">67 <div class="container">68 <div class="row">69 <main class="col-md-8">70 {% for post in post_list %}71 <article class="post post-{{ post.pk }}">72 <header class="entry-header">73 <h1 class="entry-title">74 <a href="{{ post.get_absolute_url }}">{{ post.title }}</a>
解决方法是 ,在blogproject/urls.py 里面改为 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'', include('blog.urls')), ]在blog/urls.py 去掉对 ^$ 对空字符串的匹配直接使用空字符串 '' (双单引号内不含空格) 则程序正常运行。。。
damonfly本人环境Mac py3.6.3 Django1.11.6 按照教程里面代码,如下在blogproject/urls.py 里面 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^$', include('blog.urls')),]在blog/urls.py里面 urlpatterns = [ url(r'^$', views.index, name='index'), url(r'^post/(?P<pk>[0-9]+)/$', views.detail, name='detail'),] 会报错:Error during template renderingIn template /Users/dev/temp_python/temp02-django/blogproject/templates/blog/index.html, error at line 74Reverse for 'detail' with keyword arguments '{'pk': 1}' not found. 1 pattern(s) tried: ['$post/(?P<pk>[0-9]+)/$']64<div class="copyrights">Modified by <a href="http://zmrenwu.com/">追梦人物的博客</a></div>6566<div class="content-body">67 <div class="container">68 <div class="row">69 <main class="col-md-8">70 {% for post in post_list %}71 <article class="post post-{{ post.pk }}">72 <header class="entry-header">73 <h1 class="entry-title">74 <a href="{{ post.get_absolute_url }}">{{ post.title }}</a>解决方法是 ,在blogproject/urls.py 里面改为 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'', include('blog.urls')), ]在blog/urls.py (这里我手快有误应该是blogproject/urls.py) 去掉对 ^$ 对空字符串的匹配直接使用空字符串 '' (双单引号内不含空格) 则程序正常运行。。。
"{{ post.get_absolute_url }}"无法获得详情页的url时,要将blogproject/urls改为 url(r'',include('blog.urls',namespace = 'blog')),
![](http://upload-images.jianshu.io/upload_images/2046288-e9a217810acab27c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
加图片好麻烦。建议楼主加入评论图片功能
赞一个,解决了我的问题
Unknown command: 'runserve'
Type 'manage.py help' for usage.
博主,这是个什么情况,manage.py替换了还是这样
有点尴尬,解决了
楼主,请问个问题,这个从主页跳转到详情页面,可以用Js来做并传值吗?具体应该怎么做呢?
请参考js相关功能的文档,我对此没有过研究。
/blog/post/{{ post.pk }} 我觉得这样写就行了
ERRORS:blog.Post_tags: (fields.E336) The model is used as an intermediate model by 'blog.Post.tags', but it does not have a foreign key to 'Post' or 'Tag'.System check identified 1 issue (0 silenced).
请问这是哪里出错了
from django.urls import reverse
ModuleNotFoundError: No module named 'django.urls'
按照博主教程一路走下来,开启服务,提示没有Django.urls这个模块。不知道什么原因
解决了,from django.core.urlresolvers import reverse
博主好,本章节之前的内容都能实现成功,项目环境和教程中完全的一样。但是之后添加detail函数后为什么会出现这样的编码错误
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd0 in position 222: invalid continuation byte
应该不存在编码的改变或者问题啊
每个文件为了避免编码错误,在文件头都添加了# -*-coding:utf-8 -*-
一部分的错误显示:File "C:\Python3\lib\traceback.py", line 520, in _load_lines frame.line File "C:\Python3\lib\traceback.py", line 282, in line self._line = linecache.getline(self.filename, self.lineno).strip() File "C:\Python3\lib\linecache.py", line 16, in getline lines = getlines(filename, module_globals) File "C:\Python3\lib\linecache.py", line 47, in getlines return updatecache(filename, module_globals) File "C:\Python3\lib\linecache.py", line 137, in updatecache lines = fp.readlines() File "C:\Python3\lib\codecs.py", line 321, in decode (result, consumed) = self._buffer_decode(data, self.errors, final)UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd0 in position 222: invalid continuation byte
编码问题可能是你不小心键入了特殊字符,以及如果你用 python,最好在字符串前加前缀u,例如 u'some string'
博主,请问一下。当前文章的页面如何获取上一篇和下一篇的url呢
思路是获取全部文章 id,获取这一篇文章 id,然后定位这一篇文章的位置,从而找到上一篇和下一篇文章的 id,再 get 获取
django.urls.exceptions.NoReverseMatch: Reverse for 'detail' with keyword arguments '{'pk': 2}' not found. 1 pattern(s) tried: ['$post/(?P<pk>[0-9]+)/$']
这个错是什么原因啊?
通常来说就是你的 url 写错了,仔细对比一下设计到 url 的地方,看看哪个字符漏了
$post/(?P<pk>[0-9]+)/$
这个写错了,正确的
^post/(?P<pk>[0-9]+)/$
"$":正则中是结束位置的标识
File "<frozen importlib._bootstrap_external>", line 674, in exec_module File "<frozen importlib._bootstrap_external>", line 781, in get_code File "<frozen importlib._bootstrap_external>", line 741, in source_to_code File "<frozen importlib._bootstrap>", line 205, in _call_with_frames_removed File "D:\blogproject\blog\models.py", line 48 def __str__(self): ^SyntaxError: invalid syntax
一加上def__str__(self):就报错,其他和老师的都一样,这是为什么啊
def __str__(self)
def 后面要加一个空格,否则报语法错误。
post-{{ post.pk }这里拼接这个class有何用意呢?看到这里还没看出来
没有意义,作为一个 hook,便于你以后可能为其写 js,css
受教了!
在这里分享一下我遇到的问题吧, Django version是 1.11.3, 遇到 NoReverseMatch , u"'blog" is not a registered namespace 的错误, 在urls.py加入app_name='blog' 可以解决
我的1.11.4,加了app_name还是不行,不清楚为什么
看看你添加的位置是否正确
最后发现是setting里的ROOT_URLCONF定义有问题,解决了
非常感谢!
请问你的ROOT_URLCONF是如何定义的?我的Django版本和你的一样,并且遇到和你一样的问题..
我的显示变成这样了,转换成功了,但是网页怎么不显示成对应的
一级标题
二级标题
三级标题
python def detail(request, pk): post = get_object_or_404(Post, pk=pk) 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})
网页中的引用方式是否正确?{{ post.toc|safe }}
博主你好,我发现我用了这段代码以后我点开首页文章标题的链接,打开的网页仍然是index模板渲染的网页,这是什么原因
在浏览器里检查一下你的超链接是否指向了文章详情页呢?
是的,浏览器里的地址是http://127.0.0.1:8000/post/2/,我的get_absolute_url定义是
def get_absolute_url(self):
return reverse('myblog:detail',args=[self.pk])
views.py里定义的detail函数是
def detail(request, pk):
post = get_object_or_404(Post, pk=pk)
post.body = markdown.markdown(post.body,extensions=['markdown.extensions.extra',
'markdown.extensions.codehilite',
'markdown.extensions.toc',])
return render(request, 'myblog/detail.html', context={'post': post})
detail.html放在templates/myblog下面 这里面有什么错误吗
已经解决了
博主,我发现我的博客详情页body部分前后各有一个
和
,像这样:这是一个测试
我的detail.html body部分代码和上面是完全一样的,这个是什么问题
使用 safe 模板标签,教程中有提到,例如:{{post.body|safe}}
请问你是如何解决的?
urls.py 利用正则判断 页面路由
使 index 的视图 优先匹配了 post/ 路径下的页面
所以 需要将 detail 视图url 放在 index 上面
2018年4月1日01点05分
windows 10 + python 3.6 + Django version 2.0.3
谢谢,不然老是无法跳转
后面 评论 模块 也有这个坑
请问能详细解释下为什么detail路由要在index路由前面吗?以前看别的案例好像都不需要强调顺序的。谢谢了
因为正则 本身的原因,至于为啥,我就不知道了。不过还是挺佩服自己能想到这的
我也佩服,,,,,昨天一直调试,完全没有错误出现,,,,,都不知道怎么修改。详情页面就是无法跳转。哈哈哈
我也遇到了这个问题,请问你是怎么解决的?
你好,我遇到的是name 'get_object_or_404' is not defined……
【编写 detail 视图函数】下有一行导入模块里加上get_object_or_404,遇到这种问题,可以ctrl+f当前网页搜索一下。
detail.html中并没有{% for post in post_list %} ,且base.html中也没有定义。他是如何获取的post呢?
detail.html只需要一个post的内容,所以是通过views.py代码中的传递PK,也就是数据库默认id进入到detail.html中,然后通过这一行选择某个PK对应的文章的。
index主页需要显示全部的post->title,所以要从列表中轮询{% for post in post_list %}。
个人理解,如果有错误请多指教。
views.detail获取网址中的pk,然后传递到函数中获得post中的对象渲染给detail.html,index.html则是渲染了post_list过去
请问楼主,我的在index.html中增加了{{ post.get_absolute_url }}但是却没有生成url的链接地址呀,但是用路径 http://127.0.0.1:8000/post/1/ 却是可以访问的这是什么原因啊?
怀疑你的 get_absolute_url 方法写错了?
<a href="{{post.get_absolute_url}}"> 是不是忘加大括号了
File "/home/jay/projects/blogproject/blog/models.py", line 5, in
from django.urls import reverse
ImportError: No module named 'django.urls'
导入django.urls出错,请问是什么原因以及怎样解决
解决了 from django.core.urlresolvers import reverse
你可能 django 版本与教程不一致。
请问博主。正则表达式我还是有些基础的,但这个'^post/(?P[0-9]+)/$'[0-9]+ ,其中?表示0或一,P这个怎样能匹配成数字呢?P是不是表示“参数pk”的意思,不是标准的表达式,是告诉django此处表示参数?谢谢
怎样跟post/255匹配上的,我还真难以理解了。
post不用说了。?P
?P 是 python 正则表达式的一个占位格式,表示其后匹配的内容将被存入键为 pk 的字典中。
博主你好,出现了这个问题:
UnicodeDecodeError at /
'utf-8' codec can't decode byte 0xca in position 1814: invalid continuation byte
Request Method: GET
Request URL: http://127.0.0.1:8000/
Django Version: 1.10.6
Exception Type: UnicodeDecodeError
Exception Value:
'utf-8' codec can't decode byte 0xca in position 1814: invalid continuation byte
Exception Location: F:\ligang\Envs\blogproject_env\lib\codecs.py in decode, line 319
rror during template rendering
In template F:\ligang\Workspace\blogproject\templates\blog\index.html, error at line 1
utf-8
1 {% extends 'base.html' %}
这种情况可能是你的模板文件中含有奇怪的编码字符或者文件本身不是 utf-8 编码,另外如果使用的 py2,有很大概率会遇到这个问题。推荐使用 py3.
我用的是py3,您说的模板文件具体是指的哪个呢?
index.html,base.html 都有可能。
博主,首页href="index.html",点击会直接在原有的地址加上index.html,改成href="/blog/index.html"这样就能返回首页了。django本身就这样,还是版本的问题?我用的django-1.11
需要把链接改成首页路由,后续教程会有相关介绍的。
reverse导入的路径不一样,,难道是django版本不一样的原因?
from django.core.urlresolvers import reverse
最新版 django 推荐从 urls 中导入 reverse,rom django.core.urlresolvers import reverse 是老式导入,django 可能在未来的某个版本移除这个导入路径。
写的一篇长博客中为什么首行不缩进,段落也不换行
TemplateDoesNotExist at /
base.html
这个是少了什么?
这可能是你的模板路径不对,或者没有在 settings.py 中设置模板根目录
楼主,{% extends 'base.html' %}路径报错,应该是{% extends 'blog/base.html' %}才行,我的环境是Windows 10+Python3.6.1 (64位) + Django 1.10.6
请对照示例项目查看模板路径和你的有什么不同。
樓主,想問代碼:return reverse('blog:detail', kwargs={'pk': self.pk}) 中的self.pk是從什麼時候傳入的?
self.pk 引用实例自身的 pk 属性,这个 pk 属性是来自 Post 的父类 models.Model
楼主问题解决了,在logproject\urls里加namespace就可以了,
url(r'', include('blog.urls', namespace='blog'))
赞
{{ post.get_absolute_url }}楼主这个方法好像不能用,报错信息时这样:
NoReverseMatch at /'blog' is not a registered namespace
然后指向这个位置
{{ post.title }}
没报错,点文章标题和继续阅读就是没反应
用的是mysql数据库
可否把相关的代码发到 pythonzh.cn ?使用 markdown 排版。博客的评论不支持粘贴代码。
感谢博主,发现是django1.8版本问题,需要在namespace设置才行,用app_name连接不过去,感谢楼主的回复!
命名空间怎么定义的namespace='block',错误的?
在 include 函数里加入 namespace 参数即可。
博主,麻烦把章的代码更新一下,把app_name = blog,换成namespace='blog'
文章中代码没错呀?
点击文章标题怎么不跳转
可能没有设置超链接
{{ post.title }}
urlpatterns = [[0-9]+)/$', views.detail, name='detail'),
url(r'^blog', include('blog.urls', namespace='blog')),
url(r'^post/(?P
]
url(r'^post/(?P[0-9]+)/$', views.detail, name='detail'), 这一条应该放在 blog.urls.py 里。你用浏览器看一下标题的 a 标签的 href 是不是文章的 url?
NoReverseMatch at /}' not found. 1 pattern(s) tried: ['post/(?P[0-9]+)/$']
Reverse for 'detail' with arguments '()' and keyword arguments '{u'pk':
WHY????
Please paste the related codes and more imformation. We can not find out it only with a exception message!
图片复制不了...
直接粘贴一下代码吧,或者加群后小窗口我。
In template D:\Django\workspace\blogproject\templates\blog\index.html, error at line 7
1 {% extends 'base.html' %}
回复
正在加载评论框...
收起
2 {% block main %}
3 {% for post in post_list %}
4
5
6
7 {{ post.title }}
8
9
10 {{ post.category.name }}</spa
没什么问题,github 上有所有相应分支的代码,你可以把你的代码和项目代码仔细对比一下,看是哪里的问题。重点对对 view 和 url 的代码。
我的问题跟你一样,请问你解决了么?
请教一下,为何一路跟着做到此处,我的出来的效果和你的不一样呢?
我在数据库中添加了2篇文章,但是在主页中看不到。
另外,“继续阅读”按钮也找不到。
但是其它没有什么问题。
是不是删了某些模板代码?仔细检查一下模板继承有没有问题。github 有每一步对应的代码,仔细对比一下哪里不同。
'utf-8' codec can't decode byte 0xcd in position 2605: invalid continuation byte这个怎么解决
很多人遇到这个问题,目前没有发现导致这个问题的原因,可能是你的文件编码问题或者含有特殊的字符导致的。也可能和操作系统有关,并非所有人遇到这个问题。
文件配置编码改成utf-8
右键文件最后一个选项 properties把GBK编码换掉
换了utf-8之后要把的中文字重新写一遍
不能使用Post.tag.name
因为 Post 和 Tag 是多对多的关系,所以要获取 Post 下的全部 tag 需使用 post .tags.all(),post.tags 将返回一个类似于 objects 的模型管理器。
嗯嗯,返回对象在循环一次就可以了,谢谢。
怎么显示每个文章的标签呢?