Skip to content

Commit

Permalink
Document how to create a Blog
Browse files Browse the repository at this point in the history
  • Loading branch information
batiste committed Dec 14, 2020
1 parent a4ed699 commit b846a5c
Show file tree
Hide file tree
Showing 2 changed files with 235 additions and 0 deletions.
234 changes: 234 additions & 0 deletions doc/create-blog-application.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
================================
How to create a Blog application
================================

A Blog is made of dated Blog Posts. It so happens this CMS pages model
contain a creation date and is flexible enough to contain all sort contents that could
be useful in a Blog post.
So how can we use this CMS to create a Blog application? This guide gives a step
by step recipe that demonstrate how easily you can build new features on
top of this CMS.

Step 1: Create a new Django app within your project
------------------------------------------------------

.. code-block:: bash
python manage.py startapp blog
Step 2: Create the views
---------------------------

Open you newly created `blog/views.py` file and create 2 views. One for the
category view and another for the Blog's index.
We are using the `taggit` to handle the categories, this way a Blog can be in
several categories.

.. code-block:: python
from django.shortcuts import render
from pages.models import Page
from taggit.models import Tag
from django.core.paginator import Paginator
def category_view(request, *args, **kwargs):
context = dict(kwargs)
category = Tag.objects.get(id=kwargs['tag_id'])
page = context['current_page']
blogs = page.get_children_for_frontend().filter(tags__name__in=[category.name])
paginator = Paginator(blogs, 8)
page_index = request.GET.get('page')
blogs = paginator.get_page(page_index)
context['blogs'] = blogs
context['category'] = category.name
return render(request, 'blog-home.html', context)
def blog_index(request, *args, **kwargs):
context = dict(kwargs)
page = context['current_page']
blogs = page.get_children_for_frontend()
paginator = Paginator(blogs, 7)
page = request.GET.get('page')
blogs = paginator.get_page(page)
context['blogs'] = blogs
context['template_name'] = 'blog-home.html'
return render(request, 'blog-home.html', context)
Step 2: Link the views with the CMS
------------------------------------

Populate `blog/urls.py` with those urls

.. code-block:: python
from django.conf.urls import url
from blog import views
from django.urls import include, path, re_path
urlpatterns = [
url(r'^category/(?P<tag_id>[0-9]+)$', views.category_view, name='blog_category_view'),
url(r'^$', views.blog_index, name='blog_index')
]
Then the last step is to register this URL module with the CMS. Place this
code at the top of you project `urls.py` file.

.. code-block:: python
from pages.urlconf_registry import register_urlconf
register_urlconf('blog', 'blog.urls', label='Blog index')
Step 3: Create the blog templates
------------------------------------

You will need create 3 templates for your blog application. The first one is a helper template called `blog-card.html`.
It contains a basic representation of a blog as a card:

.. code-block:: html+django

{% load pages_tags static i18n humanize thumbnail %}
<div class="card mb-4 shadow-sm">
<a class="blog-lead-image" href="{% show_absolute_url page %}">
{% get_content page "lead-image" as image %}
{% if image %}
{% thumbnail image "320x240" crop="center" as img %}
<img src="{{ img.url }}">
{% endthumbnail %}
{% else %}
<!-- no image for this post -->
{% endif %}
</a>
<div class="card-body">
<a href="{% show_absolute_url page %}">
<h3 class="my-0 font-weight-normal">{% show_content page "title" %}</h3>
</a>
<p>{% show_content page "lead" %}</p>
{% if forloop.first %}
{% get_content page "content" as content %}
<p class="d-none d-lg-block">{{ content | striptags | safe | truncatechars:220 }}</p>
{% endif %}
<p class="blog-meta">Published {{ page.creation_date | naturalday }}
{% if page.tags.count %}
in the categories:
{% for tag in page.tags.all %}
<a href="/{{ lang }}/blog/category/{{ tag.id }}">{{ tag.name }}</a>{% if not forloop.last %},{% endif %}
{% endfor %}
{% endif %}
by {{ page.author.first_name }} {{ page.author.last_name }}
</p>
</div>
</div>

