Evgenij LegotskojNov. 13, 2016, 1:04 a.m.

Django - Tutorial 014. Displays a list of popular articles on Django

Many blogs and news sites to keep the audience's attention using such methods as ranking popular articles this week, related publications, and some major resources and more advice on user preferences.

First, it was decided to do - it displays a list of popular articles. The first version of the popular articles was based on a general counter views and eventually deduced the article with the most views. This is generally a bad option, since the TOP will result in articles just scored the highest number of views for all time.

Therefore it was necessary to change something. As a result, the output has been introduced popular articles in last 7 days in its simplest form. That is, the table has been added which introduced views of articles by day. Of course, the accuracy of counting under heavy load can vary greatly, but attendance is not reached the 5,000 - 10,000 unique visitors a day - it's not so important.

Now lets proceed with an example of how to make a list of popular articles Django .


Article and Statistics models

Here is a stripped-down version of the model for items, as in this case, I'm interested in only the title of the article.

class Article(models.Model):
    class Meta:
        db\_table = "article"

    title = models.CharField('Title', max\_length=200)

    def \_\_str\_\_(self):
        return self.title

A statistical model views on articles will be the next code.

class ArticleStatistic(models.Model):
    class Meta:
        db\_table = "ArticleStatistic"

    article = models.ForeignKey(Article)                    
    date = models.DateField('Date', default=timezone.now)   
    views = models.IntegerField('Views', default=0)     

    def \_\_str\_\_(self):
        return self.article.title


class ArticleStatisticAdmin(admin.ModelAdmin):
    list\_display = ('\_\_str\_\_', 'date', 'views')  
    search\_fields = ('\_\_str\_\_', )                

In this code, made two models:

  1. The model itself to collect statistics
    Model to display the data in the admin area.

These models will be written in models.py file.

Do not forget to also register the model in the admin in admin.py file.

from django.contrib import admin

from .models import Article, ArticleStatistic, ArticleStatisticAdmin

admin.site.register(Article)
admin.site.register(ArticleStatistic, ArticleStatisticAdmin)

Then do not forget to do a database migration.

python manage.db makemigrations
python manage.db migrate

Views

Once we have added to the model, it remains to add the conclusion of popular articles and make the counting statistics when requested article from the server.

from django.views import View
from django.shortcuts import render\_to\_response, get\_object\_or\_404
from django.utils import timezone
from django.db.models import Sum

# To work with the models of articles I have used knowledge module
from knowledge.models import Article, ArticleStatistic  


# while module is used for displaying articles post
# This was done in order to URL items was the following form
#    /post/42/ - where 42 - it is id od article in database
class EArticleView(View):
    template\_name = 'knowledge/article.html'    

    def get(self, request, *args, **kwargs):
        article = get\_object\_or\_404(Article, id=self.kwargs['article\_id'])    
        context = {}

        # Then we pick up the object of today's statistics, or create a new one if required
        obj, created = ArticleStatistic.objects.get\_or\_create(
            defaults={
                "article": article,
                "date": timezone.now()
            },
            # At the same time define a fence or statistics object creation
            # by two fields: date and a foreign key to the article
            date=timezone.now(), article=article    
        )
        obj.views += 1    
        obj.save(update\_fields=['views'])

        # Now pick up the list of the last 5 most popular articles of the week
        popular = ArticleStatistic.objects.filter(
            # filter records in the last 7 days
            date\_\_range=[timezone.now() - timezone.timedelta(7), timezone.now()]
        ).values(
            # Taking the field of interest to us, namely, the id and the title
            # Unfortunately we can not to pick up an object on the foreign key in this case 
            # Only the specific field of the object
            'article\_id', 'article\_\_title'
        ).annotate(
            # Summing over rated recording
            # All sum properly with matching fields for the requested objects
            views=Sum('views')
        ).order\_by(
            # sort the records Descending
            '-views')[:5]  # Take 5 last records

        context['popular\_list'] = popular # We went to the context of the list of articles

        return render\_to\_response(template\_name=self.template\_name, context=context)

Display template

And now just be displayed in page template list of popular articles of the week. I'll note that only give you a template to display a list. This is enough to understand how to get a list of articles on the page.

Do not also forget that I am using django_bootstrap3, therefore, the pattern looks accordingly.

{% if popular\_list %}{% load bootstrap3 %}
<ul class="list-group">
<li class="list-group-item active"><strong>Популярные публикации за неделю</strong></li>
{% for pop\_article in popular\_list %}
    <li class="list-group-item">
    <a href="{% url 'post:article' pop\_article.article\_id %}">{{ pop\_article.article\_\_title }}</a>
    </li>
{% endfor %}
</ul>
{% endif %}

URL pattern:

