На многих блогах и новостных сайтах для удержания внимания аудитории используются такие приёмы, как рейтинг популярных за неделю статей, похожие публикации, а у некоторых крупных ресурсов ещё и рекомендации по предпочтениям пользователей.
Первое, что было решено сделать - это вывод списка популярных статей. Первый вариант популярных статей был основан на общем счётчике просмотров и в итоге выводил статьи с самым большим количество просмотров. Это в целом плохой вариант, поскольку в ТОПе в итоге окажутся статьи просто набравшие самое большое количество просмотров за всё время.
Следовательно нужно было что-то менять. В результате был внедрен вывод популярных статей за последние 7 дней в самом простом варианте. То есть, добавлена была таблица в которую вносится количество просмотров статей по дням. Конечно, точность подсчётов при большой нагрузке может очень сильно варьироваться, но пока посещаемость не достигла 5000 - 10000 уникальных посетителей в сутки - это не настолько важно.
А теперь давайте разберём пример того, как сделать такой список популярных статей средствами Django .
Модели статей и статистики
Приведу урезанный вариант модели для статей, поскольку в данном случае меня интересует только заголовок статьи.
- class Article(models.Model):
- class Meta:
- db_table = "article"
- title = models.CharField('Название статьи', max_length=200)
- def __str__(self):
- return self.title
А для модели статистики просмотров по статьям код будет следующий.
- class ArticleStatistic(models.Model):
- class Meta:
- db_table = "ArticleStatistic"
- article = models.ForeignKey(Article) # внешний ключ на статью
- date = models.DateField('Дата', default=timezone.now) # дата
- views = models.IntegerField('Просмотры', default=0) # количество просмотров в эту дату
- def __str__(self):
- return self.article.title
- class ArticleStatisticAdmin(admin.ModelAdmin):
- list_display = ('__str__', 'date', 'views') # отображаемые поля в админке
- search_fields = ('__str__', ) # поле, по которому производится поиск
В данном коде сделано две модели:
- Сама модель для сбора статистики
- Модель для отображения данных в админке.
Эти модели будут написаны в файле models.py.
Не забываем также зарегистрировать эти модели в админке в файле admin.py.
- from django.contrib import admin
- from .models import Article, ArticleStatistic, ArticleStatisticAdmin
- admin.site.register(Article)
- admin.site.register(ArticleStatistic, ArticleStatisticAdmin)
После чего не забываем сделать миграцию базы данных.
- python manage.db makemigrations
- python manage.db migrate
Представление для отображения страницы
После того, как у нас добавлены модели, осталось добавить вывод популярных статей и сделать подсчёт статистики при запросе статьи с сервера.
- 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
- # Для работы с моделями статей у меня используется модуль knowledge
- from knowledge.models import Article, ArticleStatistic
- # тогда как для отображения статей используется модуль post
- # Это было сделано для того, чтобы URL статей был следующего вида
- # /post/42/ - где 42 - это id статьи в базе данных
- 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 = {}
- # Далее забираем объект сегодняшней статистики или создаём новый, если требуется
- obj, created = ArticleStatistic.objects.get_or_create(
- defaults={
- "article": article,
- "date": timezone.now()
- },
- # При этом определяем, забор объекта статистики или его создание
- # по двум полям: дата и внешний ключ на статью
- date=timezone.now(), article=article
- )
- obj.views += 1 # инкрементируем счётчик просмотров и обновляем поле в базе данных
- obj.save(update_fields=['views'])
- # А теперь забираем список 5 последний самых популярных статей за неделю
- popular = ArticleStatistic.objects.filter(
- # отфильтровываем записи за последние 7 дней
- date__range=[timezone.now() - timezone.timedelta(7), timezone.now()]
- ).values(
- # Забираем интересующие нас поля, а именно id и заголовок
- # К сожалению забрать объект по внешнему ключу в данном случае не получится
- # Только конкретные поля из объекта
- 'article_id', 'article__title'
- ).annotate(
- # Суммируем записи по просмотрам
- # Всё суммируется корректно с соответствием по запрашиваемым полям объектов
- views=Sum('views')
- ).order_by(
- # отсортируем записи по убыванию
- '-views')[:5] # Заберём последние пять записей
- context['popular_list'] = popular # Отправим в контекст список статей
- return render_to_response(template_name=self.template_name, context=context)
Отображение в шаблоне
Ну а теперь просто отобразим в шаблоне страницы список популярных статей за неделю. Оговорюсь, что приведу только шаблон для отображения списка. Этого достаточно для понимания того, как вывести список статей на странице.
Не забываем также что я использую django_bootstrap3 , поэтому шаблон выглядит соответствующим образом.
- {% 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 для запроса страниц с сайта:
- url(r'^(?P<article_id>[0-9]+)/$', views.EArticleView.as_view(), name='article'),
Итог
Список популярных статей будет похож на тот, что используется на данном сайте, только без общего количества просмотров, а в админке статистика будет выглядеть следующим образом:
Для Django рекомендую VDS-сервера хостера Timeweb .
Добрый день! В Django я новичок. По Вашей инструкции у меня получилось вывести популярные статьи, но они видны только в статье. Как вывести их на главную страницу? Заранее спасибо за ответ!
Я подумал, что этот вопрос можно рассмотреть немного подробнее, поэтому представил в виде отдельной статьи. Можете посмотреть вариант решения здесь: Вывод списка популярных статей на любой странице сайта
Спасибо Вам большое!!!
Добрый день!
Во-первых перепишите urlpatterns так
Во-вторых вы используете id, а там нужно тогда указать, что это у вас целочисленное значение, по умолчанию обрабатывается как строка. Значит результирующая запись будет такой.
К сожалению это не изменило ситуацию. Убираю ссылку на статью из шаблона и все работает. Вероятно не правильно сформирована ссылка в шаблоне.
Да. действительно, на это я не обратил внимания. Напишите либо так
И этот вариант к сожалению не рабочий =(
Извиняюсь, неправильно написал последний ответ. В рамках данной статьи это не правильно, у вас же во вьюшке формируется объект у которого в post_id должен содержаться его PrimaryKey.
Такая же как и у вас вроди бы.
мда... глупо как-то получилось. У вас же в шаблоне два аргумента задано.
Если делать таким образом, то вьюха отдает id категории а не slug. Попробую пост сделать отдельным приложением. Во всяком случае большое спасибо за помощь.
А. Так вы slug использовали? Тогда там надо брать поле slug из section в запросе.
Вот и я пришел к тому же пути. Так вроди бы логично и красиво выглядит.
Я как понял, этот метод создает статистику каждый день (на каждый день), не удаляя старые данные за день и выводит все данные за сегодняшние просмотры у всех статей?
Да, именно такой и была задумка
спасибо