https://github.com/AnthonyBRoberts/fcclincoln/blob/master/apps/story/views.py
我有点不好意思承认这是我的。但它是。
class FrontpageView(DetailView):
template_name = "welcome_content.html"
def get_object(self):
return get_object_or_404(Article, slug="front-page")
def get_context_data(self, **kwargs):
context = super(FrontpageView, self).get_context_data(**kwargs)
context['slug'] = "front-page"
events = Article.objects.filter(slug="events")
context['events'] = events
return context
所以这是Django中一个非常普通的基于类的细节视图。
它正在分配模板,获取Article对象,并向context_data添加一些内容。
然后我复制了这个课17次。每次都有一个不同的模板,一个不同的slug,以及添加到context_data的不同内容。
我们的想法是,管理员可以使用WYSIWYG编辑器来更改Web内容,还有一个用户身份验证系统,允许多人访问网站内容。基本上,一个超级简单的CMS,所以没有人必须编辑html来更新网站。
但我真的希望我可以重构这个,所以我没有这几乎相同的18个班级。关于我应该从哪里开始的任何建议都是最受欢迎的。
答案 0 :(得分:6)
将所有类压缩到一个继承自TemplateResponseMixin
的类,如DetailView
所做的那样(也请查看SingleObjectTemplateResponseMixin
)并覆盖其get_template_names()
方法返回适合当前情况的模板。
正在使用的一个很好的例子是django-blog-zinnia项目
def get_template_names(self):
"""
Return a list of template names to be used for the view.
"""
model_type = self.get_model_type()
model_name = self.get_model_name()
templates = [
'zinnia/%s/%s/entry_list.html' % (model_type, model_name),
'zinnia/%s/%s_entry_list.html' % (model_type, model_name),
'zinnia/%s/entry_list.html' % model_type,
'zinnia/entry_list.html']
if self.template_name is not None:
templates.insert(0, self.template_name)
return templates
Django将获取该名称列表并尝试每个项目以查看它是否存在于templates文件夹中。如果是,则使用该模板。
仔细查看您的代码后,可能是这样的:
# convert each url
url(r'^$', FrontpageView.as_view()),
url(r'^history/$', HistoryView.as_view()),
url(r'^calendar/$', CalendarView.as_view()),
url(r'^news/$', NewsView.as_view()),
url(r'^visitors/$', VisitorsView.as_view()),
...
# to just
url(r'^(?P<slug>[\w\d/-]+)/$', SuperSpecialAwesomeView.as_view()),
# but, put this at the end of urls list after any routes that don't use this view
DetailView
,在设置了类属性model
后,将检查是否{ur}的kwargs中有slug
,如果是,则会使用slug进行模型查找就像你刚才所做的那样:Article.ojects.get(slug=self.kwargs['slug'])
您可以在type
模型中添加Article
字段。该类型将指定它是什么类型的文章。例如,您的ChildrenView
,YouthView
和AdultView
都可以使用music
类型(因为模板都是音乐,我假设它们是相关的)。
ARTICLE_TYPE_CHOICES = (
(0, 'music'),
(1, 'weddings'),
(2, 'outreach'),
...
)
class Article(models.Model):
...
type = models.IntegerField(choices=ARTICLE_TYPE_CHOICES)
...
class SuperSpecialAwesomeView(DetailView):
template_name = None
model = Article
def get_template_names(self):
slug = self.kwargs.get('slug', '')
templates = [
# create a template based on just the slug
'{0}.html'.format(slug),
# create a template based on the model's type
'{0}.html'.format(self.object.get_type_display()),
]
# Allow for template_name overrides in subclasses
if self.template_name is not None:
templates.insert(0, self.template_name)
return templates
鉴于文章实例的类型为music
且slug为ministry/children
,Django将查找名为ministry/children.html
的模板和名为music.html
的模板。
如果您需要为其他视图做一些特殊的事情(就像SermonsView
可能需要的那样),那么子类SuperSpecialAwesomeView
class SermonsView(SuperSpecialAwesomeView):
paginate_by = 2
queryset = Article.objects.order_by('-publish_date')
答案 1 :(得分:1)
我会想到一个快速的方法: 在模型中添加模板字段,其中包含预定义模板选项列表(可以动态创建)。 覆盖默认的DetailView方法,覆盖get_template_names方法,为视图分配正确的模板(如果没有可用的回退,可以通过try:except :)完成。 除此之外,您可以使用任何类型的模型标志更改View行为。 这样,您可以为模型创建单个入口点,而不是在整个位置定义可重复的视图。 我倾向于保持FrontPageView独立于其他视图,因为它很容易,因为它有不同的用途。 如果需要可重复的上下文条目,请考虑上下文处理器,如果需要针对特定视图的可重复上下文条目,请考虑使用Mixins。
答案 2 :(得分:0)
我很少能找到一个需要使用CBD的地方。
你可以像这样重构:
def editable_page(slug):
return {
'context': {
'slug': slug
}
'template': 'mysupertemplates/{0}.html'.format(slug)
}
def frontpage(req):
return editable_page('frontpage')
def chat(req):
return editable_page('char')
def about(req):
return editable_page('about')