Sign In Start Free Trial
Account

Add to playlist

Create a Playlist

Modal Close icon
You need to login to use this feature.
  • Book Overview & Buying Django 3 By Example
  • Table Of Contents Toc
Django 3 By Example

Django 3 By Example - Third Edition

By : Antonio Melé
4.3 (26)
close
close
Django 3 By Example

Django 3 By Example

4.3 (26)
By: Antonio Melé

Overview of this book

If you want to learn the entire process of developing professional web applications with Python and Django, then this book is for you. In the process of building four professional Django projects, you will learn about Django 3 features, how to solve common web development problems, how to implement best practices, and how to successfully deploy your applications. In this book, you will build a blog application, a social image bookmarking website, an online shop, and an e-learning platform. Step-by-step guidance will teach you how to integrate popular technologies, enhance your applications with AJAX, create RESTful APIs, and set up a production environment for your Django projects. By the end of this book, you will have mastered Django 3 by building advanced web applications.
Table of Contents (17 chapters)
close
close
15
Other Books You May Enjoy
16
Index

Adding the tagging functionality

After implementing your comment system, you need to create a way to tag your posts. You will do this by integrating a third-party Django tagging application into your project. django-taggit is a reusable application that primarily offers you a Tag model and a manager to easily add tags to any model. You can take a look at its source code at https://github.com/jazzband/django-taggit.

First, you need to install django-taggit via pip by running the following command:

pip install django_taggit==1.2.0

Then, open the settings.py file of the mysite project and add taggit to your INSTALLED_APPS setting, as follows:

INSTALLED_APPS = [
    # ...
    'blog.apps.BlogConfig',
    'taggit',
]

Open the models.py file of your blog application and add the TaggableManager manager provided by django-taggit to the Post model using the following code:

from taggit.managers import TaggableManager
class Post(models.Model):
    # ...
    tags = TaggableManager()

The tags manager will allow you to add, retrieve, and remove tags from Post objects.

Run the following command to create a migration for your model changes:

python manage.py makemigrations blog

You should get the following output:

Migrations for 'blog':
  blog/migrations/0003_post_tags.py
    - Add field tags to post

Now, run the following command to create the required database tables for django-taggit models and to synchronize your model changes:

python manage.py migrate

You will see an output indicating that migrations have been applied, as follows:

Applying taggit.0001_initial... OK
Applying taggit.0002_auto_20150616_2121... OK
Applying taggit.0003_taggeditem_add_unique_index... OK
Applying blog.0003_post_tags... OK

Your database is now ready to use django-taggit models.

Let's explore how to use the tags manager. Open the terminal with the python manage.py shell command and enter the following code. First, you will retrieve one of your posts (the one with the 1 ID):

>>> from blog.models import Post
>>> post = Post.objects.get(id=1)

Then, add some tags to it and retrieve its tags to check whether they were successfully added:

>>> post.tags.add('music', 'jazz', 'django')
>>> post.tags.all()
<QuerySet [<Tag: jazz>, <Tag: music>, <Tag: django>]>

Finally, remove a tag and check the list of tags again:

>>> post.tags.remove('django')
>>> post.tags.all()
<QuerySet [<Tag: jazz>, <Tag: music>]>

That was easy, right? Run the python manage.py runserver command to start the development server again and open http://127.0.0.1:8000/admin/taggit/tag/ in your browser.

You will see the administration page with the list of Tag objects of the taggit application:

Figure 2.10: The tag change list view on the Django administration site

Navigate to http://127.0.0.1:8000/admin/blog/post/ and click on a post to edit it. You will see that posts now include a new Tags field, as follows, where you can easily edit tags:

Figure 2.11: The related tags field of a Post object

Now, you need to edit your blog posts to display tags. Open the blog/post/list.html template and add the following HTML code below the post title:

<p class="tags">Tags: {{ post.tags.all|join:", " }}</p>

The join template filter works the same as the Python string join() method to concatenate elements with the given string. Open http://127.0.0.1:8000/blog/ in your browser. You should be able to see the list of tags under each post title:

Figure 2.12: The Post list item, including related tags

Next, you will edit the post_list view to let users list all posts tagged with a specific tag. Open the views.py file of your blog application, import the Tag model form django-taggit, and change the post_list view to optionally filter posts by a tag, as follows:

from taggit.models import Tag
def post_list(request, tag_slug=None):
    object_list = Post.published.all()
    tag = None
    if tag_slug:
        tag = get_object_or_404(Tag, slug=tag_slug)
        object_list = object_list.filter(tags__in=[tag])
    paginator = Paginator(object_list, 3) # 3 posts in each page
    # ...

