"detail": "Authentication credentials were not provided." when trying to access list view as admin. Django REST framework

28 views Asked by At

I have this simple view I built using Django REST framework:

class ProductListCreateAPIView(
        StaffEditorPermissionMixin,
        generics.ListCreateAPIView):

    queryset = Product.objects.all()
    serializer_class = ProductSerializer

    def perform_create(self, serializer):
        print(serializer.validated_data)
        name = serializer.validated_data.get('name')
        description = serializer.validated_data.get('description') or None
        if description is None:
            description = name
        serializer.save(description=description)

here is the StaffEditorPermissionMixin:

class StaffEditorPermissionMixin():
    permission_classes = [permissions.IsAdminUser, IsStaffEditorPermission]

and here is the ProductSerializer:

class ProductSerializer(serializers.ModelSerializer):
    edit_url = serializers.SerializerMethodField(read_only=True)
    url = serializers.HyperlinkedIdentityField(
        view_name='product-details',
        lookup_field='pk',
    )
    class Meta:
        model = Product
        fields = [
            'url',
            'edit_url',
            'name',
            'description',
            'price',
            'sale_price',
        ]

    def get_edit_url(self, obj):
        # return f"/api/v2/products/{obj.pk}/"
        request = self.context.get('request')

        if request is None:
            return None
        return reverse("product-edit", kwargs={"pk": obj.pk}, request=request)

and just in case here's products.url:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.ProductListCreateAPIView.as_view(), name='product-list'),
    path('<int:pk>/update/', views.ProductUpdateAPIView.as_view(), name='product-edit'),
    path('<int:pk>/delete/', views.ProductDestroyAPIView.as_view()),
    path('<int:pk>/',  views.ProductDetailAPIView.as_view(), name='product-details'),
]

and just in case here's the source urls.py:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('api.urls')),
    path('api/products/', include('product.urls')),
    path('api/v2/', include('rest_practice.routers')),
]

so when I am logging in as admin to http://127.0.0.1:8000/admin/ and I head to http://127.0.0.1:8000/api/products/ I cannot access the product list and receiving

HTTP 401 Unauthorized
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
WWW-Authenticate: Bearer

{
    "detail": "Authentication credentials were not provided."
}

So I don't know why authentication is not working so any help would be appreciated

EDIT: I am using Django's own admin panel

2

There are 2 answers

2
Omar Gaber El-Sayed On

I think the question is a little bit unclear on whether you mean Django's own admin panel or you have one of your own that calls that endpoint. This is happening because while going to that page from the admin, the request doesn't include your user's token.

That being said, I think its better to disassociate the ListCreateAPIView from the admin pages (if you're talking about Django's own admin pages), so that the view would be the logic serving the API calls. To do that, all you have to modify is the admin.py file within your app folder to be something like this:

from django.contrib import admin
from .models import Product

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    list_filter = ['some_column',...]
    list_display = [...]

Hope this helps.

0
Abdullah Shekfeh On

I have forgotten to change DEFAULT_AUTHENTICATION CLASSES where I had it set up like this

auth_classes = [
    "rest_framework.authentication.SessionAuthentication",
    "api.authentication.TokenAuthentication",
]

if DEBUG:
    auth_classes = ["api.authentication.TokenAuthentication"]

REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": auth_classes,
    "DEFAULT_PERMISSION_CLASSES": [
        "rest_framework.permissions.IsAuthenticatedOrReadOnly",
        "rest_framework.permissions.IsAdminUser",  # ONLY GET METHODS
    ],
}

where it should be something like this:

REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": [
        "rest_framework.authentication.SessionAuthentication",
        "api.authentication.TokenAuthentication",
    ],
    "DEFAULT_PERMISSION_CLASSES": [
        "rest_framework.permissions.IsAuthenticatedOrReadOnly",
        "rest_framework.permissions.IsAdminUser",  # ONLY GET METHODS
    ],
}