The second is the `blog-home.html` referenced by the views you previoulsy wrote, it will be used by the index and
the categories:

.. code-block:: html+django

{% extends 'index.html' %}
{% load pages_tags static i18n humanize thumbnail %}

{% block header %}
<div class="px-3 py-3 pt-md-5 pb-md-4 mx-auto text-center">
<h1 class="display-4">{% placeholder "title" %} {{ category }}</h1>
<p class="lead">{% placeholder "lead" with Textarea %}</p>
</div>
{% endblock %}

{% block content %}
<div class="card-deck mb-3 text-center blog-home">
{% for page in blogs %}
{% include "blog-card.html" %}
{% endfor %}
</div>

<div class="pagination">
<span class="step-links">
{% if blogs.has_previous %}
<a href="?page=1" class="btn btn-light">&laquo; first</a>
<a href="?page={{ blogs.previous_page_number }}" class="btn btn-light">previous</a>
{% endif %}

<span class="current">
Page {{ blogs.number }} of {{ blogs.paginator.num_pages }}.
</span>

{% if blogs.has_next %}
<a href="?page={{ blogs.next_page_number }}" class="btn btn-light">next</a>
<a href="?page={{ blogs.paginator.num_pages }}" class="btn btn-light">last &raquo;</a>
{% endif %}
</span>
</div>
{% endblock %}

Finaly the last one is for the Blog Post itself. You could have different Blog Post templates
but for now we only need one:

.. code-block:: html+django

{% extends 'index.html' %}
{% load pages_tags static i18n humanize %}

{% block header %}
<div class="px-3 py-3 pt-md-5 pb-md-4 mx-auto text-center blog-post">
<h1 class="display-4">{% placeholder "title" %}</h1>
<p class="lead">{% placeholder "lead" with Textarea %}</p>
<p class="blog-meta">Published {{ current_page.creation_date | naturalday }}
{% if current_page.tags.count %}
in the categories:
{% for tag in current_page.tags.all %}
<a href="/{{ lang }}/blog/category/{{ tag.id }}">{{ tag.name }}</a>{% if not forloop.last %},{% endif %}
{% endfor %}
{% endif %}
by {{ current_page.author.first_name }} {{ current_page.author.last_name }}
</p>
</div>
{% endblock %}

{% block content %}
<div class="blog-post">
<div class="blog-lead-image">
{% imageplaceholder 'lead-image' block %}
{% if content %}
<img src="{{ MEDIA_URL }}{{ content }}" alt="">
{% endif %}
{% endplaceholder %}
</div>

<div>
{% placeholder "content" with RichTextarea %}
</div>
</div>
{% endblock %}

To finish thigs up you need to allow those templates to be selected
by the CMS, add them to your `PAGE_TEMPLATES` settings:

.. code-block:: python
PAGE_TEMPLATES = (
('index.html', 'Default template'),
('blog-post.html', 'Blog post'),
('blog-home.html', 'Blog home'),
)
Step 4: Activate the Blog in the admin
------------------------------------------

You can now activate the Blog in the CMS admin. To do so follow those few steps:

1. Create a new page named "Blog", chose the template "Blog Home", and the option "Delegate to application: Blog Index".
2. Add a couple of child pages to this Blog Index page and chose the "Blog Post" template as their template.

The result should be a functional blog with an index page, category pages, tagging and pagination.

You are also free to create serveral Blog instances withing the CMS by repeating a version of this step. There is no restrictions.

`A fully functionnal version of this Blog application is available <https://github.com/batiste/django-page-cms/tree/master/example>`_
1 change: 1 addition & 0 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ Table of content
edit-content.rst
navigation-template-tags.rst

create-blog-application
3rd-party-apps.rst
commands.rst

Expand Down

0 comments on commit b846a5c

Please sign in to comment.