Unable to POST with ListCreateAPIView

Thank you very much for all your help.

We are currently using Django to create a blog with membership features. I would like to allow only members to post articles, but I can't use POST while logged in. When not logged in, POST is available.

What is wrong?

models.py

class Post(models.Model):
    title = models.CharField(max_length=100, blank=True, default='')
    content = models.TextField(blank=True, default='')

    def __str__(self):
        return self.title


class Category(models.Model):
    name = models.CharField(max_length=100, blank=False, null=True, default='')
    posts = models.ManyToManyField(Post, related_name='categories', blank=True)

    class Meta:
        verbose_name_plural = 'categories'

    def __str__(self):
        return self.name

serializers.py

class PostSerializer(serializers.ModelSerializer):

    class Meta:
        model = Post
        fields = ['id', 'title','content', 'categories']


class CategorySerializer(serializers.ModelSerializer):
    name = serializers.CharField(required=False, allow_null=True, allow_blank=True)
    posts = PostSerializer(many=True, read_only=True)
    new_posts = serializers.PrimaryKeyRelatedField(
            queryset=Post.objects.all(), many=True,
            write_only=True, required=False)

    class Meta:
        model = Category
        fields = ['id', 'name', 'posts', 'new_posts']

    def create(self, validated_data):
        category = Category.objects.create()
        category.name = validated_data.pop('name', None)
        new_posts = validated_data.pop('new_posts', None)
        category.posts.set(new_posts)
        category.save()
        return category

    def update(self, instance, validated_data):
        instance.name = validated_data.get('name', instance.name)
        instance.posts.set(validated_data.get('new_posts', instance.posts))
        instance.save()
        return instance

views.py

class PostList(generics.ListCreateAPIView):
    queryset = Post.objects.all()
    serializer_class = serializers.PostSerializer
    permission_classes = (IsAdmin,)
    # permission_classes = (AllowAny,)

permissions.py

class IsAdmin(permissions.IsAdminUser):

    def has_permission(self, request, view):
        if request.method in permissions.SAFE_METHODS:

            role_slug = None

            if not request.user.is_anonymous and request.user.role is not None:
                role_slug = request.user.role
            if role_slug:
                return bool(str(role_slug) == 'admin')
            else:
                return False

urls.py

urlpatterns = [

    path('posts/', views.PostList.as_view()),

]

settins.py

INSTALLED_APPS = [
    
    # ommited

    # 3rd party
    'rest_framework',
    'corsheaders',
    'djoser',

    # my apps
    'blogs.apps.BlogsConfig',

]

REST_FRAMEWORK = {

    'DEFAULT_PERMISSION_CLASSES'    : [
        'rest_framework.permissions.IsAuthenticated'
    ],

    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ),

}

POST request with login and response

{
    "detail": "You do not have permission to perform this action."
}

If you try to POST non-logged in...

{
    "id": 1,
    "title": "title ok.",
    "content": "content ok.",
}

Checking permissions.SAFE_METHODS, it seems that only the following are accepted (no POST).

('GET', 'HEAD', 'OPTIONS')

Is this a specification of ListCreateAPIView?

Yes, the safe methods are ('GET', 'HEAD', 'OPTIONS')

Please check the GitHub repo for rest_framework permissions. https://github.com/encode/django-rest-framework/blob/master/rest_framework/permissions.py

You can rewrite the permission class to the one below.:

def has_permission(self, request, view):
    if request.method in 'POST':
        role_slug = None
        if not request.user.is_anonymous and request.user.role is not None:
            role_slug = request.user.role
        if role_slug:
            return bool(str(role_slug) == 'admin')
        else:
            return False
Back to Top