I'm building a web app IMDB's like. Each (logged) user views the same exact homepage, but they can flag/unflag every movie they want to save them in a "seen list". I've done that but I've noticed that every user logged can view the other user's flagged movies. Of course this is a problem, so I'd like to build a page relative to each user, so that everyone would have different "seen films" page based on the movies flagged as seen. The main idea behind this, is that whenever a user adds a movie to the database, he can flag it as seen with a simple models.BooleanField in the model of the film. I have then another model "Seen" where there are all the movies flagged.
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()
I need to add that for the user, I use the default class provided by django:
from django.contrib.auth.models import User
I get that the error is everyone can flag/unflag a movie and so everyone can see other user's movies but I have no idea how to fix that. Also I think the code in views.py is very raw but it was more a test than the final product. Thank you!
CodePudding user response:
You could extend the default User class (check the docs, there is several ways to do this and the one I use may not be the best one for you) and use a many-to-many to save all the movies that the user has seen:
# models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
films_seen = models.ManyToManyField(Films, related_name='seen_by')
Then you could use a ListAPIView
and override the get_queryset()
method:
# 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()
Note that you must be sure that each user has a profile associated (with a signal for example, docs here), else get_queryset()
would raise a 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)
You could also implement a view returning all the films and a flag to know if the user saw the film:
# 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']