Как отобразить последние элементы для персонализации в веб-приложении?

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

Пример отображения последних проектов в порядке последнего посещения

Пример отображения последних проблем в порядке последнего посещения

Я использую Django для создания веб-приложения, и мне нравится включать ту же функцию.

У меня есть две идеи, но ни одна из них еще не реализована:

1. Одна гигантская таблица, хранящая все посещения отдельных пользователей

Должен ли я иметь одну гигантскую таблицу, в которой хранятся все элементы, которые посещают все пользователи? Если так, то как мне затем соединить это с основной таблицей, по которой я должен искать, чтобы произвести сортировку правильно?

2. Добавитьvisitedколонка к отдельным основным таблицам

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

Чего мне не хватает в плане понимания?

Кроме того, справедливо ли предположить, что мне нужно ограничить количество самых последних элементов, хранящихся на пользователя?

То есть, используя пример GitHub, можно хранить не более 5 самых последних проектов или проблем на пользователя.

3 ответа

Будет ли работать таблица, содержащая FK для пользователя, URL-адрес и дату и время последнего посещения? Затем создайте API (drf), чтобы вернуть самые последние 5 для пользователя:

visits.objects.filter(user=request.user).order_by('-datetime_visited')[:5]

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

last = visits.objects.filter(user=request.user).order_by('datetime_visited').first()
last.delete()
visits.objects.create(user=request.user, url=page_url, datetime_visited=datetime.datetime.now())

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

1. Одна гигантская таблица, хранящая все посещения отдельных пользователей

Вот как я мог бы реализовать это:

class Visit(models.Model):
    user = ForeignKey(User, related_name="recent_visits")
    item = ForeignKey(Item, related_name="visitors")
    last_visited = DateTimeField()

Затем в User сериализатор вы могли бы иметь SerializerMethodField чтобы соответствовать определенному количеству недавно посещенных пунктов, например:

class VisitSerializer(models.Model):
    item = YourItemSerializer()

    class Meta:
        model = Visit
        fields = ['item', 'last_visited']


class UserSerializer(serializers.ModelSerializer):
    recent_visits = serializers.SerializerMethodField()

    def get_items(self, obj):
        # you could also get the value of 5 from a constant or your settings or 
        # even the API itself
        items = Item.recent_visits.filter(user=obj)[:5]
        serializer = VisitSerializer(instance=items, many=True)
        return serializer.data

Однако это может быть излишним, если вы хотите сохранить небольшой список недавно посещенных элементов и не хотите иметь логику, основанную на расширенной истории посещений пользователя.

Хранение информации об элементе в пользовательской модели

Если вы хотите показать только определенную информацию об элементе (например, идентификатор, имя и т. Д.), Вы можете сохранить эту информацию в JSONField в модели пользователя и посещать элемент только тогда, когда пользователь хочет его детали. Вы можете сохранить запросы к базе данных таким способом, но вам придется немного поспорить с JSON, когда пользователь посещает или повторно посещает элемент.

Этот подход также будет зависеть от того, как часто поля Item что вы хотите сохранить в User модель меняется, или если элемент удаляется вообще.

Я думаю, что использование Visit в качестве отдельной модели является хорошим выбором для сохранения разделения.

Хорошо просто ограничить возвращаемый результат, такой как User.recent_visits.all()[:5] в API DRF.

Приведенное ниже решение гарантирует, что User.recent_visits.all () вернет 5 последних посещений без нарезки и избежит огромного списка.

"Шаблон", который я успешно использовал в прошлом, который примерно переводил бы в этот контекст как:

class VisitQuerySet(models.QuerySet):
    MAX_LRV = 5 # Max Last Recent Visits

    def add_item(self, user, item):
        with transaction.atomic():
            # to avoid duplicate items
            lrv, created = self.get_or_create(user=user, item=item)

            if not created:
                lrv.save()  # update timestamp
                return lrv

            self.prune_lrv(user)
        return lrv

    def prune_lrv(self, user):
        # One example of how to clean up the recent visits
        qs = self.filter(user=user)
        if qs.count() > self.MAX_LRV:
            pending_delete = qs[self.MAX_LRV:]
            self.filter(user=user, pk__in=pending_delete).delete()


class Visit(models.Model):
    class Meta:
        ordering = ('-last_visited',) # ordering important

    user = ForeignKey(User, related_name="recent_visits")
    item = ForeignKey(Item, related_name="visitors")
    last_visited = DateTimeField(auto_now=True)

    objects = VisitQuerySet.as_manager()


 # Adding a item
 Visit.objects.add_item(user, item)

 #Get last 5 recent visits
 request.user.recent_visits.all()

Список поддерживается при добавлении новых элементов, легко изменить MAX_LRV и должен быть простым, чтобы избежать дублирования (в зависимости от того, как элемент создается в этом сценарии).

Другие вопросы по тегам