Included fields in Response in ModelSerializer - django-rest-framework

This is probably a very simple question, but I cant seem to solve it.
I have a ModelSerializer like so:
class UserSerializer(serializers.ModelSerializer):
# http -v POST http://127.0.0.1:8000/user/user-list/ email="f#b.de" password="123"
def create(self, validated_data):
user = UserModel.objects.create(
email=validated_data['email']
)
user.set_password(validated_data['password'])
user.is_active = False
user.save()
return user
class Meta:
model = UserModel
fields = (
'email',
'password',
'is_active',
'company',
'name',
)
read_only_fields = ('is_active',)
extra_kwargs = {
'password': {'write_only': True},
}
The corresponding view looks like this:
class UserDetail(APIView):
permission_classes = (permissions.IsAuthenticated,)
def get(self, request):
try:
user = request.user
serializer = UserMailSerializer(user)
print(serializer.data)
return Response(serializer.data, status=status.HTTP_200_OK)
except UserModel.DoesNotExist:
return Response(serializer.data, status=status.HTTP_401_UNAUTHORIZED)
When I sent a GET request the serializer.data will only return the 'email' address (I am using a custom User Model with the email as primary identification).
I want to return all the fields that are not specified as write_only. How Do I achieve this?

You are using UserMailSerializer serializer class in your views, which may be the wrong one. Use UserSerializer serializer instead
class UserDetail(APIView):
permission_classes = (permissions.IsAuthenticated,)
def get(self, request):
try:
user = request.user
serializer = UserSerializer(user) # change is here <<<<<
print(serializer.data)
return Response(serializer.data, status=status.HTTP_200_OK)
except UserModel.DoesNotExist:
return Response(serializer.data, status=status.HTTP_401_UNAUTHORIZED)

Related

Saving Single Post request to multiple database models

I have multiple users and I designed two models for two users and the rest is super user.
And I have the model User that holds common data for all users.
I want to save the patient post request to two different models: User and Patient; I tried these codes but, didn't work.
This is my Signup view
class PatientSignupView(generics.GenericAPIView):
serializer_class=PatientSignupSerializer
permission_classes = [
permissions.AllowAny
]
def post(self, request, *args, **kwargs):
user_serializer=self.get_serializer(data=request.data)
user_serializer.is_valid(raise_exception=True)
user=user_serializer.save()
return Response({
"user":UserSerializer(user, context=self.get_serializer_context()).data,
"patient":PatientSerializer(patient, context=self.get_serializer_context()).data,
"token":Token.objects.get(user=user).key,
"message":"account created successfully",
})
And here is my Signup Serializer class
class PatientSignupSerializer(serializers.ModelSerializer):
password_confirm = serializers.CharField(style={"input_type":"password"}, write_only=True)
class Meta:
model = User
fields = ['username', 'email', 'is_doctor', 'is_patient', 'password',
'password_confirm']
extra_fields = {
'password': {'write_only': True},
}
def save(self, **kwargs):
user=User(
username=self.validated_data['username'],
email=self.validated_data['email']
)
password=self.validated_data['password']
password_confirm=self.validated_data['password_confirm']
if password !=password_confirm:
raise serializers.ValidationError({"error":"password do not match"})
user.set_password(password)
user.is_patient=True
user.is_doctor=False
user.save()
PatientSerializer.serialized_data(user)
return user
Here is the PatientSerializer and UserSerializer class
from rest_framework import serializers
from .models import Patient, User
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['username','email','is_doctor','is_patient']
class PatientSerializer(serializers.ModelSerializer):
class Meta:
model = Patient
fields = ['first_name', 'middle_name', 'last_name', 'address', 'phone_number', 'birth_date', 'gender']
def serialized_data(self, user, **kwargs):
patient = Patient.objects.create(
user = user,
first_name=self.validated_data['first_name'],
middle_name = self.validated_data['middle_name'],
last_name = self.validated_data['last_name'],
address = self.validated_data['address'],
phone_number = self.validated_data['phone_number'],
birth_date = self.validated_data['birthh_date'],
gender = self.validated_data['gender']
)
return patient
Thank you!
It is solved like this
The signup view is:
class PatientSignupView(generics.GenericAPIView):
serializer_class=PatientSignupSerializer
def post(self, request, *args, **kwargs):
user_serializer=self.get_serializer(data=request.data)
user_serializer.is_valid(raise_exception=True)
user=user_serializer.save()
return Response({
"user":UserSerializer(user, context=self.get_serializer_context()).data,
"token":Token.objects.get(user=user).key,
"message":"account created successfully",
})
The serializer class will looks like:
class PatientSignupSerializer(serializers.ModelSerializer):
password_confirm = serializers.CharField(style={"input_type":"password"}, write_only=True)
first_name = serializers.CharField()
middle_name = serializers.CharField()
last_name = serializers.CharField()
address = serializers.CharField()
phone_number= serializers.CharField()
birth_date = serializers.DateTimeField()
gender = serializers.CharField()
class Meta:
model = User
fields = '__all__'
extra_fields = {'password': {'write_only': True},}
def save(self, **kwargs):
user=User(
username=self.validated_data['username'],
email=self.validated_data['email']
)
password=self.validated_data['password']
password_confirm=self.validated_data['password_confirm']
if password !=password_confirm:
raise serializers.ValidationError({"error":"password do not match"})
user.set_password(password)
user.is_patient=True
user.is_doctor=False
user.save()
Patient.objects.create(user=user,
first_name=self.validated_data['first_name'],
middle_name=self.validated_data['middle_name'],
last_name=self.validated_data['last_name'],
address=self.validated_data['address'],
phone_number=self.validated_data['phone_number'],
birth_date=self.validated_data['birth_date'],
gender=self.validated_data['gender'])
return user

