Search code examples
djangodjango-modelsdjango-rest-frameworkdjango-filtered

Django Filters with Rest Framework Authentication message filtering strategy/issue in a Chat application


I have a Django DRF backend, with token user authentication implemented. The application itself is a chat which consists of public Lobbies and private Threads (Threads between particular users). Currently my models file includes Message model which has foreign key relation to the Lobby and Thread models and keeps one of those fields as Null, to determine wheter the particular message concerns private Thread or public Lobby.

So far I have been focusing on developing the public Lobbies, where the user was querying the messages based on the Lobby he was currently in.

After i finished the development of Lobbies and enabled the authentication, the frontend stopped filtering the messages by the Lobby title and just kept simply returning me all messages relevant to the current authenticated user - obviously disregarding any disctinction between Lobbies the messages are related to. After inspecting the actual API, i found out that when i enable authentication, the Filtering option completely disappears from the page.

how can I combat this issue? 

EDIT: i updated the post with some code
I would rather keep one Message model rather creating separate Message models for Lobby and Thread.

here are my models :

class Thread(models.Model):
    user1 = models.ForeignKey(Account, on_delete=models.PROTECT, related_name="user1")
    user2 = models.ForeignKey(Account, on_delete=models.PROTECT, related_name="user2")
    date = models.DateTimeField(auto_now_add=True, blank=False) 
    def __repr__(self):
        return f"user1: {self.user1} user2: {self.user2}"

class Message(models.Model):
    content = models.TextField(max_length=255, default="", blank=False, null=False)

    user = models.ForeignKey(Account, on_delete=models.PROTECT, related_name="user")
    date = models.DateTimeField(auto_now_add=True, blank=False)

    lobby = models.ForeignKey(Lobby, on_delete=models.CASCADE, related_name="messages", blank=True, null=True )
    thread = models.ForeignKey(Thread, on_delete=models.CASCADE, related_name="messages", blank=True,
    null=True )

class Lobby(models.Model):
    title = models.TextField(max_length=90, blank=False, null=False)
    thumb = models.ImageField(default='lobby.jpg')

here are the serializers :

class ThreadSerializer(serializers.ModelSerializer):
    user1 = serializers.CharField(source="user1.username")
    user1thumb = serializers.CharField(source="user1.accountimage.image.url")
    user2 = serializers.CharField(source="user2.username")
    user2thumb = serializers.CharField(source="user2.accountimage.image.url")
    class Meta:
        model= Thread
        fields = ["user1", "user2", "user1thumb", "user2thumb"]


class MessageSerializer(serializers.ModelSerializer):
    username = serializers.CharField(source='user.username')
    thumb = serializers.CharField(source='user.accountimage.image.url')
    class Meta:
        model= Message
        fields=['id','content', 'username', 'thumb']

class LobbySerializer(serializers.ModelSerializer):
    class Meta:
        model=Lobby
        fields="__all__"
        depth=2

and finally the views :

class ThreadView(viewsets.ModelViewSet):
    queryset = Thread.objects.all()
    serializer_class = ThreadSerializer

    def get_queryset(self):
        print(self.request.user)
        return Thread.objects.filter(Q(user1= self.request.user) | Q(user2=self.request.user))


class MessageView(viewsets.ModelViewSet):
    queryset = Message.objects.all()
    serializer_class = MessageSerializer
    filter_fields=('lobby__title',)



class LobbyView(viewsets.ModelViewSet):
    queryset = Lobby.objects.all()
    serializer_class = LobbySerializer

in my settings.py i enabled the Authentication globally:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES':[
        'rest_framework.authentication.TokenAuthentication', 
        'rest_framework.authentication.SessionAuthentication'
    ], 
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',

    )
}

Solution

  • Updated: Your problem has nothing to do with authorization. You are adding a

    "REST_FRAMEWORK"

    setting block, but not specifiying a filter backend to use

    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES':[
            'rest_framework.authentication.TokenAuthentication', 
            'rest_framework.authentication.SessionAuthentication'
        ], 
        'DEFAULT_PERMISSION_CLASSES': [
            'rest_framework.permissions.IsAuthenticated',
        ],
        'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend',]
    
    }
    

    and replace

    filter_fields = ('lobby__title',)

    with:

    filterset_fields = ['lobby__title',]
    

    P.S: you need to pip install django-filter if you haven't

    I hope this helps!