url(r'^(?P<article\_id>[0-9]+)/$', views.EArticleView.as\_view(), name='article'),

Result

The list of popular articles will be similar to that used on this site, but without the total number of views and, in the admin stats will look like this:

For Django I recommend VDS-server of Timeweb hoster .

We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.
R
  • #
  • Jan. 5, 2017, 2:20 a.m.

Добрый день! В Django я новичок. По Вашей инструкции у меня получилось вывести популярные статьи, но они видны только в статье. Как вывести их на главную страницу? Заранее спасибо за ответ!

Я подумал, что этот вопрос можно рассмотреть немного подробнее, поэтому представил в виде отдельной статьи. Можете посмотреть вариант решения здесь: Вывод списка популярных статей на любой странице сайта

R

Спасибо Вам большое!!!

IM
Здравствуйте Евгений! Чему может быть причиной эта ошибка:
Reverse for 'post' with arguments '(1,)' not found. 1 pattern(s) tried: ['main\\/(?P<section>[^/]+)\\/(?P<post_id>[^/]+)\\/$']
Мой урл, и вьюха.
app_name = 'main'

urlpatterns = [
    path('', views.Index, name='index'),
    path('<section>/', views.SectionView.as_view(), name='section'),
    path('<section>/<post_id>/', views.PostView.as_view(), name='post')
]

class PostView(View):
    template_name = 'main/post.html'    # Шаблон статьи
 
    def get(self, request, *args, **kwargs):
        post = get_object_or_404(Post, id=self.kwargs['post_id'])
        context = {}
        obj, created = PostStatistic.objects.get_or_create(defaults={"post": post,"date": timezone.now()}, date=timezone.now(), post=post)
        obj.views += 1
        obj.save(update_fields=['views'])
 
        popular = PostStatistic.objects.filter(
            date__range=[timezone.now() - timezone.timedelta(7), timezone.now()]
        ).values(
            'post_id', 'post__title'
        ).annotate(
            views=Sum('views')
        ).order_by(
            '-views')[:2]

        context['post_id'] = post
        context['popular_list'] = popular
        context['username'] = auth.get_user(request).username
 
        return render_to_response(template_name=self.template_name, context=context)
Ну и шаблон до кучи:

{% if popular_list %}
<ul class="list-group">
<li class="list-group-item active"><strong>Популярные публикации за неделю</strong></li>
{% for pop_post in popular_list %}
    <li class="list-group-item">
    <a href="{% url 'main:post' pop_post.post_id %}">{{ pop_post.post__title }}</a>
    </li>
{% endfor %}
</ul>
{% endif %}
Очень надеюсь на вашу помощь.

Добрый день!

Во-первых перепишите urlpatterns так

urlpatterns = [
    path('', views.Index, name='index'),
    path('<section>/<post_id>/', views.PostView.as_view(), name='post'),
    path('<section>/', views.SectionView.as_view(), name='section')
]
Маршрутизатор url в Django иногда тупит из-за последовательности объявления шаблонов. Поэтому лучше шаблоны url прописывать в алфавитном порядке и больший шаблон ставить первым.

Во-вторых вы используете id, а там нужно тогда указать, что это у вас целочисленное значение, по умолчанию обрабатывается как строка. Значит результирующая запись будет такой.
urlpatterns = [
    path('', views.Index, name='index'),
    path('<section>/<int:post_id>/', views.PostView.as_view(), name='post'),
    path('<section>/', views.SectionView.as_view(), name='section')
]
IM

К сожалению это не изменило ситуацию. Убираю ссылку на статью из шаблона и все работает.  Вероятно не правильно сформирована ссылка в шаблоне.

Да. действительно, на это я не обратил внимания. Напишите либо так

<a href="{% url 'main:post' pop_post.id %}">{{ pop_post.post__title }}</a>
либо так
<a href="{% url 'main:post' pop_post.pk %}">{{ pop_post.post__title }}</a>
IM