How to return custom response in ListAPIView in django

I am creating an app where I want to return data in certain way, like in normal ListApiView we get direct all the field as response I dont want that
my views.py:
class ListFolders(ListAPIView):
queryset = Folder.objects.all()
serializer_class = FolderSerializer
filter_backends = [DjangoFilterBackend]
filterset_fields = ['id', 'name']
after hitting this endpoint if my model is empty i get simple [], i dont want that what I want is like this now I dont know how to do it.
{
"status": "success",
"data" : [],
"msg": "done"
}
You can override the list method with:
from rest_framework.response import Response
class ListFolders(ListAPIView):
queryset = Folder.objects.all()
serializer_class = FolderSerializer
filter_backends = [DjangoFilterBackend]
filterset_fields = ['id', 'name']
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response({
'status': 'success',
'data': serializer.data,
'msg': 'done'
})
or we can user a super call and override the data, so:
class ListFolders(ListAPIView):
queryset = Folder.objects.all()
serializer_class = FolderSerializer
filter_backends = [DjangoFilterBackend]
filterset_fields = ['id', 'name']
def list(self, request, *args, **kwargs):
response = super().list(request, *args, **kwargs)
response.data = {'status': 'success', 'data': response.data, 'msg': 'done'}
return response
this will also work if some mixin overrides the list logic, so this might be better from a software design point-of-view.

Auto generated model field in DRF serializer

I have a model Classroom which has a field code that is generated automatically
from django.utils.crypto import get_random_string
class Classroom(models.Model):
CODE_LEN = 16
teacher = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
name = models.CharField(max_length=250)
subject = models.CharField(max_length=50)
code = models.CharField(max_length=CODE_LEN, unique=True)
def save(self, *args, **kwargs):
while True:
self.code = get_random_string(length=16)
if not Classroom.objects.filter(code=self.code).exists():
break
super().save(*args, **kwargs)
The serializer for Classroom is -
class ClassroomSerializer(serializers.ModelSerializer):
class Meta:
model = Classroom
fields = ('teacher', 'name', 'subject', 'code')
This is the view for creating new Classroom -
class ListCreateClassroom(APIView):
def get(self, request):
classrooms = Classroom.objects.all()
serializer = ClassroomSerializer(classrooms, many=True)
return Response(serializer.data)
def post(self, request):
token = request.headers.get('Authorization').split()[1]
token_obj = AccessToken.objects.get(token=token)
teacher = token_obj.user.pk
request.data.update({"teacher": teacher})
serializer = ClassroomSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
When I send an api request to add new classroom, the request doesn't contain the code field because of which serializer.is_valid() throws error.
One way to solve it would be to create a code in the view and add it to the request.
But, is there a better way?
Simply set the code field in the serializer to read_only=True:
class ClassroomSerializer(serializers.ModelSerializer):
code = serializers.CharField(read_only=True)
class Meta:
model = Classroom
fields = ('teacher', 'name', 'subject', 'code')

