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 Т.Ж.

спасибо

Пікірлер

Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
Кіріңіз немесе Тіркеліңіз
Г

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

  • Нәтиже:66ұпай,
  • Бағалау ұпайлары-1
t

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

  • Нәтиже:33ұпай,
  • Бағалау ұпайлары-10
t

Qt - Тест 001. Сигналы и слоты

  • Нәтиже:52ұпай,
  • Бағалау ұпайлары-4
Соңғы пікірлер
G
GoattRockҚыр. 3, 2024, 1:50 Т.Қ.
Linux жүйесінде файлдарды қалай көшіруге болады Задумывались когда-нибудь о том, как мы привыкли доверять свои вещи службам грузоперевозок? Сейчас такие услуги стали неотъемлемой частью нашей жизни, особенно когда речь идет о переездах между …
d
dblas5Шілде 5, 2024, 11:02 Т.Ж.
QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssrАқп. 8, 2024, 6:43 Т.Қ.
Qt Linux - Сабақ 001. Linux астында Autorun Qt қолданбасы как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий КононенкоАқп. 5, 2024, 1:50 Т.Ж.
Qt WinAPI - Сабақ 007. Qt ішінде ICMP Ping арқылы жұмыс істеу Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
Енді форумда талқылаңыз
Evgenii Legotckoi
Evgenii LegotckoiМаусым 24, 2024, 3:11 Т.Қ.
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
F
FynjyШілде 22, 2024, 4:15 Т.Ж.
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …
BlinCT
BlinCTМаусым 25, 2024, 1 Т.Ж.
Нарисовать кривую в qml Всем привет. Имеется Лист листов с тосками, точки получаны интерполяцией Лагранжа. Вопрос, как этими точками нарисовать кривую? ChartView отпадает сразу, в qt6.7 появился новый элемент…
BlinCT
BlinCTМамыр 5, 2024, 5:46 Т.Ж.
Написать свой GraphsView Всем привет. В Qt есть давольно старый обьект дял работы с графиками ChartsView и есть в 6.7 новый но очень сырой и со слабым функционалом GraphsView. По этой причине я хочу написать х…
Evgenii Legotckoi
Evgenii LegotckoiМамыр 2, 2024, 2:07 Т.Қ.
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.

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