The post_list view now works as follows:

  1. It takes an optional tag_slug parameter that has a None default value. This parameter will be passed in the URL.
  2. Inside the view, you build the initial QuerySet, retrieving all published posts, and if there is a given tag slug, you get the Tag object with the given slug using the get_object_or_404() shortcut.
  3. Then, you filter the list of posts by the ones that contain the given tag. Since this is a many-to-many relationship, you have to filter posts by tags contained in a given list, which, in your case, contains only one element. You use the __in field lookup. Many-to-many relationships occur when multiple objects of a model are associated with multiple objects of another model. In your application, a post can have multiple tags and a tag can be related to multiple posts. You will learn how to create many-to-many relationships in Chapter 5, Sharing Content on Your Website. You can discover more about many-to-many relationships at https://docs.djangoproject.com/en/3.0/topics/db/examples/many_to_many/.

Remember that QuerySets are lazy. The QuerySets to retrieve posts will only be evaluated when you loop over the post list when rendering the template.

Finally, modify the render() function at the bottom of the view to pass the tag variable to the template. The view should look like this:

def post_list(request, tag_slug=None):
    object_list = Post.published.all()
    tag = None
    if tag_slug:
        tag = get_object_or_404(Tag, slug=tag_slug)
        object_list = object_list.filter(tags__in=[tag])
    paginator = Paginator(object_list, 3) # 3 posts in each page
    page = request.GET.get('page')
    try:
        posts = paginator.page(page)
    except PageNotAnInteger:
        # If page is not an integer deliver the first page
        posts = paginator.page(1)
    except EmptyPage:
        # If page is out of range deliver last page of results
        posts = paginator.page(paginator.num_pages)
    return render(request, 'blog/post/list.html', {'page': page,
                                                   'posts': posts,
                                                   'tag': tag})

Open the urls.py file of your blog application, comment out the class-based PostListView URL pattern, and uncomment the post_list view, like this:

path('', views.post_list, name='post_list'),
# path('', views.PostListView.as_view(), name='post_list'),

Add the following additional URL pattern to list posts by tag:

path('tag/<slug:tag_slug>/',
     views.post_list, name='post_list_by_tag'),

As you can see, both patterns point to the same view, but you are naming them differently. The first pattern will call the post_list view without any optional parameters, whereas the second pattern will call the view with the tag_slug parameter. You use a slug path converter to match the parameter as a lowercase string with ASCII letters or numbers, plus the hyphen and underscore characters.

Since you are using the post_list view, edit the blog/post/list.html template and modify the pagination to use the posts object:

{% include "pagination.html" with page=posts %}

Add the following lines above the {% for %} loop:

{% if tag %}
  <h2>Posts tagged with "{{ tag.name }}"</h2>
{% endif %}

If a user is accessing the blog, they will see the list of all posts. If they filter by posts tagged with a specific tag, they will see the tag that they are filtering by.

Now, change the way tags are displayed, as follows:

<p class="tags">
  Tags:
  {% for tag in post.tags.all %}
    <a href="{% url "blog:post_list_by_tag" tag.slug %}">
      {{ tag.name }}
    </a>
    {% if not forloop.last %}, {% endif %}
  {% endfor %}
</p>

In the code above, you loop through all the tags of a post displaying a custom link to the URL to filter posts by that tag. You build the URL with {% url "blog:post_list_by_tag" tag.slug %}, using the name of the URL and the slug tag as its parameter. You separate the tags by commas.

Open http://127.0.0.1:8000/blog/ in your browser and click on any tag link. You will see the list of posts filtered by that tag, like this:

Figure 2.13: A post filtered by the tag "jazz"

CONTINUE READING
83
Tech Concepts
36
Programming languages
73
Tech Tools
Icon Unlimited access to the largest independent learning library in tech of over 8,000 expert-authored tech books and videos.
Icon Innovative learning tools, including AI book assistants, code context explainers, and text-to-speech.
Icon 50+ new titles added per month and exclusive early access to books as they are being written.
Django 3 By Example
notes
bookmark Notes and Bookmarks search Search in title playlist Add to playlist download Download options font-size Font size

Change the font size

margin-width Margin width

Change margin width

day-mode Day/Sepia/Night Modes

Change background colour

Close icon Search
Country selected

Close icon Your notes and bookmarks

Confirmation

Modal Close icon
claim successful

Buy this book with your credits?

Modal Close icon
Are you sure you want to buy this book with one of your credits?
Close
YES, BUY

Submit Your Feedback

Modal Close icon
Modal Close icon
Modal Close icon