Here's a serializer for registering a user.
class RegisterSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'email', 'password')
extra_kwargs = {'password': {'write_only': True}}
def create(self, validated_data):
user = User.objects.create_user(validated_data['username'], validated_data['email'], validated_data['password'])
return user
Here's the api view:
class RegisterView(generics.GenericAPIView):
serializer_class = RegisterSerializer
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.save()
return Response({
"user": UserSerializer(user, context=self.get_serializer_context()).data,
# "token": AuthToken.objects.create(user)[1]
})
On the api view, if I try to pass in a name that is exactly the same as an existing name, it will say that it already exists. However, I can still make the emails the same which I don't want. Is there a way to get it so that I can also tell DRF that I would like the email to have to be unique as well?
There are 2 options:
Enforcing the unique criterion on the serializer level:
from rest_framework import serializers
from rest_framework.validators import UniqueValidator
class RegisterSerializer(serializers.ModelSerializer):
email = serializers.EmailField(
validators=[UniqueValidator(queryset=User.objects.all())]
) # recommend using `get_user_model`
class Meta:
model = User # recommend using `get_user_model`
...
...
Using a custom User model that enforces the unique criterion on the model level. More details here:
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
email = models.EmailField(unique=True)
Note: The 2nd option also requires making changes to the settings and potentially other areas of the code if you reference the User model directly in your other models. If you are directly using User in other areas of your code, please take a look at using get_user_model.
Since you are using the ModelSerializer I think you can achieve it by having emails as unique field in the model itself and the serializer will handle the validation part for you.
Related
Perhaps the question is wrongly worded. I created user profile using Django through the following blocks of code:
models.py
class = Profile (models.Models):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
first name = models.CharField(max_length=50)
•••
serializer.py
class profile_serializer(serializers.ModerlSerializer)
class Meta:
model = Profile
fields = '__all__'
views.py
class profile_view(generics.ListCreateAPIView)
queryset = Profile.objects.all().filter(user=instance)
urls.py
urlspatterns = [path('profile', profile_view.as_view(), name='user_profile)
I definitely do not know how to implement the filter method to ensure that only the logged in user is retrieved. Or is there a better approach to obtain a specific user? If I use Project.objects.all() without the filter I get all the registered user as expected. But I don't know how to retrieve a particular user.
Hmm, I would do something like this:
from rest_framework.response import Response
from rest_framework import status, generics, permissions
class UserView(generics.GenericAPIView):
permission_classes = (permissions.IsAuthenticated,)
serializer_class = profile_serializer
def get(self, request):
user = request.user
return Response(profile_serializer(user).data,status=status.HTTP_200_OK)
Basically when a user is authenticated, their user is present in the request.
Here's the UserSerializer, comments was hard to format. (Ironically for a tech forum?)
from rest_framework import serializers
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = '__all__'
def get(self, instance):
return instance
def patch(self, instance, validated_data):
instance.model_method()
return super().update(instance, validated_data)
def create(self, validated_data):
user = self.context['request'].user
return super().update(user, validated_data)
And here's the profile_serializer:
class profile_serializer(serializers.ModerlSerializer):
user = UserSerializer(read_only=True)
class Meta:
model = Profile
fields = ('user', 'first_name', )
A newbie here. This is a Django related question.
How can I save a newly registered user to the User Model (auth.model)? Currently, the only account which is seen inside the admin panel -- under Users (Authentication and Authorization section) is the superuser (aka me).
I am using DRF (Rest framework) in order to register a user and not an HTML form.
models.py:
class Register(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
username = models.CharField(max_length = 100)
email = models.EmailField(max_length = 100)
password = models.CharField(max_length = 100)
def __str__(self):
return self.name
views.py:
class RegisterView(APIView):
def post(self, request, format=None):
serializer = RegisterSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response("Thank you for registering", status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
serializers.py:
from rest_framework import serializers
from .models import Register
class RegisterSerializer(serializers.ModelSerializer):
class Meta:
model = Register
fields = ['username', 'email', 'password']
When registering a new user via POSTMAN, the data is saved within the Register model (which is fine) but my issue is that it's not seen within the Users model.
Any feedback is highly appreciated. Thank you.
I am trying to implement authentication by combining Django Rest Framework and Angular, but I am suffering from user information update.
Angular sends it to Django with the PUT method, Django accepts the request with View "AuthInfoUpdateView".
class AuthInfoUpdateView(generics.GenericAPIView):
permission_classes = (permissions.IsAuthenticated,)
serializer_class = AccountSerializer
lookup_field = 'email'
queryset = Account.objects.all()
def put(self, request, *args, **kwargs):
serializer = AccountSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
At this time, Django accepts the request as below.
request.data = {'email': 'test3#example.com', 'username': 'test3', 'profile': 'i am test3'}
request.user = test3#example.com
And the serializer is implementing as below.
from django.contrib.auth import update_session_auth_hash
from rest_framework import serializers
from .models import Account, AccountManager
class AccountSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=False)
class Meta:
model = Account
fields = ('id', 'username', 'email', 'profile', 'password')
def create(self, validated_data):
return Account.objects.create_user(request_data=validated_data)
def update(self, instance, validated_data):
insntance.username = validated_data.get('username', instance.username)
insntance.email = validated_data.get('email', instance.email)
insntance.profile = validated_data.get('profile', instance.profile)
instance = super().update(instance, validated_data)
return instance
I tried to update the user from Angular in such an implementation, and the following response is returned.
"{"username":["account with this username already exists."],"email":["account with this email address already exists."]}"
It is thought that it is because you did not specify the record to update, but is there a way to solve it smartly without changing the current configuration so much?
I need your help.
use
class AuthInfoUpdateView(generics.UpdateAPIView):
use http method patch can partial_update your instance.
method PATCH -> partial update instance
method PUT -> update instance
I'm trying to implement a user profile in django rest framework.
Users should be able to request the profile of other users; however, since profiles contain sensitive information, I want to limit the information returned to non-owners and non-authenticated users when they request a profile.
I'm looking for a test that I can run inside my view methods that will determine which serializer to use for that request.
How can I do this?
# models.py
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, related_name='profile')
bio = models.CharField(max_length=100)
# dob is sensitive and should be protected...
dob = models.DateTimeField(blank=True, null=True)
My serializers would look like this:
# serializers.py
# Only for the owner...
class ProfileOwnerSerializer(serializers.HyperlinkedModelSerializer):
user = serializers.ReadOnlyField(source='user.id')
first_name = serializers.ReadOnlyField(source='user.first_name')
last_name = serializers.ReadOnlyField(source='user.last_name')
class Meta:
model = Profile
fields = (
'url',
'id',
'dob', #sensitive
'user',
'first_name',
'last_name', #sensitive
)
#For logged in users...
class ProfileSerializer(serializers.HyperlinkedModelSerializer):
user = serializers.ReadOnlyField(source='user.id')
first_name = serializers.ReadOnlyField(source='user.first_name')
class Meta:
model = Profile
fields = (
'url',
'id',
'bio',
'user',
'first_name',
)
#For everyone else...
class NonAuthProfileSerializer:
...
And I would try to distinguish between them here...
# views.py
class ProfileDetail(APIView):
"""
Retrieve a profile instance.
"""
# Can't user permission_classes bc I want to cater to different classes...
def get_object(self, pk):
try:
return Profile.objects.get(pk=pk)
except Profile.DoesNotExist:
raise Http404
def get(self, request, pk, format=None):
profile = self.get_object(pk)
# is_owner = ???
# is_authenticated = ???
# Define the serializer to be ProfileSerializer, ProfileOwnerSerializer, etc.
serializer = CorrectSerializer(
profile,
context={"request": request},
)
return Response(serializer.data)
I don't think it'd be too hard to check if the request was sent by the owner, since I can just cross-reference the profile id.
However, how would I check whether the user was logged in or not? I've tried looking at request.user.auth in the view method, but that seems to be None whether or not the request is logged in.
I think you should be checking with request.user.is_authenticated(). To fill in the blanks:
is_owner = profile.user == request.user
is_authenticated = request.user.is_authenticated()
I am beginning to use the Django Rest Framework and making a user registration process. I have used this to create a rudimental version and it works fine, but I get the hashed password back in my response, which I don't want. Tried using write_only_fields, but that made no difference.
This is my current serializer:
class UserSerializer(serializers.ModelSerializer):
def create(self, validated_data):
user = User(email=validated_data['email'], username=validated_data['username'])
user.set_password(validated_data['password'])
user.save()
return user
class Meta:
model = User
fields = ('id', 'username', 'email', 'password',)
write_only_fields = ('password',)
How can I prevent DRF to return the created password in the response?
Declare the password field explicitly like this and rest of the code will remain same:
password = serializers.CharField(write_only=True)
Other method can be to delete the password from the to_representation method:
def to_representation(self, instance):
ret = super(MySerializer, self).to_representation(instance)
del ret['password']
return ret
You may use different serializers for creating a user and for showing the user's data. For example, you may inherit from the basic UserSerializer class and thus create something like ReadOnlyUserSerializer, where you completely remove the password field from the Meta.fields property.
The only thing you will need to do is to switch between these serializers properly in ViewSets or whatever you use to render the output.