И этот вариант к сожалению не рабочий =(

Извиняюсь, неправильно написал последний ответ. В рамках данной статьи это не правильно, у вас же во вьюшке формируется объект у которого в post_id должен содержаться его PrimaryKey.

 
Вообще можете показать модель PostStatistic? Я явно что-то упускаю здесь.
IM

Такая же как и у вас вроди бы.


class PostStatistic(models.Model):
    class Meta:
        db_table = "PostStatistic"
 
    post = models.ForeignKey(Post, on_delete=models.CASCADE) 
    date = models.DateField('Дата', default=timezone.now)   
    views = models.IntegerField('Просмотры', default=0)
 
    def __str__(self):
        return self.post.title

мда... глупо как-то получилось. У вас же в шаблоне два аргумента задано.

Один аргумент - это либо id раздела, либо его имя (вомзожно тоже самое slug поле, а вторым параметром идёт id самого поста).

Полагаю, что вы, возможно, основывались на вот этой статье , когда изучали материал.
Дело в том, что здесь идёт иной подход в формировании url для поста. И вам ещё потребуется указать раздел этого поста в шаблоне.

Что-то типо такого
<a href="{% url 'main:post' pop_post.post__section pop_post.post_id %}">{{ pop_post.post__title }}</a>

Думаю, что вам нужно немного поправить ещё вот этот метод
popular = PostStatistic.objects.filter(
    date__range=[timezone.now() - timezone.timedelta(7), timezone.now()]
).values(
    'post_id', 'post__title', 'post__section'
).annotate(
    views=Sum('views')
).order_by(
    '-views')[:2]
IM

Если делать таким образом, то вьюха отдает id категории а не slug. Попробую пост сделать отдельным приложением. Во всяком случае большое спасибо за помощь.

А. Так вы slug использовали? Тогда там надо брать поле slug из section в запросе.

Но реально, сделайте post лучше отдельным приложение.
Я по началу делал на сайте статьи с зависимостью от секции, но потом понял, что это будет ошибкой. Дело в том, что если у вас поменяется раздел у статьи или поста, то тогда пост будет располагаться по другому url, а старый будет отдавать ошибку 404. Это плохо для индексации сайта. Поэтому я вовремя опомнился и сделал url поста независимым от раздела.
IM

Вот и я пришел к тому же пути. Так вроди бы логично и красиво выглядит.

Я как понял, этот метод создает статистику каждый день (на каждый день), не удаляя старые данные за день и выводит все данные за сегодняшние просмотры у всех статей?

Да, именно такой и была задумка

спасибо

Comments

Only authorized users can post comments.
Please, Log in or Sign up
Fornex

Let me recommend you a great European Fornex hosting.

Fornex has proven itself to be a stable host over the years.

For Django projects I recommend VPS hosting

Following the link you will receive a 5% discount on shared hosting services, dedicated servers, VPS and VPN

View Hosting
JS

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:50points,
  • Rating points-4
V

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:50points,
  • Rating points-4
DK

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:20points,
  • Rating points-10
Popular publications in the last 90 Days
Last comments

Qt/C++ - Lesson 005. QSqlRelationalTableModel - The work with relational tables

Хочу поделится, мы сделали свой вариант QSqlRelationalTableModel и заодно к нему новое развитие QTableView, и получилась готовая таблица PblTableDlg, у которой реализованы внешние связи, комбобо…
S

Qt WinAPI - Lesson 004. QtIFW - Automation WinDeployQt and build installers with Qt Installer Framework

Hello Evgenij, regarding the online installer, I've tried many times to use web host for the created repo after repogen step. I tried using github but I found people talking it is not …
  • juvf
  • Jan. 16, 2023, 10:18 p.m.

Qt/C++ - Lesson 051. QMediaPlayer – simple audio player

PS. Почти дописал плеер на QML. Уперся в ограничения QML. Переписываю плеер на с++/qt, а графика останится в qml. Нашел то, что мне надо, а именно индикатор звука. Qt может перехватывать аудиопо…

Qt/C++ - Lesson 039. How to paint stroke in QSqlTableModel by value in the column?

В этом случае вижу только какой-нибудь костыль в стиле перебора по всем индексам в заголовке с помощью методу headerData . То есть пройтись в for цикле пока не будет совпадения н…
a
  • avt
  • Dec. 12, 2022, 9:06 a.m.

Qt/C++ - Lesson 039. How to paint stroke in QSqlTableModel by value in the column?

Спасибо за ответ. Нет, дело не в читаемости кода, в разных таблицах у меня есть столбцы с одинаковым именем, но с разными индексами. Хотел сделать решение по имени столбца для всех таблиц сразу.…
Now discuss on the forum

django rest framework лишние символы

Покажите код сериализатора вашего.

Здравствуйте помогите с qml

нужно высчитывать координаты того, что должно двигаться, полагаю, что тот маленький круг, и в случае выхода за пределы круга менять переменную типа bool на true/false, которая в свою очередь буд…
  • BlinCT
  • Jan. 30, 2023, 11:59 a.m.

Обращение к сигналу из qml который реализован в другом потоке

Хотя есть мысль что я не правильно создаю реакцию на данный сигнал. Но вроде как правильно все.
VA

Как добавить виртуальную клавиатура с Т9 в своей проект на QML.

Добрый день. Прошу помочь, пишу небольше приложение в Qt. Добвил в свой проект виртуальную клавиатуру от Qt. Но как добавить в него возможность изменения Т9 никак не могу понять.
P
About
Services
© EVILEG 2015-2022
Recommend hosting TIMEWEB