Method POST not allowed [DRF]

Viewed 320

When I try to create an UserProfile for User with user_id=2 using the url http://localhost:8000/api/user/profile/2 I get detail : not found

models.py:

class User(AbstractBaseUser, PermissionsMixin, Base):
    user_id = models.AutoField(primary_key=True)
    email = models.EmailField(db_index=True, max_length=100, unique=True)
    is_advisor = models.BooleanField(default=False)
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)
    is_active = models.BooleanField(default=False)

UserProfile:

class UserProfile(Base):
    profile_id = models.AutoField(primary_key=True)
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='user_profile')
    first_name = models.CharField(null=True, blank=True, max_length=100)
    last_name = models.CharField(null=True, blank=True, max_length=100)

UserProfileSerializer:

class UserProfileSerializer:
    class Meta:
        model = UserProfile
        fields = "__all__"

views.py:

class UserProfileViewSet(viewsets.ModelViewSet):
    queryset = UserProfile.objects.all()
    parser_classes = (MultiPartParser, )
    serializer_class = UserProfileSerializer
    lookup_field = 'user'

urls.py:

router = SimpleRouter(trailing_slash=False)
router.register(r'user', UserViewSet)
router.register(r'user/profile', UserProfileViewSet)
urlpatterns = [
    path(r'user/activate', ActivateUser.as_view(), name='activate_user'),
] + router.urls
3 Answers

With ModelViewSets, api/user/profile/2 corresponds to a detail view. This implies that the object should already exist.

Since there is no profile yet for user 2 (you wanted to create one), you get the 404/not found error.

There are a number of ways to resolve this, but to support creation of a profile for a user with no changes required in your current code, you can simply just post to /api/user/profile with the user id in the request data so:

POST: http://localhost:8000/api/user/profile

{
    "user": 2,
    "first_name": "Tannisha",
    "last_name": "Hill"
}

I am seeing quite a few minor beginner errors. I recommend that you take smaller steps and ensure each part is working as you move forwards.

Make sure your User model is set in the settings to be the AUTH_USER_MODEL and check you can create and see at least one user in the shell before you even worry about DRF serialization etc.

Then, as you have a custom user model, it is highly unlikely that you'll need or want a UserProfile object - that typically exists to extend an existing user model and as you've got your own model you can probably just extend that to keep things as simple as possible.

Get the user fields how you want them and experiment creating users in the shell. The django shell is an excellent development and learning tool.

Once you can make users in the shell and list them (with e.g. User.objects.all()), you can look to adding a serializer. That will need to inherit some behavior from a suitable DRF default serializer. Add it to your urls and test it using the DRF api (you'll need 'rest_framework' in your settings).

You can test your serializer in the shell too but the DRF api tester is very handy when you are getting started so you might want to add the url straight away and use that. You'll be able to look at and post your changes. The lookup_field is not necessary.

When adding urls for models, don't use slashes to break up the model name. Slashes indicate separate parts and the model name is a single meaningful part of the url. You can use underscores if you want to break up the name (e.g. "api/user_profile/").

Leave DRF trailing slashes in unless you have a very good reason not to want them. Django will automatically append them as part of its error handling if you forget to type them.

I hope this is enough to get you unstuck.

urlpatterns = [ path('', include(router.urls)), …… ]

Related