Показывайте разные страницы в зависимости от пользователя - django
Я создаю веб-приложение, подобное IMDB. Каждый (зарегистрированный) пользователь просматривает одну и ту же домашнюю страницу, но он может отметить/отметить каждый фильм, который он хочет сохранить в "списке просмотренных". Я сделал это, но заметил, что каждый зарегистрированный пользователь может просматривать фильмы, отмеченные другим пользователем. Конечно, это проблема, поэтому я хотел бы создать страницу относительно каждого пользователя, чтобы у каждого была своя страница "просмотренных фильмов", основанная на фильмах, отмеченных как просмотренные. Основная идея заключается в том, что каждый раз, когда пользователь добавляет фильм в базу данных, он может отметить его как просмотренный с помощью простого models.BooleanField в модели фильма. Затем у меня есть еще одна модель "Seen", где находятся все фильмы, отмеченные как просмотренные.
models.py
class Films(models.Model):
...
seen = models.BooleanField(default=False)
class Seen(models.Model):
...
views.py
films = Films.objects.all()
for film in films:
flag = 0
seen_films = Seen.objects.all()
for _ in seen_films:
if film.name == _.name:
flag = 1
break
if not flag and film.seen:
act_seen = Seen(image=film.image, name=film.name, description=film.description)
act_seen.save()
Нужно добавить, что для пользователя я использую класс по умолчанию, предоставляемый django:
from django.contrib.auth.models import User
Я понял, что ошибка в том, что каждый может отметить/отметить фильм и поэтому каждый может видеть фильмы других пользователей, но я понятия не имею, как это исправить. Также я думаю, что код в views.py очень сырой, но это был скорее тест, чем конечный продукт. Спасибо!
Вы можете расширить стандартный класс User (проверьте документацию, есть несколько способов сделать это, и тот, который использую я, может не быть лучшим для вас) и использовать много-ко-многим для сохранения всех фильмов, которые пользователь видел:
# models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
films_seen = models.ManyToManyField(Films, related_name='seen_by')
Тогда вы можете использовать ListAPIView и переопределить метод get_queryset():
# views.py
from rest_framework.generics import ListAPIView
class FilmsSeenList(ListAPIView):
permission_classes = (IsAuthenticated,)
def get_queryset(self):
return self.request.user.profile.films_seen.all()
Обратите внимание, что вы должны быть уверены, что каждый пользователь имеет связанный профиль (например, с сигналом docs here), иначе get_queryset() вызовет ошибку Profile.DoesNotExist:
# handlers.py
from django.contrib.auth import get_user_model
from django.db.models.signals import post_save
from django.dispatch import receiver
from accounts.models import Profile # Define where your Profile model is here
User = get_user_model()
@receiver(post_save, sender=User, dispatch_uid="create_profile")
def post_save_user(sender, instance, created, **kwargs):
# Making sure that a profile is assigned for new users
if created:
Profile.objects.create(user=instance)
Вы также можете реализовать представление, возвращающее все фильмы и флаг, чтобы узнать, видел ли пользователь фильм:
# views.py
from rest_framework.generics import ListAPIView
class AllFilmsList(ListAPIView):
permission_classes = (IsAuthenticated,)
serializer_class = FilmsSeenFlagSerializer
def get_queryset(self):
return Films.objects.all()
# serializers.py
class FilmsSeenFlagSerializer(serializers.ModelSerializer):
seen = serializers.SerializerMethodField()
def get_seen(self, instance):
return instance.seen_by.filter(pk=self.context['request'].user.pk).exists()
class Meta:
model = Films
fields = [..., 'seen']