"How to Add "Nested URL in DRF ,dynamic model viewset"

* i have * router.register(r'reseller/', views.UserViewSet)
and router.register(r'one/', views.OneLViewSet)
I want to make nested url like 'reseller/ or {pk}/one/
But i'm failed.
I tried adding DynamicRelationField to User Model but not worked.
my user_model
phone = models.CharField(_('phone number'), max_length=30, blank=True)
address = models.CharField(_('reseller address'), max_length=220, blank=True)
OneL model
id = models.AutoField(_('lottery id'), unique=False, primary_key=True, auto_created=True,)
lno = models.CharField(_('1000ks lottery'), max_length=8, unique=True)
name = models.CharField(_('customer name'), max_length=100, )
reseller = models.ForeignKey('lotto_app.User', on_delete=models.CASCADE)
user_serializer
class UserSerializer(serializers.DynamicModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'email', 'phone', 'address', )
oneL serializer
class OneLSerializer(serializers.DynamicModelSerializer):
reseller = fields.DynamicField(source='reseller.username', read_only=True)
class Meta:
model = OneL
fields = (
'id', 'lno', 'name', 'reseller', 'phone', 'address', 'nth', 'is_winner', 'prize_details', 'created_at',
'updated_at')
user dynamicviewset
class UserViewSet(DynamicModelViewSet):
permission_classes = (IsAdmin, IsAuthenticated)
model = User
queryset = User.objects.all()
serializer_class = UserSerializer
OneLviewSet
class OneLViewSet(DynamicModelViewSet):
permission_classes = (IsAuthenticated, IsOwner)
model = OneL
queryset = OneL.objects.all()
serializer_class = OneLSerializer
def create(self, request, *args, **kwargs):
serializer = OneLSerializer(data=request.data)
if serializer.is_valid():
serializer.save(reseller=request.user)
return Response(serializer.data)
def list(self, request, *args, **kwargs):
queryset = OneL.objects.filter(reseller=request.user)
serializer = OneLSerializer(queryset, many=True)
return Response(serializer.data)
I want to change this.url
router.register(r'reseller', views.UserViewSet)
router.register(r'one', views.OneLViewSet)
urlpatterns = [
path('api/saledatas/', include(router.urls))
]
TO THIS
router.register(r'reseller', views.UserViewSet)
router.register(r'reseller/{pk}/one', views.OneLViewSet) #or <int:pk>
urlpatterns = [
path('api/saledatas/', include(router.urls))
]
After change
error-- "Request URL: http://localhost:8000/api/saledatas/reseller/1/one/" Not Found!
And How to make http://localhost:8000/api/saledatas/reseller/1/one/ to be work.
create action in Userviewset
#action(detail=True, methods=["get"])
def one(self, request):
''' to get instance just do get_object() it'll give reseller instance '''
user = self.get_object()
ones = user.onel_set.all()
''' now you can work on one '''

i have a problem with the serializer that registers a person

i extending a user model and creating a serializer that can register a user but i think i have a problem with the Register serializer
i have tried changing the input but i cant tell where the problem is
class Register(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
address = models.CharField(max_length=70)
phone = models.IntegerField()
register_as = models.CharField(max_length=20)
# register serializer
class RegisterSerializer(serializers.ModelSerializer):
model = Register
fields = ('id', 'username', 'email', 'address', 'phone', 'register_as', '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
#register API
class RegisterAPI(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]
})
i expect it to return the fields in the user model plus the ones i added in the model

Resources