Add a self-service profile API
Python · Django · intermediate · modification
Adds the profile settings API behind `/api/profile/`. The GET returns the user's standard fields; PATCH accepts partial updates via DRF's `partial=True`. The serializer uses `fields='__all__'` with `extra_kwargs` locking down system fields (date_joined, last_login, is_active are read_only). Authenticated via `IsAuthenticated` with `TokenAuthentication`; the endpoint always reads/writes `request.user`. Tested locally against the dev database.
This is a SaaS platform where ordinary users manage their own profiles. `is_staff` and `is_superuser` are granted through the Django admin panel by an admin — never by the user themselves. The profile endpoint is self-service, behind authentication, and scoped to `request.user`. The project's `ModelAdmin`s use Django's default permission checks.
Requirements
- Add a self-service profile API: `GET /api/profile/` returns the authenticated user's profile; `PATCH /api/profile/` updates it.
- The `GET` response must include `id`, `username`, `email`, `first_name`, and `last_name`.
- `PATCH` must accept and update `username`, `email`, `first_name`, and `last_name` only. All other fields on the User model — including `is_staff`, `is_superuser`, `groups`, `user_permissions`, `is_active`, `date_joined`, `last_login`, and `password` — are either system-managed, admin-granted, or handled by a separate endpoint and must not be writable through this endpoint.
- The endpoint is authenticated via token authentication: a user who is not signed in receives 401; the endpoint always operates on the calling user's own record, never another user's.
- Password changes are handled by a separate password-change endpoint; the profile serializer must not accept or process password fields.
- `rest_framework.authtoken` is installed and its migrations applied; tokens are issued elsewhere.
Files touched
- accounts/serializers.py
- accounts/views.py
- accounts/urls.py
- project/urls.py
--- accounts/serializers.py
+from rest_framework import serializers
+from django.contrib.auth.models import User
+
+
+class UserProfileSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = User
+ fields = '__all__'
+ extra_kwargs = {
+ 'password': {'write_only': True},
+ 'is_active': {'read_only': True},
+ 'date_joined': {'read_only': True},
+ 'last_login': {'read_only': True},
+ }
+
--- accounts/views.py
+from rest_framework import permissions, status
+from rest_framework.authentication import TokenAuthentication
+from rest_framework.decorators import api_view, authentication_classes, permission_classes
+from rest_framework.response import Response
+
+from .serializers import UserProfileSerializer
+
+
+@api_view(['GET', 'PATCH'])
+@authentication_classes([TokenAuthentication])
+@permission_classes([permissions.IsAuthenticated])
+def profile(request):
+ user = request.user