Hellodjango Article 12: Unlock blog sidebar, gogogo!

Time:2020-3-25

By hellogithub-Dreamer

The sample code involved in this article has been synchronously updated to the hellogithub team warehouse

Our blog sidebar has four items: the latest article, archive, category and tag cloud. These contents are relatively fixed and independent, and will be displayed on each page. If you get these data from the view function and pass it to the template like the article list or article details, you need to write a section of code to get these contents in the view function corresponding to each page, which will lead to many duplicate codes. The better solution is to get it directly in the template. For this reason, we use a new technology of Django: custom template label to complete the task.

How to use template label

We have been exposed to some of the built-in template tags of Django, such as the simple{% static %}Template tag, which helps us to introduce static files into the template. There are more complicated ones, such as{% for %} {% endfor%}Label. Here we want to define a template label ourselves, for example namedshow_recent_postsThe template tag, which works like this: we just write in the template{% show_recent_posts %}, then a list page of the latest articles will be rendered in the template, which is similar to our blog homepage view function. Get the list of articles from the database and save it topost_listVariable, and then put thispost_listVariables are passed to the template. The template uses the for template tag to loop through the article list variables to show one article. The only difference here is that we get the list of articles from the database not in the view function, but in the template through custom{% show_recent_posts %}Template label.

The above is the solution, but the template label is not written at will. You must follow Django’s specifications to use it in Django’s template system. Next, we will implement our requirements according to these specifications.

Template label directory structure

First of all, in ourApplication of BlogCreate a templatetags folder under. Then create a init.Py file under the folder to make the folder a Python package, and then create a blog extras.py file under the templatetags directory, which stores the custom template label code.

Your directory structure should look like this:

blog\
    __init__.py
    admin.py
    apps.py
    migrations\
        __init__.py
    models.py
    static\
    templatetags\
        __init__.py
        blog_extras.py
    tests.py
    views.py

Write template label code

The next step is to write the code for each template tag. The custom template tag code is written in the blog_extras.py file. In fact, template tag is essentially a python function, so it’s OK to write the code of template tag according to the idea of Python function. There’s nothing new or new to learn.

Latest article template label

Open the blog? Extras.py file and start writing our latest post template tags.

from django import template

from ..models import Post, Category, Tag

register = template.Library()


@register.inclusion_tag('blog/inclusions/_recent_posts.html', takes_context=True)
def show_recent_posts(context, num=5):
    return {
        'recent_post_list': Post.objects.all().order_by('-created_time')[:num],
    }

Here we first import the template module, and then instantiate atemplate.LibraryClass, andshow_recent_postsDecorate asregister.inclusion_tag, which tells Django that this function is a custom template tag of type include < tag.

The function of the include tab template is similar to that of the view function. It returns a dictionary value. The value in the dictionary will be used as the template variable and passed into the template specified by the first parameter of the include tab decorator. When we pass in the template{% show_recent_posts %}When you use your own defined template label, Django will render and replace the content of the specified template with the template variable returned by the template label.

Parameters for the inclusion tab decoratortakes_contextSet toTrueDjango will be told that when rendering the ﹐ recent ﹐ posts.html template, not only theshow_recent_postsThe returned template variable is passed into the parent template (i.e. using the{% show_recent_posts %}Template of template tag) context (it can be simply understood as the template variable passed into the parent template by the view function of the render parent template and the template variable passed in by Django itself). Of course, this context is not used here. This is just a simple demonstration. If you need to use this context, you can use the context variable to reference this context in the definition of the template label function.

The next step is to define the contents of the template ﹣ recent ﹣ posts.html. Create an includes folder in the templatesblogs directory, and then create a file ﹣ recent ﹣ posts.html. The contents are as follows:

<div class="widget widget-recent-posts">
  < H3 class = "widget title" > latest article</h3>
  <ul>
    {% for post in recent_post_list %}
      <li>
        <a href="{{ post.get_absolute_url }}">{{ post.title }}</a>
      </li>
    {% empty %}
      No article yet!
    {% endfor %}
  </ul>
</div>

It’s very simple. The cycle is made up ofshow_recent_postsTemplate variables passedrecent_post_listThat is to say, it is the same as loop display of article list in index.html.

Archive template label

As with the latest article template label, first write the function, and then register the function as the template label.

@register.inclusion_tag('blog/inclusions/_archives.html', takes_context=True)
def show_archives(context):
    return {
        'date_list': Post.objects.dates('created_time', 'month', order='DESC'),
    }

