Adam
Adam

Reputation: 2552

AttributeError: 'UserViewSet' object has no attribute 'user'

I've currently got an API endpoint that works as I would expect it when I send a request to it manually via Postman. The way I do so is running:

GET /user/?fromid=1&toid=100

I am now trying to setup unit tests using factory-boy but I'm not able to get it to work due to an error.

So far, the important files with regards to the unit tests that I have are:

urls.py

from django.urls import include, path
from rest_framework import routers
from rest_framework.schemas import get_schema_view

import views

router = routers.DefaultRouter()
router.register(r"user", views.UserViewSet, basename='user')

urlpatterns = [
    path('user', views.UserViewSet.as_view({'get': 'user'}), name='user')
]

test_user.py

import factory
from django.test import Client, TestCase
from django.urls import reverse
from factory import DjangoModelFactory, Faker
from models.user import User

class UserFactory(DjangoModelFactory):
    class Meta:
        model = User

class UserViewSetTest(TestCase):
    def setUp(self):
        client = Client()

    def test_user_list(self):
        response = self.client.get(reverse('user'), format='json')
        self.assertEqual(response.status_code, 200)

When running pytestusing the above, I get an error:

AttributeError: 'UserViewSet' object has no attribute 'user'

I have a feeling that the parameters in the URL aren't allowing me to call it as is from my unit test, but I'm not sure.

As I mentioned, I've been able to send a request via Postman to the API so I'm not sure it's useful to show my complete code (i.e. the ViewSet, models and serializers). For what it's worth, the viewset currently just returns a list of users in Json format.

EDIT:

I've been able to recreate the error manually on Postman. If I create a request without specifying the URL parameters, like the following:

GET /user

I get the same error manually

AttributeError: 'UserViewSet' object has no attribute 'user'

As a result, I have tried to update my reverse command within the unit test to include the URL parameters, as such:

response = self.client.get(reverse('user'), kwargs={'fromid':1, 'toid': 100}, format='json')

But I'm still getting the same original error.

EDIT2:

I think part of the problem is with the way I'm calling reverse. The kwargs parameter wasn't in the actual reverse function. I've modified it to be as such:

response = self.client.get(reverse('user', kwargs={'fromid':1, 'toid': 100}), format='json')

Now my error is to do with the url path (I believe) as now I'm getting a new error which is:

Reverse for 'user' with keyword arguments '{'fromid':1, 'toid': 100}' not found. 1 pattern(s) tried: ['/user$']

My (hopefully final) question is how do I specify multiple parameters in my path to accept the kwargs? My endpoint is currently accepted to parameters (fromid and toid) in the URL, so I need to specify that in the path elements below. How can I do so?

router.register(r"user", views.UserViewSet, basename='user')
    
urlpatterns = [
    path('user', views.UserViewSet.as_view({'get': 'user'}), name='user')
]

Upvotes: 1

Views: 1077

Answers (1)

Ehsan Nouri
Ehsan Nouri

Reputation: 2040

drf routers will use a name like

basename+'-list'

for generated url with list actions. so your code should be:

response = self.client.get(reverse('user-list', kwargs={'fromid':1, 'toid': 100}), format='json')

Upvotes: 1

Related Questions