Search code examples
djangopython-3.xdjango-viewsdjango-authentication

@login_required decorator within an 'if' statement?


I have a model 'Playlist' with an attribute 'private' that can be True or False (and therefore private or public). I want to use the @login_required decorator only if 'private = False', but can't figure out how to achieve this result. Here is my models.py file:

class Playlist(models.Model):
    """Allow a user to create a customized list of songs."""
    name = models.CharField(max_length=100)
    image = models.ImageField(upload_to='playlists/%Y/%m/%d', blank=True, null=True)
    songs = models.ManyToManyField('Song')
    description = models.TextField(blank=True, null=True, max_length=1000)
    date_added = models.DateTimeField(auto_now_add=True)
    private = models.BooleanField()

    def __str__(self):
        """String for representing the model object."""
        return self.name

    def get_absolute_url(self):
        """Returns the url to access a detail record for this song."""
        return reverse('playlist-detail', args=[str(self.id)])

And my views.py file:

def playlist(request, playlist_id):
    """Show a single playlist and associated data."""
    playlist = Playlist.objects.get(id=playlist_id)
    songs = playlist.songs.all()
    for song in songs:
        if song.url:
            song.video_id = song.url.replace("https://www.youtube.com/watch?v=", "")

    context = {'playlist': playlist, "playlist_songs": songs}

    return render(request, 'great_songs_app/playlist.html', context)

I stumbled across a similar thread but there was no answer to the problem:Conditionally apply login_required decorator in Django

I imagine code looking something like what the OP posted, with the view function being preceded by:

if playlist.private == True:
    @login_required
    ...

But obviously that won't work. Any ideas?


Solution

  • Rather than trying to apply @login_required, you could simply let the view undecorated and do something like the following, checking whether the user is authenticated:

    from django.shortcuts import redirect
    from django.conf import settings
    
    def playlist(request, playlist_id):
        """Show a single playlist and associated data if user is authenticated."""
        playlist = Playlist.objects.get(id=playlist_id)
        if not playlist.private or (playlist.private and request.user.is_authenticated):
            songs = playlist.songs.all()
            for song in songs:
                if song.url:
                    song.video_id = song.url.replace("https://www.youtube.com/watch?v=", "")
    
            context = {'playlist': playlist, "playlist_songs": songs}
    
            return render(request, 'great_songs_app/playlist.html', context)
        else:
            redirect(settings.LOGIN_URL)