I am building a web application using Django where users can follow or unfollow items (e.g., photos) from a list. Currently, I have implemented the follow/unfollow functionality, but it reloads the page every time the user clicks on follow or unfollow. I want to achieve this without reloading the page, so the user stays on the same page and the state changes (follow/unfollow) are reflected immediately.
models.py
class UserProfile(models.Model):
user = models.OneToOneField(get_user_model(), on_delete=models.CASCADE)
follows = models.ManyToManyField(Photo, related_name='followers')
def __str__(self):
return self.user.username
views.py
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from .models import Photo, Episode, UserProfile
def viewPhoto(request, pk):
photo = get_object_or_404(Photo, id=pk)
episodes = Episode.objects.filter(photo=photo)
if request.user.is_authenticated:
user_profile, created = UserProfile.objects.get_or_create(user=request.user)
is_following = photo in user_profile.follows.all()
else:
is_following = False
context = {
'photo': photo,
'episodes': episodes,
'is_following': is_following,
}
return render(request, 'photos/photo.html', context)
@login_required
def follow(request, pk):
photo = get_object_or_404(Photo, id=pk)
user_profile, created = UserProfile.objects.get_or_create(user=request.user)
user_profile.follows.add(photo)
return redirect('photo', pk=pk)
@login_required
def unfollow(request, pk):
photo = get_object_or_404(Photo, id=pk)
user_profile, created = UserProfile.objects.get_or_create(user=request.user)
user_profile.follows.remove(photo)
return redirect('photo', pk=pk)
html
{% if is_following %}
<div class="btn follow">
<a href="{% url 'unfollowPhoto' photo.id %}">Unfollow</a>
</div>
{% else %}
<div class="btn follow">
<a href="{% url 'followPhoto' photo.id %}">Follow</a>
</div>
{% endif %}
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('photo/<int:pk>/', views.viewPhoto, name='photo'),
path('photo/<int:pk>/follow/', views.follow, name='followPhoto'),
path('photo/<int:pk>/unfollow/', views.unfollow, name='unfollowPhoto'),
]