"How to Add "Nested URL in DRF ,dynamic model viewset" - django-rest-framework

* 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 '''

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 get the nested objects in DRF

I have two models Role and User. User model has a foreign-key field associated with model Role.
Model Role
class Role(models.Model):
role_name = models.CharField(max_length=255, blank=False, unique=True)
def __str__(self):
return 'Role Object ({})'.format(self.id, self.role_name)
Model User
class User(AbstractBaseUser, PermissionsMixin):
first_name = models.CharField(max_length=255, blank=False)
last_name = models.CharField(max_length=255, blank=False)
email = models.EmailField(max_length=255, blank=False, unique= True)
phone_number = models.BigIntegerField(blank=False, unique= True)
password = models.TextField(blank=False)
company_name = models.CharField(max_length=255, null=True, unique=True)
is_active = models.BooleanField(default= False)
role = models.ForeignKey(Role, related_name='group_name', on_delete=models.CASCADE, blank=False)
business = models.ForeignKey(Businesses, on_delete=models.CASCADE, null=True)
objects = UserManager()
USERNAME_FIELD = 'email'
def __str__(self):
return 'User Object ({})'.format(self.id)
Using ModelSerializer and ListAPIView I want to get the list of all the users as shown below -
{
"first_name": "",
"last_name":"",
"email":"",
"phone_number":,
"is_active":"",
"role":{
"id":1,
"role_name": "Admin"
}
}
Also, I have created serializers -
class AdminSerializer(serializers.ModelSerializer):
role = RoleSerializer(read_only=True)
class Meta:
model = User
fields = ['id', 'first_name', 'last_name', 'email', 'phone_number', 'password', 'role', 'is_active' ]
read_only_field = ['role_name']
extra_kwargs = {
'password':{
'write_only':True
},
'is_active':{
'required':False
}
}
def create(self, validated_data):
return User.objects.create_user(**validated_data)
class RoleSerializer(serializers.ModelSerializer):
class Meta:
model = Role
field = ['id', 'role_name']
What exactly should I do to my serializer to achieve desire output. What exactly should I write in my ListAPIView() what a ListAPIVIew returns.
class UsersListAPIView(ListAPIView):
queryset = User.objects.all()
serializer_class = AdminSerializer
def list(self, request):
queryset = self.get_queryset().filter(role=request.query_params.get['id']).prefetch_related("group_name")
serializer = AdminSerializer(queryset, many=True)
return Response(serializer.data)
This returns an error -
TypeError: 'method' object is not subscriptable

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

Included fields in Response in ModelSerializer

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)

Create model with foreign key and return serialized response

I'm trying to create a new note via a POST request that looks like this: {content: "hello world", user: 1} with a response that looks like this: { id: 1, content: "hello world", user: { id: 1, first_name: "Homer", last_name: "Simpson" }.
After reading at the other foreign key questions I've been able to create the note and get back something like: { id: 1, content: "hello world", user: 1 } but I really need the additional user information.
I attempted to modify the response using the to_representation like so:
class NotePOSTSerializer(serializers.ModelSerializer):
class Meta:
model = Note
fields = ('id', 'content', 'timestamp', 'user')
def to_representation(self, instance):
rep = super().to_representation(instance)
"""Convert `status` to human-readable."""
rep['user'] = UserSerializer(id=rep['user'])
return rep
but I got this error: TypeError: Object of type ModelState is not JSON serializable
This is what I've got so far. Thanks in advance!
models.py
class Article(models.Model):
id = models.PositiveSmallIntegerField('Article Id', null=True)
title = models.CharField('Title', max_length=100)
content = models.TextField('Description', blank=True, null=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
class Note(models.Model):
id = models.PositiveSmallIntegerField('Note Id', null=True)
content = models.TextField('Content', blank=True)
timestamp = models.DateTimeField('Timestamp', auto_now_add=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
views.py
class ArticleListView(viewsets.ModelViewSet):
serializer_class = ArticleSerializer
queryset = Article.objects.all()
class NoteListView(viewsets.ModelViewSet):
serializer_class =NoteSerializer
queryset = Note.objects.all()
def get_serializer_class(self):
assert self.serializer_class is not None, (
"'%s' should either include a `serializer_class` attribute, "
"or override the `get_serializer_class()` method."
% self.__class__.__name__
)
if self.request.method in ('POST', 'PUT'):
return NotePOSTSerializer
else:
return self.serializer_class
serializers.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'first_name', 'last_name', 'email')
class NoteSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = Note
fields = ('id', 'content', 'timestamp', 'user')
class NotePOSTSerializer(serializers.ModelSerializer):
class Meta:
model = Note
fields = ('id', 'content', 'timestamp', 'user')
class ArticleSerializer(serializers.ModelSerializer):
notes = NoteSerializer(many=True, read_only=True)
class Meta:
model = Article
fields = ('id', 'title', 'content', 'created', 'updated', 'notes')
I'm getting completely different errors, so I will just provide working code
def to_representation(self, instance):
rep = super().to_representation(instance)
rep['user'] = UserSerializer(instance=User.objects.get(pk=instance.user_id)).data
# UserSerializer(instance=instance)
return rep

Resources