我的网站搭建(第50天) 添加专题

  • 发布时间:2017年4月3日 16:36
  • 作者:杨仕航
* 该文是基于Python2.7开发的,最新Python3.x和Django2.x视频教程可以前往 >> Django2.0视频教程

一直以来,我都想加个“专题”的模块。可以从我写的文章看出规律:每段时间写的内容都具有一定的关联。

专题模块可以将我网站中相关性较强而且具有一定的流程逻辑的博客和教程放到一起。这样可以提高我网站博客和教程的曝光率和关联性。让零散的文章或知识变成一个有机的整体。


该功能对于Django来说,创建一个新的app。(我创建了一个名为subject的应用)

python manage.py startapp subject

该app的模型应当如何创建?要先做好数据库搭建的规划。

例如,1个专题要有标题、预览图片、描述等等内容。

还有,专题的内容是一个章节结构(2级的树结构)。专题下分章节,章节下分明细。如我成果:

20170403/20170403154620481.png

而且,我希望可以显示阅读数。

这个简单加个装饰器即可,前面有开发过相关应用:我的网站搭建(第24天) 阅读计数优化

另外,最好可以评论,增加与访客互动。评论功能我还是使用django-comments库。

不过,前面为了评论或回复发送邮件。被我修改只支持博客应用发送邮件,所以这个还需调整修改代码。


1、创建模型

打开subject专题应用目录中的models.py文件,先添加一些辅助模型。

由于设置到的内容不同,加个分类模型:

#coding:utf-8
from django.db import models

class SubjectType(models.Model):
    '''subject type'''
    type_name = models.CharField(max_length=20)
    create_time = models.DateTimeField(auto_now_add=True)

    def __unicode__(self):
        return '%s' % (self.type_name)


另外,一个专题的文章可能还没写完,我就先发布了专题。为了避免误解,可以给该专题标记更新状态。例如:连载中、已完结。模型如下:

class SubjectStaticType(models.Model):
    '''subject static type'''
    type_name = models.CharField(max_length = 12)
    create_time = models.DateTimeField(auto_now_add=True)

    def __unicode__(self):
        return self.type_name


专题相关辅助模型添加完毕,加入专题的模型:

from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.auth.models import User
import django_comments

class Subject(models.Model):
    '''subject model'''
    caption = models.CharField(max_length=20)
    description = models.TextField()

    author = models.ForeignKey(User, default=1)
    img = models.FileField(upload_to='static/media/subject')
    static = models.ForeignKey(SubjectStaticType, default=1)
    subject_type = models.ForeignKey(SubjectType, default=1)

    create_time = models.DateTimeField(auto_now_add=True)
    update_time = models.DateTimeField(auto_now=True)

    def __unicode__(self):
        return '%s' % self.caption

    #获取评论和回复数
    def get_comment_count(self):
        obj_type = ContentType.objects.get_for_model(self)
        comment_model = django_comments.get_model()
        comments = comment_model.objects.filter(content_type=obj_type, object_pk=self.id)
        return comments.count()

这里要说明一下,给模型添加get_comment_count方法是为了获取评论和回复的总数。

还有,这里加了author字段是为了和博客模型(博客模型也有该字段)对应,为了发送邮件可以取得邮箱。


专题模型添加完毕,再加入专题内容相关的模型。首先是章节,此处需要外键和专题关联:

class SubjectChapter(models.Model):
    '''subject chapter'''
    title = models.CharField(max_length=20)
    subject = models.ForeignKey(Subject)
    create_time = models.DateTimeField(auto_now_add=True)

    def __unicode__(self):
        return u'<%s-%s>' % (self.title, self.subject)


章节添加完毕,再加入明细模型。明细模型我修改了很多次。

本来打算该模型包含标题和链接。在前端生成明显列表时,可以直接获取得到标题和链接。但后来测试URLField类型字段无法使用相对路径的链接而且考虑到对应的博客或教程的标题可能随时更改,所以就作罢了。模型如下:

class SubjectItem(models.Model):
    '''subject item'''
    chapter = models.ForeignKey(SubjectChapter, default=1)

    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey(
        ct_field = "content_type",
        fk_field = "object_id"
    )

    create_time = models.DateTimeField(auto_now_add=True)
    update_time = models.DateTimeField(auto_now=True)

    def __unicode__(self):
        return 'subject item %s' % self.id

该模型使用到ContentType,可以关联任何对象。(这个我在前面写阅读计数优化也使用到)

这么处理还有一个好处:我可以在博客具体的文章中显示“相关专题”,提高内容的关联性。

模型创建完毕之后,就在settings.py加入该应用并更新数据库。


2、用inlines简化admin中的操作

上面创建模型中有个对应关系:1个专题下对应多个章节,1个章节下对应多个明细。

若在admin后台管理界面显示并编辑很不方便。若有对应关系的模型可以放到一起编辑的话,就大大简化操作。

这个可以使用inlines。如下设置admin.py文件:

