Как отобразить последние элементы для персонализации в веб-приложении?
В 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 и должен быть простым, чтобы избежать дублирования (в зависимости от того, как элемент создается в этом сценарии).