I am building a project in Django CMS using version 4.1.2. Part of the project will be a news-section, for which I defined a Django model like this:
# news/models.py
from django.db import models
from django.utils import timezone
from djangocms_text_ckeditor.fields import HTMLField
class Post(models.Model):
title = models.CharField(max_length=200, verbose_name="Title")
text = HTMLField(verbose_name="Text")
user = models.ForeignKey('auth.User', on_delete=models.CASCADE, verbose_name="Author", blank=True, null=True)
date = models.DateTimeField(default=timezone.now, verbose_name="Date")
class Meta:
verbose_name = "Post"
verbose_name_plural = "Posts"
def __str__(self):
return self.title
I want this model to be a django model instead of handling it with CMS-Plugins, so that editors can manage Posts using the admin-interface and to make it easier to use things like pagination. I have a little experience with Django, but not really with Django CMS.
However, on the page displaying the news-section, I also want to have a header, a sidebar and a footer that should be editable using the CMS-Toolbar. Therefore I made an Apphook - from what I understand this should allow me to integrate the news-page with Django CMS. This is what my Apphook looks like:
# news/cms_apps.py
from cms.app_base import CMSApp
from cms.apphook_pool import apphook_pool
from django.urls import path
from django.utils.translation import gettext_lazy as _
from news import views
@apphook_pool.register
class NewsApp(CMSApp):
app_name = "news_app"
name = _("News Application")
def get_urls(self, page=None, language=None, **kwargs):
return [
path("news/", views.news_view, name="news"),
]
The view that should be called by this Apphook looks like this:
# news/views.py
from django.shortcuts import render
from .models import Post
def news_view(request):
posts = Post.objects.all().order_by('-date')
print("Number of posts:", posts.count())
context = {
'posts': posts,
}
return render(request, 'news.html', context)
A minimal example of the template news.html
looks like this:
{% extends "base.html" %}
{% load cms_tags sekizai_tags %}
{% load djangocms_alias_tags %}
{% block title %}News{% endblock %}
{% block header %}
{% placeholder "header_placeholder" %}
{% endblock %}
{% block content %}
<h1>News</h1>
{% for post in posts %}
{{ post.title }}
{% endfor %}
<p>End of news</p>
{% endblock %}
In the admin panel I created a page called "News" with the slug news/
. In the advanced settings of that page, I selected the Apphook. As a template for that page, I selected news.html
, which is also declared in settings.py
:
# settings.py
CMS_TEMPLATES = [
('home.html', 'Content Template'),
('news.html', 'Newspage Template'),
]
With this whole setup I expected the view to pass the post-data to the template, which then renders it - in case of the minimal example between <h1>News</h1>
and <p>End of news</p>
. However, it doesn't. Nothing is being rendered between those tags, and it seems like there is no data at all being passed to the template, since I also don't see the print
-results from the view.
Changing the get_urls()
-method in the Apphook to this leads to the template being rendered as expected, but without being editable by CMS:
def get_urls(self, page=None, language=None, **kwargs):
return [
path("", views.news_view, name="news"),
]
Can someone maybe point me in the right direction to solve this? I don't really understand what is happening here, and I couldn't find anything on this in the documentation so far... Thank you!
The placeholder
template tag only works on django CMS pages.
What you probably want is a common header for all news items. You might want to look at the djangocms-alias package, it allows to define reusable content.
Replace the placeholder
template tag by a static_alias
:
{% load djangocms_alias_tags %}
...
{% block header %}
{% static_alias "header_placeholder" %}
{% endblock %}
...
You can edit and version the aliases independently of your news articles. Also for pages in different languages.