Istanbul/Turkey

21- Add/Remove Movies To My List

In this post, I will add a button on moviesapppage that adds that specific movie to user's list. So, uses can easily see their selected movies later on and watch. To do that,first I need change my model a little bit. Many users can add many different movies and movies can be added by many different users. Therefore I need a ManyToMany field. At the end, my query will fetch and list movies from movie table. So,I am going to create this new field on Movies table.

models.py

I defined a related name as usermovielist. Django creates a new intermediary table internally for this field.

class Movie(models.Model):
    title= models.CharField(max_length=100)
    gender= models.CharField(max_length=20)
    description= models.CharField(max_length=255, blank=True, null=True)
    moviefile= models.FileField(upload_to='movie', blank=True, null=True)
    photo= models.FileField(upload_to='photo',blank=True, null=True)
    publishDate= models.DateField(blank=True, null=True)
    imdbID= models.CharField(max_length=10, blank=True, null=True)
    movieapp_score= models.FloatField(blank=True, null=True)
    date_added= models.DateField(auto_now=True)
    numberOfViews= models.IntegerField(default=0)
    duration= models.FloatField(blank=True, null=True)
    resolution= models.CharField(max_length=5)
    users = models.ManyToManyField(MyCustomUser, through='UserComment')
    usermovielist = models.ManyToManyField(MyCustomUser, related_name="usermovielist")
    
    def __str__(self):
        return self.title

 

Run makemigrations and migrate commands.

 

 

moviesapp.html

 I added a bootstrap badge (button link) and defined the url. I also pass movie id in the link.

{% extends 'base.html' %}

{% block title %}
    <title>MoviesApp</title>
{% endblock title %}


{% block content%}
<div class="p-3 mb-2 bg-dark text-white">
    <div class="container" style="background-color: #86aac4;">
        <div class="row row-cols-6">

            {% for m in movies%}
                <div class="col-2">
                            
                            <a href="/{% url 'watchmovie' m.id %}">
                            <p class="text-light">{{m.title}}</p>
                            <img src="/{{ MEDIA_URL }}{{m.photo}}"  width="200" height="300" class="rounded">
                            </a>
                            <a href="/{% url 'addtolist' m.id %}" class="text-white">Add To List</a>
                            <hr>

                            
                            
                </div>
            {%endfor block%} 
        </div>
        <!--pagination -->
        <nav aria-label="Pagination">
        <ul class="pagination justify-content-center">
            <li class="page-item"><a class="page-link" href="/?pg=1">First</a></li>
            {% if movies.has_previous %}
            <li class="page-item"><a class="page-link" href="/?pg={{movies.previous_page_number}}">{{movies.previous_page_number}}</a></li>
            {% endif %}
            <li class="page-item"><a class="page-link" href="/?pg={{movies.number}}">{{movies.number}}</a></li>
            {% if movies.has_next %}
            <li class="page-item"><a class="page-link" href="/?pg={{movies.next_page_number}}">{{movies.next_page_number}}</a></li>
            {% endif %}
            <li class="page-item"><a class="page-link" href="/?pg={{movies.paginator.num_pages}}">Last</a></li>
        </ul>
        </nav>
    <!--pagination ends--> 
    </div>
</div>
{% endblock content %}

 

urls.py

Then created its url

path('addtolist/<id>', views.addtolist, name='addtolist'),

 

views.py

I need unauthenticated user to be redirected to login page,therefore I am using @loginrequired decorator right before the view.

I fetched the movie object by using the passed id in the link. Then fetched the logged on user. The messages were just used to test if I was fetching correct objects, I then commented out them. We can check if we really fetch the expected objects by using messages like below. Then I added the user for this movie's usermovielist filed and created the relation.

from django.contrib.auth.decorators import login_required

@login_required(login_url='loginuser')
def addtolist(request, id):
    themovie = Movie.objects.get(pk=id)
    theuser = request.user
    #messages.success(request, "User is: " + theuser.username, extra_tags='green')
    #messages.success(request, "Movie is: " + themovie.title, extra_tags='green')
    themovie.usermovielist.add(theuser)
    messages.success(request, "Movie is Added", extra_tags='green')
    return redirect('moviesapp')

 

 

