Вопрос проектирования: агрегирование данных с низкой нагрузкой для страницы обзора - PullRequest
0 голосов
/ 08 мая 2019

Каков наилучший способ достижения низкой нагрузки на базу данных или сервер приложений для этого варианта использования:

Допустим, я хочу создать веб-приложение, которое имеет для каждого пользователя страницу обзора.Страница обзора показывает в агрегированном виде для каждого пользователя данные пользователя.Например, если бы это было библиотечное приложение, оно показывало бы, сколько раз пользователь посетил библиотеку в целом, сколько книг он прочитал в целом, сколько книг было доставлено с задержкой в ​​общей сложности, сколько минут он провел в здании.Каждый раз, когда пользователь посещает страницу обзора, должны отображаться актуальные значения.В то время как пользователь взаимодействует с сайтом, номера меняются.

Что я мог сделать, так это для каждого обновления страницы обзора сделать несколько подсчетов в базе данных.Но это было бы дорого.

views.py

def overview(request, userID):
    booksCount = Book.objects.count()
    booksReadCount = Book.objects.filter(UserID=userID, Status='read').count()
    # ... many more, same way
    libraryVisitedCount = LibraryVisits.objects.filter(UserID=userID).count()
    # many counts like these on different tables for the user

    data = {
        "booksCount" : booksCount,
        "booksReadCount" : booksReadCount,
        # ... many more
        "libraryVisitedCount" : libraryVisitedCount
    }

    render(..., context=data)

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

Или я мог бы использовать представление с материей, но для его обновления мне пришлось бы пересчитать все данные всехпользователи каждый раз, верно?

Другие идеи?Я использую базу данных django webframework и базу данных postgres.

TL; DR: Интересно, не существует ли лучшего способа получать подсчеты, чем каждый раз в базе данных?

Спасибо.

1 Ответ

0 голосов
/ 08 мая 2019

Допустим, в моделях Book, LibraryVisit и т. Д. Существует модель ForeignKey to User с related_name , например:

class Book(models.Model):
    UserID = models.ForeignKey(User, related_name='books', on_delete=DO_NOTHING)

class LibraryVisit(models.Model):
    UserID = models.ForeignKey(User, related_name='library_visit', on_delete=DO_NOTHING)

Тогда вы можете использовать аннотацию и условное выражение , например:

from django.db.models import Case, IntegerField, Sum, When

def overview(request, userID):
    users = User.objects.filter(pk=userId)
    users = users.annotate(
            booksReadCount=Sum(
                Case(
                    When(<b>book</b>__Status='read', then=1), 
                    output_field=IntegerField()
                )
            )
        ).annotate(library_visited_count=Count('<b>library_visit</b>'))
    # FYI: please use <i>snake_case</i> when defining object attribute(like model fields) as per PEP-8 style guide
    data = {
        "user_object" : users.first(),  # taking first item of the User queryset. Also DB is hit once in this step
        "booksCount" : Book.objects.count()
    }
    # access counts in view like this:
    # user.book_read_count
    # user.library_visited_count
    return render(..., context=data)

    # bold marked words are <b>related_name</b>

И рендер рассчитывает в шаблоне так:

{{ user_object.book_read_count }}
{{ user_object.library_visited_count }}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...