#coding:utf-8
from django.contrib import admin
from models import SubjectType, SubjectStaticType, Subject, SubjectChapter, SubjectItem

#辅助部分
@admin.register(SubjectType)
class SubjectTypeAdmin(admin.ModelAdmin):
    list_display=('id', 'type_name', 'create_time')

@admin.register(SubjectStaticType)
class SubjectStaticTypeAdmin(admin.ModelAdmin):
    list_display=('id', 'type_name', 'create_time')

#Subject部分
class SubjectChapterInline(admin.TabularInline):
    model = SubjectChapter
    extra = 3

@admin.register(Subject)
class SubjectAdmin(admin.ModelAdmin):
    list_display=('caption', 'description', 'subject_type', 'static', 'create_time', 'update_time')
    inlines = [SubjectChapterInline,]

#Subject章节
class SubjectItemInline(admin.TabularInline):
    model = SubjectItem
    extra = 3

@admin.register(SubjectChapter)
class SubjectChapterAdmin(admin.ModelAdmin):
    list_display=('subject', 'title', 'create_time')
    inlines = [SubjectItemInline,]

在注册admin的模型设置inlines,该设置内容是一个列表。列表中的元素是继承了TabularInline的类。

该类通常设置model(对应的模型)和extra(默认显示添加的个数)即可。

效果如下:

20170403/20170403161720525.png


3、输出页面

模型和后台管理有了,我们可以创建添加专题。

创建专题之后需要显示输出到页面。这个需要设置模版和写views.py文件的响应方法以及设置url路由即可。

首先,输出一个专题列表的页面,显示全部专题。由于专题的个数远远要小于博客的篇数。所以无需开发和博客页面那么复杂,先简单全部显示即可,代码如下:

#coding:utf-8
from django.shortcuts import render_to_response
from models import SubjectType, SubjectStaticType, Subject, SubjectChapter, SubjectItem

def subject_list(request):
    subjects = Subject.objects.all()

    data = {}
    data['subjects'] = subjects
    return render_to_response('subject/subject_list.html', data)

至于页面的css样式,自行根据喜好写代码即可。我目前写的效果如下:

20170403/20170403162451641.png


显示1个专题具体内容,除了显示原本的内容之外,还需要对阅读次数计数以及添加评论功能。

我的网站搭建(第24天) 阅读计数优化中,我已经将阅读计数写成一个应用,使用的时候直接加个装饰器即可。

但,这里还涉及到对明细中的ContentType类型的处理。我可以给这个专题添加的是博客,也可能添加的是教程。

不同应用,需要返回的链接不同。目前我用if判断类型处理,代码如下:

#coding:utf-8
from django.shortcuts import render_to_response
from django.http import Http404
from django.core.urlresolvers import reverse #url逆向解析
from django.template import RequestContext

from models import SubjectType, SubjectStaticType, Subject, SubjectChapter, SubjectItem
from apps_project.view_record.decorator import record_view #阅读计数

@record_view(Subject)
def subject_show(request, id):
    try:
        subject = Subject.objects.get(id=id)
        chapters = []

        #数据统计
        blog_num = 0
        tutorial_num = 0

        #遍历章节
        for i, chapter in enumerate(subject.subjectchapter_set.all()):
            #遍历子项
            items = []
            for item in chapter.subjectitem_set.all():
                obj = item.content_type.get_object_for_this_type(id=item.object_id)
                obj_type = item.content_type.model

                #根据类型不同,设置名称和链接(动态绑定属性)
                if obj_type == 'blog':
                    item.type_name = '博客'
                    item.url = reverse('detailblog', args = [item.object_id,])
                    item.title = obj.caption
                    blog_num += 1
                elif obj_type == 'tutorial':
                    item.type_name = '教程'
                    item.url = reverse('tutorial_detail', args = [item.object_id,])
                    item.title = obj.caption
                    tutorial_num += 1
                else:
                    item.type_name = '未知'
                    item.url = '/'
                    item.title = '<未知的类型>'
                items.append(item)

            chapter.items = items
            chapter.sort_num = i + 1
            chapters.append(chapter)  

    except Subject.DoesNotExist:
        raise Http404

    data = {}
    data['subject'] = subject
    data['chapters'] = chapters
    data['count'] = u'该专题分%s章节,共%s篇博客、%s个教程' % (len(chapters), blog_num, tutorial_num)
    return render_to_response('subject/subject_show.html', data, context_instance=RequestContext(request))


模版部分这里就不说了,毕竟模版可以从views.py可以得到需要的数据,返回前端即可。

再加上阅读计数和评论部分即可。接下来添加更多专题以及首页加入相关专题内容。

评论部分发送邮件修改涉及不少内容,我放到下篇博文给大家讲解。

上一篇:我的网站搭建(第51天) 解除评论发送邮件限制

下一篇:Python爬虫入门 (看这篇就够了)

评论列表

智慧如你,不想发表一下意见吗?

新的评论

清空