发布于 2016-11-06 10:45:19 | 630 次阅读 | 评论: 0 | 来源: 网络整理
2.8 完善后台的功能,在后台添加,编辑,删除数据
更改 news/admin.py
from django.contrib import admin
from .models import Column, Article
class ColumnAdmin(admin.ModelAdmin):
list_display = ('name', 'slug', 'intro',)
class ArticleAdmin(admin.ModelAdmin):
list_display = ('title', 'slug', 'author', 'pub_date', 'update_time')
admin.site.register(Column, ColumnAdmin)
admin.site.register(Article, ArticleAdmin)
创建一个超级管理员(如果你没有后台帐户和密码的话)
python manage.py createsuperuser
这里我们打开开发服务器,访问后台网址,就可以看到:
python manage.py runserver
还可以指定端口 python manage.py runserver 8002
也可以监视所有本机IP, python manage.py runserver 0.0.0.0:8001
后台首页:
后台栏目列表:
后台文章列表:
文章编辑页面:
我们已经可以在后台进行更改和保存文章了,但是在编辑新闻的时候是不是觉得不爽,没有一个编辑器,我们下面来集成百度的Ueditor 到我们的系统:
2.8.1 集成 DjangoUeditor 编辑器
安装 DjangoUeditor 包
由于这个包 1.8 有一个bug,已经被我修复了,但是原作者还没有上传到 pypi, 我们直接下载 zip,或者 git clone 下来,
原作者github 地址:https://github.com/zhangfisher/DjangoUeditor 直接下载zip (Python 2)
Python 3 开发者:https://github.com/twz915/DjangoUeditor3 直接下载zip(Python 2/3)
把里面的 DjangoUeditor-master 中的 DjangoUeditor 文件夹放到 news 同一级目录,如图所求:
在 minicms/settings.py 中加入 DjangoUeditor 这个应用
INSTALLED_APPS = (
...
'news',
'DjangoUeditor',
)
在 minicms/urls.py 中添加一行:
url(r'^ueditor/', include('DjangoUeditor.urls' )),
Django 1.8.3 urls.py 中写了,建议先引入,再使用,即:
from django.conf.urls import include, url
from django.contrib import admin
from DjangoUeditor import urls as DjangoUeditor_urls
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^ueditor/', include(DjangoUeditor_urls)),
]
但是原来的写法依旧可以使用。
这一段是后来加的,github上没有
为了让上传的图片,文件可以在本地调试的时候可以正常显示,下载,
在 minicms/settings.py 设置 static 和 media
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.8/howto/static-files/
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
# 公共的 static 文件,比如 jquery.js 可以放这里,这里面的文件夹不能包含 STATIC_ROOT
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "common_static"),
)
# upload folder
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
在 minicms/urls.py 最后加入以下代码:
# use Django server /media/ files
from django.conf import settings
if settings.DEBUG:
from django.conf.urls.static import static
urlpatterns += static(
settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
安装配置好后,修改 models.py
# 引入这个 Field,其它的不要变
from DjangoUeditor.models import UEditorField
class Article(models.Model):
...省略
#仅修改 content 字段
content = UEditorField('内容', height=300, width=1000,
default=u'', blank=True, imagePath="uploads/images/",
toolbars='besttome', filePath='uploads/files/')
...
再次打开,发现,已经可以使用了:
后台的功能就讲到这里,大家可以后期自己再进行完善。
2.9 前台内容显示
我们在后台可以看到栏目,新闻,但是让用户来看这些内容不能每人给一个后台帐号吧。
我们假设这么设计,首页显示一些栏目,每个栏目显示五篇相关的文章,栏目可以点击进去,文章也可以点击进去。
2.9.1 网址与内容如何关联
我们复习一下前面的 models.py
class Column(models.Model):
...
slug = models.CharField('栏目网址', max_length=256, db_index=True)
...
class Article(models.Model):
...
slug = models.CharField('网址', max_length=256, db_index=True)
...
前面我们都自定义了文章的网址,假设我们想访问 /column/column_slug/ 访问栏目的内容,访问 /news/article_slug/ 查看文章详情
提示:其实这里有个 bug, 不同栏目,不同文章网址可以是一样的,先不管这个,我们稍后会修复它!
我们修改 minicms/urls.py 添加上面的规则:
url(r'^$', 'news.views.index', name='index'),
url(r'^column/(?P<column_slug>[^/]+)/$', 'news.views.column_detail', name='column'),
url(r'^news/(?P<article_slug>[^/]+)/$', 'news.views.article_detail', name='article'),
url(r'^admin/', include(admin.site.urls)),
下面我们来完善这三个视图函数(这里为了告诉大家如何做,我们不用通用视图,因为通用视图都帮大家做好了,学不到什么东西)
首页 index 栏目 column 文章详情 article
# -*- coding: utf-8 -*-
from django.shortcuts import render
from django.http import HttpResponse
def index(request):
return HttpResponse(u'欢迎来 PHPERZ 学习Django')
def column_detail(request, column_slug):
return HttpResponse('column slug: ' + column_slug)
def article_detail(request, article_slug):
return HttpResponse('article slug: ' + article_slug)
上面是一个大致框架,我们马上完善它,大家看一下参数是如何传递的,可以打开开发服务器 python manage.py runserver
访问比如:http://127.0.0.1:8002/column/tech/ (注意端口,改成你自己的)会得到:
我们发现 slug 已经被正确传递到了 views.py 中的视图函数,我们在 views.py 中可以用 slug 检索出相应的栏目或文章。
至此,我们已经知道栏目网址和文章网址的规则,我们现在用代码来生成相关的网址,我们运行 python manage.py shell 进入有项目环境的终端
python manage.py shell
相当于下面两句:
python
from minicms.wsgi import *
我们知道 slug 后,就能得到相应的网址:
>>> from django.core.urlresolvers import reverse
>>>
>>> # column
>>> reverse('column', args=('tech',))
u'/column/tech/'
>>> reverse('column', args=('sports',))
u'/column/sports/'
>>>
>>> # article
>>> reverse('article', args=('article_slug',))
u'/news/article_slug/'
>>> reverse('article', args=('windows_10',))
u'/news/windows_10/'
>>>
我们修改 models.py ,将获取网址的功能写成一个函数 get_absolute_url ,然后在模板或其它脚本中调用。
后台默认也会调用这个函数,可以理解成一个约定俗成的名称。
from django.core.urlresolvers import reverse
...
class Column(models.Model):
...
slug = models.CharField('栏目网址', max_length=256, db_index=True)
...
def get_absolute_url(self):
return reverse('column', args=(self.slug,))
...
class Article(models.Model):
...
slug = models.CharField('网址', max_length=256, db_index=True)
...
def get_absolute_url(self):
return reverse('article', args=(self.slug,))
...
注意 args 参数为元组,写 args=(self.slug) 这样是错的,注意后面有一个逗号 args=(self.slug,)
我们再次进入 终端 python manage.py shell
>>> from news.models import Column, Article
>>> c = Column.objects.all()[0]
>>> c.get_absolute_url()
u'/column/sports/'
>>> a = Article.objects.all()[0]
>>> a.get_absolute_url()
u'/news/article_1/'
我们可以看到这样已经可以获取到文章或者栏目的网址了,下面我们在模板中显示它们。
2.9.2 相关模板文件
我们先写一个 base.html 所有的其它模板都继承它,由于 base.html 不属于某一个 app,它是整个项目共用的,我们建立一个专门的 模块文件夹来放它样的文件。
比如还有其它的 baidutongji.html ,把百度统计的代码放进去来统计访问情况。
我们修改 settings.py,添加一个模板目录 项目下 templates 文件夹。
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(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',
],
},
},
]
项目目录下 建一个 templates 文件夹,里面写一个 base.html
templates/base.html 模板文件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{% block title %}欢迎光临{% endblock title %} - PHPERZ </title>
{% block css %}
{% endblock css %}
{% block js %}
{% endblock js %}
</head>
<body>
{% block content %}
<h1>自强 新闻网</h1>
{% endblock content %}
{% include "baidutongji.html" %}
</body>
</html>
上面这样写是为了足够简单,喜欢 BootStrap 的同学可以用这个 base.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,Chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}欢迎光临{% endblock title %} - PHPERZ </title>
<!-- Bootstrap -->
<link href="http://apps.bdimg.com/libs/bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet">
<!-- 引入下面两个库让 IE8 支持 HTML5 元素 -->
<!-- 警告: Respond.js 通过 file:// 浏览的时候不能正常工作!-->
<!--[if lt IE 9]>
<script src="http://apps.bdimg.com/libs/html5shiv/3.7/html5shiv.min.js"></script>
<script src="http://apps.bdimg.com/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
{% block css %}
{% endblock css %}
{% block js %}
{% endblock js %}
</head>
<body>
<div>
<div>
{% block content %}
<h1>自强 新闻网</h1>
{% endblock content %}
</div>
</div>
<script src="http://apps.bdimg.com/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://apps.bdimg.com/libs/bootstrap/3.3.0/js/bootstrap.min.js"></script>
{% include "baidutongji.html" %}
</body>
</html>
templates/baidutongji.html
<!-- 这里放统计的代码 -->
<!-- 百度统计 begin-->
<div style="display:none" hidden>
<script type="text/javascript">
var _bdhmProtocol = (("https:" == document.location.protocol) ? " https://" : " http://");
document.write(unescape("%3Cscript src='" + _bdhmProtocol + "hm.baidu.com/h.js%3Fab8b04b0bf640ac196520db1cd029664' type='text/javascript'%3E%3C/script%3E"));
</script>
</div>
<!-- 百度统计 end-->
2.9.3 视图中检索结果,渲染到模板中显示出来
我们改写视图函数,查询数据库,得到相关的内容:
def column_detail(request, column_slug):
column = Column.objects.get(slug=column_slug)
return render(request, 'news/column.html', {'column': column})
def article_detail(request, article_slug):
article = Article.objects.get(slug=article_slug)
return render(request, 'news/article.html', {'article': article})
在 news 下新建 templates 文件夹,再在 templates 下新建 news 文件夹,我们来写两个模板文件:
栏目模板,视图传递过来了一个 column object
news/templates/news/column.html (或者 项目下的 templates/news/column.html 路径)Django 都能找到它们
{% extends "base.html" %}
{% block title %}
{{ column.title }}
{% endblock title %}
{% block content %}
栏目简介:{{ column.intro }}
栏目文章列表:
还需要完善
{% endblock content %}
文章模板,视图传递过来了一个 article object
news/templates/news/article.html (或者 项目下的 templates/news/article.html)
{% extends "base.html" %}
{% block title %}
{{ article.title }}
{% endblock title %}
{% block content %}
<h1>文章标题: {{ article.title }}</h1>
<div id="main">
{{ article.content }}
</div>
{% endblock content %}
我们先在首页显示所有栏目及链接:
news/views.py
def index(request):
columns = Column.objects.all()
return render(request, 'index.html', {'columns': columns})
项目下 templates/index.html
{% extends "base.html" %}
{% block title %} 首页 {% endblock title %}
{% block content %}
<ul>
{% for column in columns %}
<li>
<a href="{{ column.get_absolute_url }}"> {{ column.name }} </a>
</li>
{% endfor %}
</ul>
{% endblock content %}
我们打开开发服务器(开发服务器可以一直开着,会自动刷新),查看首页:
首页已经可以显示所有栏目了,但是栏目页我们还没有完善,如果获取栏目相关的文章呢?
我们再次在终端测试,安装 bpython,会提示相关的属性和方法
python manage.py shell
下面是测试结果:
>>> from news.models import Column
>>> c = Column.objects.all()[0]
>>> c
<Column: 体育新闻>
>>> c.article_set.all()
[<Article: 体育新闻_1>, <Article: 体育新闻_2>, <Article: 体育新闻_3>, <Article: 体育
新闻_4>, <Article: 体育新闻_5>, <Article: 体育新闻_6>, <Article: 体育新闻_7>, <Artic
le: 体育新闻_8>, <Article: 体育新闻_9>, <Article: 体育新闻_10>]
我们发现用 column.article_set.all() 方法可以获取栏目相关的文章。
我们改一下 news/templates/news/column.html
{% extends "base.html" %}
{% block title %}
{{ column.title }}
{% endblock title %}
{% block content %}
<p>栏目名称:{{ column.name }}</p>
栏目简介:{{ column.intro }}
栏目文章列表:
<ul>
{% for article in column.article_set.all %}
<li>
<a href="{{ article.get_absolute_url }}">{{ article.title }}</a>
</li>
{% endfor %}
</ul>
{% endblock content %}
我们再次访问开发服务器,会发现,栏目已经可以显示相关的文章了:
但是由于我们前期写的时候的一个 bug,多篇文章可以共用一个网址,所以每个文章的 slug 都有三个与之对应的文章,【临时办法】如果想要看到文章的内容页,我们改一下视图函数,有多个时,显示第一篇(这样做有问题,后面完善)
def article_detail(request, article_slug):
article = Article.objects.filter(slug=article_slug)[0]
return render(request, 'news/article.html', {'article': article})
我们再点击文章的名称,就可以看到:
今天就写到这里,我们明天再修复这个 bug,有能力的同学可以自己想想办法修复这样问题。