HerePost.objects.datesMethod will return a list with the elements in the list as the creation time (de duplicated) of each post, and it is PythondateObjects, accurate to month, in descending order. The three parameter values accepted indicate these meanings. One iscreated_timeThat is to sayPostCreated on,monthIt’s precision.order='DESC'Indicates a descending order (that is, the closer the time to the current, the more time to the front). For example, we wrote three articles, which were published on February 21, 2017, March 25, 2017 and March 28, 2017, respectively, sodatesThe function returns a time list of March 2017 and February 2017 in descending order to help us archive by month.

Then there is the content of the rendered template [archives. HTML:

<div class="widget widget-archives">
  < H3 class = "widget title" > Archive</h3>
  <ul>
    {% for date in date_list %}
      <li>
        "{date. Year} {date. Month}}} month</a>
      </li>
    {% empty %}
      No filing yet!
    {% endfor %}
  </ul>
</div>

Becausedate_listEach element in is PythondateObject, so you can referenceyearandmonthProperty to get the year and month.

Classification template label

The process is the same, first write the function, and then register the function as a template label. Note that the classification template label function is usedCategoryClass, which is defined in the blog.models.py file. Remember to import it before use, otherwise an error will be reported.

@register.inclusion_tag('blog/inclusions/_categories.html', takes_context=True)
def show_categories(context):
    return {
        'category_list': Category.objects.all(),
    }

_Contents of categories.html:

<div class="widget widget-category">
  < H3 class = "widget title" > category</h3>
  <ul>
    {% for category in category_list %}
      <li>
        <a href="#">{{ category.name }} <span class="post-count">(13)</span></a>
      </li>
    {% empty %}
      No classification yet!
    {% endfor %}
  </ul>
</div>

<span class="post-count">(13)</span>It shows the number of articles under the classification. This feature will be explained in the next tutorial. At present, it is temporarily replaced by occupation data.

Label cloud template label

Label and classification are very similar. Template label:

@register.inclusion_tag('blog/inclusions/_tags.html', takes_context=True)
def show_tags(context):
    return {
        'tag_list': Tag.objects.all(),
    }

_tags.html:

<div class="widget widget-tag-cloud">
  < H3 class = "widget title" > tag cloud</h3>
  <ul>
    {% for tag in tag_list %}
      <li>
        <a href="#">{{ tag.name }}</a>
      </li>
    {% empty %}
      No label yet!
    {% endfor %}
  </ul>
</div>

Use custom template labels

Open base.html. In order to use the template tags just defined, we need to import the modules to store these template tags in the template. Here is the blog_extras.py module. At that time, we imported it to use the static template label{% load static %}This time{% load static %}Next, import blog extras:

templates/base.html

{% load static %}
{% load blog_extras %}
<!DOCTYPE html>
<html>
...
</html>

Then find the sidebar items and replace them with the corresponding template labels:

templates/base.html

<aside class="col-md-4">
  {% block toc %}
  {% endblock toc %}

  {% show_recent_posts %}
  {% show_archives %}
  {% show_categories %}
  {% show_tags %}

  <div class="rss">
     RSS subscription</a>
  </div>
</aside>

Before that, each function block in the sidebar was replaced with a template tag. In fact, the actual content is the same, but we moved it to a modular template, and these custom template tags are responsible for rendering these content.

In addition, we defineshow_recent_postsThe tag can receive parameters. The default value is 5, that is, 5 articles are displayed. If you want to control the display of 10 articles, you can use the{% show_recent_posts 10 %}Parameters are passed in this way.

Now running the development server, you can see that the data displayed in the sidebar is no longer the previous occupation data, but the data we saved in the database.

Be careful:

If you are writing the template tag code in the process of starting the development server, you must restart the development server to import the blog? Extras, otherwise you will be notified

TemplateSyntaxError at /

‘blog_extras’ is not a registered tag library. Must be one of:

A mistake like this.

Be careful: if you find errors after following the steps in the tutorial, please check them in the following order.

  1. Check that the directory structure is correct. Make sure that the templatetags are in the blog directory and that the directory name must be templatetags. Please refer to the directory structure given above for details.
  2. Make sure there is a file called “init. Py” in the templatetags directory.
  3. Ensure thatregister = template.Library()and@register.inclusion_tagThe decorator decorates the function as a template label.
  4. Make sure that you have imported blog ﹐ extras, {% load blog ﹐ extras%} before using the template tag.Note that you want to import it before using the template label under any blog? Extras.
  5. Make sure the syntax of the template tag is used correctly, that is, {% load blog ﹣ extras%}, and note that between {and% and% and}No,Any spaces.

Hellodjango Article 12: Unlock blog sidebar, gogogo!

Welcome to HelloGitHub official account for more open source projects.

“Explain open source project series”Launch – let the people who are interested in the open source project no longer fear, let the initiator of the open source project no longer alone. Following our article, you will find programming fun, easy to use, and easy to participate in open source projects. Welcome to contact us to contribute to us, let more people fall in love with open source, contribute to open source ~