Evgenii Legotckoi
Evgenii LegotckoiҚар. 13, 2016, 1:04 Т.Ж.

Джанго - 014-сабақ. Джангодағы танымал мақалалар тізімін көрсету

Көптеген блогтар мен жаңалықтар сайттарында аудиторияның назарын аудару үшін аптадағы ең танымал мақалалардың рейтингі, ұқсас жарияланымдар және кейбір үлкен ресурстар, сондай-ақ пайдаланушының қалауы бойынша ұсыныстар сияқты әдістер қолданылады. .

Ең алдымен танымал мақалалардың тізімін көрсету туралы шешім қабылданды. Танымал мақалалардың бірінші нұсқасы жалпы қарау санына негізделді және ең көп қаралған мақалаларға әкелді. Бұл әдетте жаман нұсқа, өйткені ТОП-та нәтижесінде барлық уақыттағы ең көп қаралған мақалалар болады.

Сондықтан бір нәрсені өзгерту керек болды. Нәтижесінде соңғы 7 күндегі танымал мақалаларды көрсету ең қарапайым нұсқада жүзеге асырылды. Яғни, күн бойынша мақаланы қарау саны енгізілген кесте қосылды. Әрине, ауыр жүктеме кезіндегі есептеулердің дәлдігі айтарлықтай өзгеруі мүмкін, бірақ трафик күніне 5 000 - 10 000 бірегей келушілерге жеткенше, бұл соншалықты маңызды емес.

Ал енді 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\_\_', )                # поле, по которому производится поиск

Бұл кодта екі модель бар:

  1. Статистиканы жинауға арналған модельдің өзі
  2. Басқару тақтасында деректерді көрсету үлгісі.

Бұл үлгілер 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 үшін Timeweb хостының VDS-сервері ұсынамын.

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Ол саған ұнайды ма? Әлеуметтік желілерде бөлісіңіз!

R
  • Қаң. 5, 2017, 2:20 Т.Ж.

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

Evgenii Legotckoi
  • Қаң. 5, 2017, 7:50 Т.Ж.

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

R
  • Қаң. 5, 2017, 8:41 Т.Ж.

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

ИМ
  • Қаң. 30, 2018, 6:24 Т.Қ.
Здравствуйте Евгений! Чему может быть причиной эта ошибка:
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 %}
Очень надеюсь на вашу помощь.
Evgenii Legotckoi
  • Қаң. 31, 2018, 3:49 Т.Ж.

Добрый день!

Во-первых перепишите 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')
]
ИМ
  • Қаң. 31, 2018, 4:38 Т.Ж.

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

Evgenii Legotckoi
  • Қаң. 31, 2018, 4:45 Т.Ж.

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

<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>
ИМ
  • Қаң. 31, 2018, 5:37 Т.Ж.

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

Evgenii Legotckoi
  • Қаң. 31, 2018, 6:04 Т.Ж.

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

 
Вообще можете показать модель PostStatistic? Я явно что-то упускаю здесь.
ИМ
  • Қаң. 31, 2018, 6:22 Т.Ж.

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


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
Evgenii Legotckoi
  • Қаң. 31, 2018, 7:03 Т.Ж.

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

Один аргумент - это либо 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]
ИМ
  • Қаң. 31, 2018, 10:11 Т.Ж.

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

Evgenii Legotckoi
  • Қаң. 31, 2018, 10:20 Т.Ж.

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

Но реально, сделайте post лучше отдельным приложение.
Я по началу делал на сайте статьи с зависимостью от секции, но потом понял, что это будет ошибкой. Дело в том, что если у вас поменяется раздел у статьи или поста, то тогда пост будет располагаться по другому url, а старый будет отдавать ошибку 404. Это плохо для индексации сайта. Поэтому я вовремя опомнился и сделал url поста независимым от раздела.
ИМ
  • Қаң. 31, 2018, 10:22 Т.Ж.

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

Владислав Меленчук
  • Маусым 10, 2021, 12:44 Т.Қ.

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

Evgenii Legotckoi
  • Шілде 2, 2021, 4:46 Т.Ж.

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

Владислав Меленчук
  • Шілде 2, 2021, 4:52 Т.Ж.

спасибо

Пікірлер

Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
Кіріңіз немесе Тіркеліңіз
OI
  • Ora Iro
  • Жел. 24, 2024, 6:38 Т.Ж.

C++ - Тест 001. Первая программа и типы данных

  • Нәтиже:40ұпай,
  • Бағалау ұпайлары-8
AD

C++ - Тест 004. Указатели, Массивы и Циклы

  • Нәтиже:50ұпай,
  • Бағалау ұпайлары-4
m
  • molni99
  • Қаз. 26, 2024, 1:37 Т.Ж.

C++ - Тест 004. Указатели, Массивы и Циклы

  • Нәтиже:80ұпай,
  • Бағалау ұпайлары4
Соңғы пікірлер
ИМ
Игорь МаксимовҚар. 22, 2024, 11:51 Т.Ж.
Django - Оқулық 017. Теңшелген Django кіру беті Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Evgenii Legotckoi
Evgenii LegotckoiҚаз. 31, 2024, 2:37 Т.Қ.
Django - Сабақ 064. Python Markdown кеңейтімін қалай жазуға болады Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZEҚаз. 19, 2024, 8:19 Т.Ж.
Qt Creator көмегімен fb3 файл оқу құралы Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь МаксимовҚаз. 5, 2024, 7:51 Т.Ж.
Django - Сабақ 064. Python Markdown кеңейтімін қалай жазуға болады Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas5Шілде 5, 2024, 11:02 Т.Ж.
QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Енді форумда талқылаңыз
Evgenii Legotckoi
Evgenii LegotckoiМаусым 24, 2024, 3:11 Т.Қ.
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
t
tonypeachey1Қар. 15, 2024, 6:04 Т.Ж.
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
NSProject
NSProjectМаусым 4, 2022, 3:49 Т.Ж.
Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
9
9AnonimҚаз. 25, 2024, 9:10 Т.Ж.
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

Бізді әлеуметтік желілерде бақылаңыз