On Django Shell, we can run and test our query.So we can correct our view accordingly.

 Movie.objects.filter(usermovielist=4)
#<QuerySet [<Movie: The Last Samurai>, <Movie: The Shawshank Redemption>, <Movie: The Hobbit>]>

Movie.objects.filter(usermovielist=1)
#<QuerySet [<Movie: Brave Heart>, <Movie: Gladiator>, <Movie: Saving Private Ryan>]>

 

 

 That's how it looks. If AddToList button is clicked, the relation will be created between the user and the movie and message will be displayed.

 

 

 

Alright users can add movies to their list. Now we need to create a link where they can see their list. 

 

base.html

On my Navbar, let's add a link named mylist.

                  <li><a class="dropdown-item text-white" href="/{% url 'mylist' %}">My List</a></li>

 

 urls.py

Create the url path

path('mylist', views.mylist, name='mylist'),

 

 

views.py

Create the view function for listing the MyList. First get the user and then fetch movies where user id matches exactly on usermovielist table. The rest is the paginator. Here instead of a Add button we have a Remove button

def mylist(request):
    user = request.user
    movies = Movie.objects.filter(usermovielist__exact=user.id)
    #Paginator
    paginator_obj = Paginator(movies, 12)
    page_number = request.GET.get('pg')
    movies = paginator_obj.get_page(page_number)
    return render(request, 'mylist.html', {'movies': movies})

 

mylist.html

This template's content is almost the same as movieapp.html. Instead of Add To Mylist link, we have Remove link but the  link is not active at the moment (# is used for the href). Otherwise I would get an error because I do not have remove url right now.

{% extends 'base.html' %}

{% block title %}
    <title>MoviesApp</title>
{% endblock title %}


{% block content%}
<div class="p-3 mb-2 bg-dark text-white">
    <div class="container" style="background-color: #86aac4;">
        <div class="row row-cols-6">

            {% for m in movies%}
                <div class="col-2">
                            <a href="/{% url 'watchmovie' m.id %}">
                            <p class="text-light">{{m.title}}</p>
                            <img src="/{{ MEDIA_URL }}{{m.photo}}"  width="200" height="300" class="rounded">
                            </a>
                            <a href="#" class="text-white">Remove</a>
                </div>
            {%endfor block%} 
        </div>
        <!--pagination -->
        <nav aria-label="Pagination">
        <ul class="pagination justify-content-center">
            <li class="page-item"><a class="page-link" href="/?pg=1">First</a></li>
            {% if movies.has_previous %}
            <li class="page-item"><a class="page-link" href="/?pg={{movies.previous_page_number}}">{{movies.previous_page_number}}</a></li>
            {% endif %}
            <li class="page-item"><a class="page-link" href="/?pg={{movies.number}}">{{movies.number}}</a></li>
            {% if movies.has_next %}
            <li class="page-item"><a class="page-link" href="/?pg={{movies.next_page_number}}">{{movies.next_page_number}}</a></li>
            {% endif %}
            <li class="page-item"><a class="page-link" href="/?pg={{movies.paginator.num_pages}}">Last</a></li>
        </ul>
        </nav>
    <!--pagination ends--> 
    </div>
</div>
{% endblock content %}

 

 

 

Users can now see the movies which they added to their list. 

 

 

 

Remove Movies From Mylist:

Let's change mylist.html template first and define a url.

mylist.html

<a href="/{% url 'removefromlist' m.id %}" class="text-white">Remove</a>

 

 

urls.py

path('removefromlist/<id>', views.removefromlist, name='removefromlist'),

 

views.py

def removefromlist(request, id):
    themovie = Movie.objects.get(pk=id)
    theuser = request.user
    themovie.usermovielist.remove(theuser)
    messages.success(request, "Movie is Removed", extra_tags='green')
    return redirect('mylist')

 

 

 

 

  • Hits: 306