[轉] http://www.codingsoho.com/zh/blog/djangocms-plugin-integrate-serail-app/
前言
前面已經介紹了如何使用djangoCMS來搭建一個博客系統,具體效果可參考www.codingsoho.com, 但是最近使用的時候碰到一個問題就是如果某個專題的文章很多的話,僅僅靠分類功能並不能滿足,所以打算來加一個簡單的專題功能。
創建專題功能應用
首先跟普通的工程一樣我們先實現一個專題應用,然后下一步再把它集成到djangoCMS中去。
創建應用
創建應用serials
python manage.py startapp serials
創建module
創建module文件,我們需要兩個model: serial和entry
serial代表專題連載,entry是專題里的各篇文章,這個文章對應於我們要呈現的blog,當然也包含了一些其他用於專題顯示的字段。具體內容如下
class Serial(models.Model):
title = models.CharField(_('title'), max_length=150, blank=False, null=False)
abstract = models.TextField(_('abstract'), max_length=500, blank=True, null=True)
image = models.ImageField(_('image'), upload_to="upload/serial/", blank=True, null=True)
order = models.IntegerField(_("order"), blank=True, null=True, default=-1)
active = models.BooleanField(_("active"), default=False)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
updated = models.DateTimeField(auto_now_add=False, auto_now=True)
def __unicode__(self):
return self.title
def get_absolute_url(self):
return reverse("serial_detail", kwargs={"pk":self.pk})
class Meta:
verbose_name = _("Serial")
verbose_name_plural = _("Serial")
ordering = ['order', '-updated']
簡單介紹一下這幾個字段
- title – 專題的標題
- abstract – 專題摘要, 這是對專題的一些概況性描述
- image – 跟專題相關的圖片,用於顯示
- order – 用於排序
- active – 控制是否顯示,前端只顯示處於激活狀態下的連載內容
- timestamp – 創建時間,該字段默認更新
- updated – 更新時間,該字段自動賦值
Meta里的ordering設置為['order', '-updated'],這樣就能按照我們指定的順序顯示
class Entry(models.Model):
serial = models.ForeignKey(Serial, verbose_name = _("serial"), blank=False, null=False)
title = models.CharField(_('title'), max_length=150, blank=False, null=False)
url = models.URLField(_('url'), max_length=100, blank=False, null=False)
image = models.ImageField(_('image'), upload_to="upload/serial/", blank=True, null=True)
order = models.IntegerField(_("order"), blank=True, null=True, default=-1)
active = models.BooleanField(_("active"), default=False)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
updated = models.DateTimeField(auto_now_add=False, auto_now=True)
entry model里,對url這個字段簡單介紹一下,這個就是對應的博客的鏈接,不是相對路徑。這個跟評論的關聯有點類似,當然將來這種專題可以擴展到不僅僅針對博客,也可以針對視頻或者其他內容
執行makemigrations和migrate生成數據表
實現專題列表視圖
我們需要實現兩個視圖,顯示所有專題的視圖以及訪問某個專題時的對應顯示。Django強大的class-based-view模塊提供了實現該功能的基本方法
首先列表視圖,導入django.views.generic.list里的ListView,這兒我只寫了一個最簡單的實現,指定queryset和模板名字。
在queryset里,針對對象做了過濾,只提取了active的對象,便於后面對內容發布進行控制。
模板存放位置在template_name里指定,如果你用系統指定的路徑和名字,該變量可以不賦值。
from .models import *
from django.views.generic.list import ListView
class SerialListView(ListView):
queryset = Serial.objects.filter(active=True)
template_name = "serials_list.html"
添加文件template/serias_list.html
{% extends "serials_base.html" %}
{% load i18n %}
{% block content %}
{% for obj in object_list %}
{% include "serial_list_content.html" with object=obj show_entry_list=False %}
<div class="row" style="padding-top: 20px;">
<div class="col-sm-12">
<div class="text-center"><a href="{{obj.get_absolute_url}}" class="btn btn-primary btn-lg">{% trans "View Serial" %}</a></div>
</div>
</div>
<br>
<br>
{% if not forloop.last %}
<hr>
{% endif %}
{% endfor %}
{% endblock %}
內容顯示放在了模板文件serial_list_content.html里,因為后面顯示詳情了還會用到
<div class="row">
<div class="col-sm-6 push-sm-6">
<img src="{{object.image.url}}" class="img-fluid">
</div>
<div class="col-sm-6 pull-sm-6">
<h1 class="serial-headline">
<a href="{{object.get_absolute_url}}"><small><b>{{object.title}}</b></small></a>
</h1>
<p class="lead">
{{object.abstract}}
</p>
</div>
</div>
給這個視圖添加URL
創建serials/urls.py
from .views import (
SerialListView,
)
urlpatterns = [
url(r'^$', SerialListView.as_view(), name='serial_list'),
]
更新項目urls.py
urlpatterns += i18n_patterns(
url(r'^course/', include('serials.urls')),
url(r'^', include('cms.urls')),
)
注意:把course對應的URL一定要放在cms.url前面,否則cms會處理所有前面沒處理的模式pattern。
添加專題內容
內容添加在后台完成,添加下面的代碼來支持serial和entry的添加。
from .models import Serial, Entry
class EntryInline(admin.TabularInline):
model = Entry
extra = 1
max_num = 50
class SerialAdmin(admin.ModelAdmin):
inlines = [
EntryInline,
]
class EntryAdmin(admin.ModelAdmin):
pass
admin.site.register(Serial, SerialAdmin)
admin.site.register(Entry, EntryAdmin)
在admin添加對應的serial和entry。
這個時訪問http://127.0.0.1:8000/zh/course/,就可以看到如下的效果
實現專題詳情視圖
上面列出了所有的專題內容,點開某個專題時應該會列出該專題所有的博客文章,接下來我們來實現它
在views.py添加
from django.views.generic.detail import DetailView
class SerialDetailView(DetailView):
queryset = Serial.objects.all()
template_name = "serials_detail.html"
def get_context_data(self, *args, **kwargs):
context = super(SerialDetailView, self).get_context_data(*args, **kwargs)
context["object_list"] = Entry.objects.filter(serial__pk=self.get_object().pk, active=True)
return context
實現模板serials_detail.html,
{% extends "serials_base.html" %}
{% block content %}
{% include "serial_list_content.html" with show_entry_list=True %}
{% endblock %}
詳情視圖里我們繼續包含serial_list_content的內容,這部分和列表頁是一樣的,另外,我們還要添加entries列表,代碼如下
{% if show_entry_list %}
<br>
<div class="row">
<div class="col-sm-10">
<!-- <h2>{{obj}}</h2> -->
<div class="clearfix"></div>
</div>
<div class="col-sm-2">
</div>
</div>
<div class="list-group">
{% for item in object.entry_set.all %}
<a class="list-group-item justify-content-between {% if forloop.first %}first-lecture{% endif %} " href="{{item.url}}">
<h3 class="mb-1">{{item.title}}</h3>
</a>
{% endfor %}
</div>
{% endif %}
添加對應的URL
from .views import (
SerialDetailView,
)
urlpatterns = [
url(r'^(?P<pk>\d+)', SerialDetailView.as_view(), name='serial_detail'),
]
訪問http://127.0.0.1:8000/zh/course/1,效果如下
CMS插件集成應用
接下來進入到本文的重點,如何將上面的應用集成到djangoCMS里。
我是參考下面教程完成的
- http://docs.django-cms.org/en/latest/introduction/plugins.html#plugins
- tutorial
-http://docs.django-cms.org/en/latest/introduction/integrating_applications.html
教程里額外建了個應用來處理插件,為了簡化,我還是在原來的應用里完成了插件實現。
Plugin Model
在models.py里添加下面代碼
from django.db import models
from cms.models import CMSPlugin
from serials.models import Serial
class SerialPluginModel(CMSPlugin):
serial = models.ForeignKey(Serial)
def __unicode__(self):
return self.serial.title
注意:CMS plugin都是從CMSPlugin繼承來的,不是從models.Model
Plugin Class
在models.py同級目錄創建文件cms_plugin.py,這個plugin類負責向CMS提供相應的信息來渲染你的plugin
代碼實現如下
from cms.plugin_base import CMSPluginBase
from cms.plugin_pool import plugin_pool
from .models import SerialPluginModel
from django.utils.translation import ugettext as _
@plugin_pool.register_plugin # register the plugin
class SerialPluginPublisher(CMSPluginBase):
model = SerialPluginModel # model where plugin data are saved
module = _("serials")
name = _("Serial Plugin") # name of the plugin in the interface
render_template = "plugin/serial_plugin.html"
def render(self, context, instance, placeholder):
context.update({'instance': instance})
return context
注意:plugin類必須從CMSPluginBase繼承,並且在plugin_pool注冊
模板
需要在plugin類里對屬性render_template進行賦值,plugin將用這個模板渲染
內容如下
{% include "serial_list_content.html" with show_entry_list=True object=instance.serial %}
這個就是前面我們前面詳情視圖的內容,只保留了內容部分。
集成應用
至此,該應用到CMS的集成已完成。如果你用額外的應用來實現plugin的話,還需要將它添加到settings.py里。
再次添加插件時,可以看到serial已經在其中了。
點擊Serial Plugin,可以在下面頁面中選到我們前面添加的專題內容。
最終呈現效果