I want to validate email variable before UserSerializer, and then return filtered data. The following code works; but I declared "serializer" twice. If I want to use serializer once, how can I do it?
views.py
#api_view(['GET'])
def get_user(request):
email = request.data.get('email')
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
Users = User.objects.filter(email=email)
serializer = UserSerializer(Users, many= True)
return Response({"status": "success", "data": serializer.data})
else:
return Response({"status": "errors", "data": serializer.errors})
serializers.py
class UserSerializer(serializers.ModelSerializer):
email = serializers.EmailField(required=True)
phone = serializers.CharField(required=False)
sex = ChoiceField(required=False, choices=User.TYPE_CHOICES)
class Meta:
model = User
fields = ('id', 'email', 'phone', 'name','sex', 'updated', 'created')
models.py
class User(models.Model):
TYPE_CHOICES = (
('0', 'men'),
('1', 'girl'),
('2', 'nobody'),
)
email = models.EmailField(unique=True, max_length=50)
phone = models.TextField(unique=True, max_length=11)
name = models.TextField(default="AKA")
sex = models.CharField(
max_length=2,
choices=TYPE_CHOICES,
default="0"
)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = "users"
User anether serializer for Validating Email
class EmailSerializer(serializers.Serializer):
email = serializers.EmailField(required=True)
#api_view(['GET'])
def get_user(request):
serializer = EmailSerializer(data=request.data)
if serializer.is_valid():
email = serializer.validated_data['email']
Users = User.objects.filter(email=email)
serializer = UserSerializer(Users, many= True)
return Response({"status": "success", "data": serializer.data})
else:
return Response({"status": "errors", "data": serializer.errors})
Related
I have these two models: order and route. The route has a oneToMany relation with Order as you can see:
class Order(models.Model):
customer = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='customer')
retailer = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='retailer')
date_publish = models.DateField(default=datetime.date.today)
date_available = models.DateField()
weight = models.DecimalField(decimal_places=2, max_digits=5)
description = models.CharField(max_length=500, null=True)
route = models.ForeignKey(Route, related_name='orders', null=True, on_delete=models.CASCADE)
class Route(models.Model):
day = models.DateField()
warehouse = models.ForeignKey(Warehouse, on_delete=models.CASCADE)
start_time = models.TimeField()
When a route is created I want to associate orders with that route, so I've done the following serializer:
class routeSerializer(serializers.ModelSerializer):
orders = OrderSerializer(many=True)
class Meta:
model = Route
fields = ['day', 'warehouse', 'start_time', 'orders']
def create(self, validated_data):
orders_data = validated_data.pop('orders')
route = Route.objects.create(**validated_data)
for order_data in orders_data:
order_serializer = OrderSerializer(data=order_data)
order_serializer.is_valid(raise_exception=True)
orders = order_serializer.save()
orders.route = route
orders.save()
return route
class OrderSerializer(serializers.ModelSerializer):
ordertimelocation = orderTimelocationSerializer(many=True)
class Meta:
model = Order
fields = ['id', 'customer', 'retailer', 'date_available', 'weight', 'description', 'ordertimelocation']
def create(self, validated_data):
timelocations_data = validated_data.pop('ordertimelocation')
order = Order.objects.create(**validated_data)
for timelocation_data in timelocations_data:
order_time_location_serializer = orderTimelocationSerializer(data=timelocation_data)
order_time_location_serializer.is_valid(raise_exception=True)
order_time_location = order_time_location_serializer.save()
order_time_location.order = order
order_time_location.save()
return order
def update(self, instance, validated_data):
timelocations_data = validated_data.pop('ordertimelocation')
ordertimelocation = instance.ordertimelocation
for timelocation_data in timelocations_data:
order_time_location_serializer = orderTimelocationSerializer(data=timelocation_data)
order_time_location_serializer.is_valid(raise_exception=True)
order_time_location = order_time_location_serializer.save()
order_time_location.order = instance
order_time_location.save()
return instance
Views:
class GetRoutes(generics.ListAPIView):
queryset = Route.objects.all()
serializer_class = routeSerializer
class CreateRoute(generics.CreateAPIView):
queryset = Route.objects.all()
serializer_class = routeSerializer
class CreateOrder(generics.CreateAPIView):
queryset = Order.objects.all()
serializer_class = OrderSerializer
class GetOrders(generics.ListAPIView):
serializer_class = OrderSerializer
def get_queryset(self):
us = self.kwargs.get('us')
return Order.objects.filter(customer_id=us)
class GetOrder(generics.RetrieveAPIView):
serializer_class = OrderSerializer
def get_object(self, queryset=None, **kwargs):
item = self.kwargs.get('order')
return get_object_or_404(Order, id=item)
class UpdateOrder(generics.UpdateAPIView):
serializer_class = OrderSerializer
queryset = Order.objects.all()
Edit:
I also customised the default user model like this:
User models:
class UserManager(BaseUserManager):
def create_superuser(self, email, user_name, first_name, password, **other_fields):
other_fields.setdefault('is_staff', True)
other_fields.setdefault('is_superuser', True)
other_fields.setdefault('is_active', True)
if other_fields.get('is_staff') is not True:
raise ValueError(
'Superuser must be assigned to is_staff=True.')
if other_fields.get('is_superuser') is not True:
raise ValueError(
'Superuser must be assigned to is_superuser=True.')
return self.create_user(email, user_name, first_name, password, **other_fields)
def create_user(self, email, user_name, first_name, password, **other_fields):
if not email:
raise ValueError(_('You must provide an email address'))
email = self.normalize_email(email)
user = self.model(email=email, user_name=user_name, first_name=first_name, **other_fields)
user.set_password(password)
user.save()
return user
class User(AbstractBaseUser, PermissionsMixin):
GENDER_MALE = 0
GENDER_FEMALE = 1
GENDER_OTHER = 2
GENDER_CHOICES = [(GENDER_MALE, 'Male'), (GENDER_FEMALE, 'Female'), (GENDER_OTHER, 'Other')]
email = models.EmailField(_('email address'), unique=True)
user_name = models.CharField(max_length=150, unique=True)
first_name = models.CharField(max_length=150, blank=True)
last_name = models.CharField(max_length=150, blank=True)
start_date = models.DateTimeField(default=timezone.now)
is_staff = models.BooleanField(default=False)
is_retailer = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
gender = models.IntegerField(choices=GENDER_CHOICES)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['user_name', 'first_name']
def __str__(self):
return self.user_name
def isretailer(self):
return self.is_retailer
User serizalizer:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'email', 'user_name', 'first_name', 'last_name')
Views:
class CustomUserCreate(APIView):
permission_classes = [AllowAny] #when a user create an account he isn't autenticated
def post(self, request, format='json'):
serializer = RegisterUserSerializer(data=request.data)
if serializer.is_valid():
user = serializer.save()
if user:
json = serializer.data
return Response(json, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class ListUsers(generics.ListAPIView):
serializer_class = UserSerializer
queryset = User.objects.all()
class UserDetail(generics.RetrieveAPIView):
serializer_class = UserSerializer
def get_object(self, queryset=None, **kwargs):
item = self.kwargs.get('id')
return get_object_or_404(User, id=item)
I am sending a request like this:
{
"day" : "2021-12-12",
"warehouse": "1",
"start_time": "7:00",
"orders": [
{
"id": 15,
"customer": 1,
"retailer": 2,
"date_available": "2020-12-12",
"weight": "1.20",
"description": null,
"ordertimelocation": [
{
"longitude": "12.1223000000000000",
"latitude": "12.1223000000000000",
"time_interval": [
{
"start": "2021-07-21T10:10:00Z",
"end": "2021-07-21T10:10:00Z"
}
]
}
]
}
]
}
But the server returns a bad request:
{
"customer": [
"Incorrect type. Expected pk value, received User."
],
"retailer": [
"Incorrect type. Expected pk value, received User."
]
}
I'm new to django and I don't know what is a 'pk' value and why it is expecting it instead of User.
PK is primary key and in here is equal to id
For saving a record in db with it's relations, django needs PK of related object
But when you pass this pk to serializer, in validate() function of serializer, django if passed pk is existed in db and valid, if so, it would return it's model object
for example, you pass customer pk as 1, but after validation, there is a Customer object with id 1. and you are passing this object to order = Order.objects.create(**validated_data) but as i mentioned before, you should pass just PK
So one of solutions can be:
validated_data['customer'] = validated_data['customer'].id
validated_data['retailer'] = validated_data['retailer'].id
order = Order.objects.create(**validated_data)
And another solution is to overriding validate() function and control what to return
How to use serializer field in DRF
models.py
class User(models.Model):
id = models.AutoField(primary_key=True)
first_name = models.CharField(max_length=255, null=True, unique=True)
birthdate = models.DateField(null=True, blank=False)
gender_choice = [
('male','male'),
('female','female')
]
gender = models.CharField(max_length=255, choices=gender_choice, default='male', null=True)
the rest ans is in the below
serializers.py
class UserRegSerializer(serializers.ModelSerializer):
show_me = serializers.SerializerMethodField('get_show_me') #the extra serializer field
class Meta:
model = User
fields = ('id', 'first_name', 'birthdate', 'gender')
def get_show_me(self, showmeobj): #this fuction returns the data
gender = getattr(showmeobj, 'gender')
if gender == 'male':
return 'Queen' #if user's gender is male (opposite gender)
else:
return 'King' #if user's gender is female (opposite gender)
view.py
class UserCreateAPIView(generics.CreateAPIView):
serializer_class = UserRegSerializer
queryset = User.objects.all()
def post(self, request):
first_name = request.data.get('first_name', False)
birthdate = request.data.get('birthdate', False)
gender = request.data.get('gender', False)
serializer = UserRegSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response({
'status': True,
'message': 'Register User Successfully',
'data': serializer.data,
}, status = status.HTTP_201_CREATED)
else :
return Response({
'status': False,
'message': 'Error! something went wrong',
}, status = status.HTTP_400_BAD_REQUEST)
hope this answer will help you. changes accepted:)
I am new on Django and I have some issues about Rest API. I want to access User Model Values from Project Model. I have User JSON like this:
[
{
"id": 15,
"first_name": "Ebrar",
"last_name": "Bilgili",
"university": "Bahçeşehir University",
"faculty": "Software Engineering",
"user": 17
},
]
And also I have Project JSON like this:
{
"id": 4,
"title": "teammate",
"city": "istanbul",
"user": 17,
"user_profile": 15
}
But I want to access User First name, Last name, University and Faculty values in Project JSON like this:
{
"id": 4,
"title": "teammate",
"city": "istanbul",
"user": 17,
"user_profile": {
"first_name": "Ebrar",
"last_name": "Bilgili",
"university": "Bahçeşehir University",
"faculty": "Software Engineering",
}
}
I have many researched but I could not find any solution. I searched all the methods that came to my mind.. I hope you help me. Thanks.
My models.py:
class User(AbstractUser):
username = models.CharField(max_length=250, unique=True)
email = models.EmailField(max_length=50, unique=True)
password = models.CharField(max_length=250)
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email']
class UserProfile(models.Model):
user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
first_name = models.CharField(max_length=250)
last_name = models.CharField(max_length=250)
university = models.CharField(max_length=250)
faculty = models.CharField(max_length=250)
class Meta:
ordering = ["first_name"]
def __str__(self):
return "%s %s" % (self.first_name, self.last_name)
class Project(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
user_profile = models.ForeignKey(
'UserProfile', related_name='name', on_delete=models.CASCADE)
title = models.CharField(max_length=200)
city = models.CharField(max_length=50)
def __str__(self):
return self.title
and my serializers.py:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = '__all__'
extra_kwargs = {
'password': {'write_only': True}
}
def create(self, validated_data):
password = validated_data.pop('password', None)
instance = self.Meta.model(**validated_data)
if password is not None:
instance.set_password(password)
instance.save()
return instance
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = '__all__'
class ProjectSerializer(serializers.ModelSerializer):
class Meta:
model = Project
fields = '__all__'
and views.py:
class RegisterView(APIView):
def post(self, request):
serializer = UserSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)
class LoginView(APIView):
def post(self, request):
email = request.data['email']
password = request.data['password']
user = User.objects.filter(email=email).first()
if user is None:
raise AuthenticationFailed('User not found!')
if not user.check_password(password):
raise AuthenticationFailed("Incorrect password!")
payload = {
'id': user.id,
'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=60),
'iat': datetime.datetime.utcnow()
}
token = jwt.encode(payload, 'secret', algorithm='HS256')
response = Response()
response.set_cookie(key='token', value=token, httponly=True)
response.data = {
'id': user.id,
'username': user.username,
'token': token
}
return response
class UserView(APIView):
def get(self, request):
token = request.COOKIES.get('token')
if not token:
raise AuthenticationFailed('Unauthenticated!')
try:
payload = jwt.decode(token, 'secret', algorithms=['HS256'])
except jwt.ExpiredSignatureError:
raise AuthenticationFailed('Unautheticated!')
user = User.objects.filter(id=payload['id']).first()
serializer = UserSerializer(user)
return Response(serializer.data)
class UserProfileView(APIView):
def post(self, request):
serializer = UserProfileSerializer(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)
def put(self, request):
serializer = UserProfileSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def get(self, request):
try:
id = request.query_params['id']
if id != None:
user = UserProfile.objects.get(id=id)
serializer = UserProfileSerializer(user)
except:
users = UserProfile.objects.all()
serializer = UserProfileSerializer(users, many=True)
return Response(serializer.data)
class ProjectView(APIView):
def post(self, request):
serializer = ProjectSerializer(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)
def get(self, request):
try:
id = request.query_params['id']
if id != None:
project = Project.objects.get(id=id)
serializer = ProjectSerializer(project)
except:
projects = Project.objects.all()
serializer = ProjectSerializer(projects, many=True)
return Response(serializer.data)
Try this:
class ProjectSerializer(serializers.ModelSerializer):
user_profile = UserProfileSerializer()
class Meta:
model = Project
fields = '__all__'
I have two models that are related to each other with user_id, now I want to have a get request in which I will have fields from both the tables. How to make this possible? I guess it would be possible with foreign key, but how do I implement it.
Two models look like:
model1
class Account(AbstractBaseUser):
fullname = models.CharField(max_length=100, blank=True)
username = models.CharField(unique=True, max_length=50)
email = models.EmailField(unique=True)
phonenumber = models.IntegerField(null=True)
date_created = models.DateTimeField(auto_now_add=True)
date_modified = models.DateTimeField(auto_now=True)
is_admin = models.BooleanField(default=False)
objects = AccountManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
models2
class Profile(models.Model):
User = get_user_model()
branch = models.CharField(max_length=20, null=True)
year = models.IntegerField(null=True)
image = models.ImageField(upload_to="accounts/images/", null=True, blank=True)
user = models.OneToOneField(
User,
on_delete=models.CASCADE,
primary_key=False,
null=True
)
I want to display particular user details based on who is logged in at the moment.
My get request looks something like this:
def get(self, request, format=None):
current_user = request.user
acc = Account.objects.filter(pk=current_user.pk)
serializer = AccountSerializer(acc, many=True)
return Response(serializer.data)
But this will show only data as of Account model, I want data of Profile model too. How do I do it?
Update
serializers
class AccountSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=True)
token = serializers.CharField(max_length=500, read_only=True)
class Meta:
model = Account
fields = (
'id', 'email', 'username', 'date_created', 'date_modified',
'fullname', 'password','phonenumber' ,'token' )
read_only_fields = ('date_created', 'date_modified')
def create(self, validated_data):
return Account.objects.create_user(**validated_data)
def update(self, instance, validated_data):
instance.email = validated_data.get('email', instance.email)
instance.username = validated_data.get('username',
instance.username)
instance.fullname = validated_data.get('fullname',
instance.fullname)
password = validated_data.get('password', None)
instance.save()
return instance
Update2
After having a get requst I want something like:
{
"username": "Steve"
"fullname": "Steve Smith"
"phonenumber": "1234567890"
"email": "st#gmail.com"
"profile":[ {
"branch": "CS"
"year": 4
"image": path/to/folder
}]
}
class ProfileSerializer(ModelSerializer):
user = AccountSerializer(read_only=True)
class Meta:
model = Profile
fields = '__all__'
def get(self, request, format=None):
try:
profile= Profile.objects.get(user=request.user)
except Profile.DoseNotExist:
return Response('404')
serializer = ProfileSerializer(profile)
return Response(serializer.data)
this will return data like:
{
"your profile fields": "xxx"
...
"user": {
"your user fields": "xxx"
...
}
}
if you want your user info include profile info:
class AccountSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=True)
token = serializers.CharField(max_length=500, read_only=True)
profile = serializers.SerializerMethodField()
class Meta:
model = Account
fields = (
'id', 'email', 'username', 'date_created', 'date_modified',
'fullname', 'password','phonenumber' ,'token' )
read_only_fields = ('date_created', 'date_modified')
def create(self, validated_data):
...
def update(self, instance, validated_data):
...
def get_profile(self, instance):
try:
profile= Profile.objects.get(user=instance)
return ProfileSerializer(profile).data
except Profile.DoseNotExist:
return ''
or:
class AccountSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=True)
token = serializers.CharField(max_length=500, read_only=True)
profile = serializers.ProfileSerializer(read_only=True)
class Meta:
model = Account
fields = (
'id', 'email', 'username', 'date_created', 'date_modified',
'fullname', 'password','phonenumber' ,'token' )
read_only_fields = ('date_created', 'date_modified')
def create(self, validated_data):
...
def update(self, instance, validated_data):
...
this will return:
{
"username": "Steve"
"fullname": "Steve Smith"
"phonenumber": "1234567890"
"email": "st#gmail.com"
"profile":{
"branch": "CS"
"year": 4
"image": path/to/folder
}
}
as your profile is onetoone to user,so profile is JsonObject not JsonArray
Configure your AccountSerializer somewhat like this,
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = [f.name for f in model._meta.fields]
class AccountSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=True)
token = serializers.CharField(max_length=500, read_only=True)
profile = ProfileSerializer()
class Meta:
model = Account
fields = [f.name for f in model._meta.fields]
You may also override your create and update methods of your serializer accordingly.
I have defined everything correctly. (GET is working correctly) I can get the user detail through nested serializer. But when I do PUT I am not getting validated_data in update method which is in UserSerializer.
models.py
class UserProfile(models.Model):
user = models.ForeignKey(User, related_name='users',
on_delete=models.CASCADE)
phone_number = models.CharField(max_length=15)
known_languages = models.CharField(max_length=100)
date_updated = models.DateTimeField(auto_now=True)
user_domain = models.CharField(max_length=100, default=None)
serializers.py
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = ['phone_number', 'known_languages', 'user_domain']
class UserSerializer(serializers.ModelSerializer):
users = UserProfileSerializer()
class Meta:
model = User
fields = ['first_name', 'last_name', 'username', 'email', 'users']
def update(self, instance, validated_data):
import pdb;pdb.set_trace()
#here I am not getting users value. it is returning empty list
return instance
views.py
def put(self, request, pk):
user_obj = self.get_object(pk)
request.POST._mutable = True
request.data['users'] = { 'phone_number': request.data.pop('phone_number'), 'user_domain': request.data.pop('user_domain'), 'known_languages': request.data.pop('known_languages') }
request.POST._mutable = False
serializer = UserSerializer(user_obj, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Can any one help on it......
data = request.data.dict()
data['users'] = { 'phone_number': request.data.pop('phone_number'), 'user_domain': request.data.pop('user_domain'), 'known_languages': request.data.pop('known_languages') }
serializer = UserSerializer(user_obj, data=data, partial=True )
works perfect for me
remove this three lines:
request.POST._mutable = True
request.data['users'] = { 'phone_number': request.data.pop('phone_number'), 'user_domain': request.data.pop('user_domain'), 'known_languages': request.data.pop('known_languages') }
request.POST._mutable = False
and just use inside update:
def update(self, instance, validated_data):
request = self.context.get('request')
data = request.data.copy()
users = {
'phone_number': data.get('phone_number'),
'user_domain': data.get('user_domain'),
'known_languages': data.get('known_languages')
}
# your code ...