Get serializer data by foreign key - django

I need to pass data from EmployeeSerializer to VacationSerializer as nested json. This is my serializer.py:
class EmployeeSerializer(serializers.ModelSerializer):
class Meta:
model = Employee
fields = ('pk', 'first_name', 'surname', 'patronymic', 'birthday', 'email', 'position', 'phone_number')
class VacationSerializer(serializers.ModelSerializer):
class Meta:
model = Vacation
fields = ('pk', 'start_date', 'end_date', 'employee_id', 'employee')
and my models.py:
class Employee(models.Model):
first_name = models.CharField("Name", max_length=50)
surname = models.CharField("surname", max_length=50)
patronymic = models.CharField("patronymic", max_length=50)
birthday = models.DateField()
email = models.EmailField()
position = models.CharField("position", max_length=128)
phone_number = models.CharField("phone", max_length=12, null=True)
is_deleted = models.BooleanField(default=False)
def __str__(self):
return f'{self.surname} {self.first_name} {self.patronymic}'
class Vacation(models.Model):
start_date = models.DateField()
end_date = models.DateField()
employee_id = models.ForeignKey(Employee, related_name='employee', on_delete=models.PROTECT, default=-1)
def __str__(self):
return f'{self.start_date} - {self.end_date}'
#property
def date_diff(self):
return (self.end_date - self.start_date).days
in views.py I have this:
#api_view(['GET', 'POST'])
def vacations_list(request):
if request.method == 'GET':
data = Vacation.objects.all()
serializer = VacationSerializer(data, context={'request': request}, many=True)
return Response(serializer.data)
I've tried this:
class VacationSerializer(serializers.ModelSerializer):
employee = EmployeeSerializer(read_only=True, many=True)
class Meta:
model = Vacation
fields = ('pk', 'start_date', 'end_date', 'employee_id', 'employee')
but it doesn't show me even empty nested json, it shows me only VacationSerializer data.
I easily can access VacationSerializer from EmployeeSerializer using PrimaryKeySerializer or any other serializer and get nested json where VacationSerializer data is nested in EmployeeSerializer data. But I want it opposite - nested json of employee related to this vacation. How to achieve this?

That is because of the naming on your model. You need to serialize the 'employee_id' field:
class VacationSerializer(serializers.ModelSerializer):
employee_id = EmployeeSerializer()
class Meta:
model = Vacation
fields = ('pk', 'start_date', 'end_date', 'employee_id')

Related

retrieving the last instance of a model in another model's modelSerializer in django rest framework

I am creating rest APIs for a website in which users can purchase one of the provided subscriptions.
In this website there is a user-info API which returns the information about the logged in user which can be used to show their info on the website.
The problem is that, the mentioned API's serializer is a modelSerializer on the "User" model and the information that I want to return is the instance of "Subscription" model which the latest instance of "SubPurchase" model refers to.
These are my serializers, models and views.And I need to somehow return the user's current subscription's ID and name along with the user's information. If you have any further questions, ask me in the comments and I'll answer them.
# models.py
class User(AbstractBaseUser, PermissionsMixin):
userID = models.AutoField(primary_key=True)
username = models.CharField(max_length=100, unique=True, validators=[RegexValidator(regex="^(?=[a-z0-9._]{5,20}$)(?!.*[_.]{2})[^_.].*[^_.]$")])
email= models.EmailField(max_length=100, unique=True, validators=[EmailValidator()])
name = models.CharField(max_length=100)
isSuspended = models.BooleanField(default=False)
isAdmin = models.BooleanField(default=False)
emailActivation = models.BooleanField(default=False)
balance = models.IntegerField(default=0)
objects = UserManager()
USERNAME_FIELD = 'username'
class Subscription(models.Model):
subID = models.AutoField(primary_key=True)
nameOf = models.CharField(max_length=50)
price = models.PositiveIntegerField()
salePercentage = models.PositiveIntegerField(default=0)
saleExpiration = models.DateTimeField(default=datetime.datetime.now, blank=True)
def __str__(self):
return f"{self.nameOf}"
class SubPurchase(models.Model):
price = models.PositiveIntegerField()
dateOf = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
subscription = models.ForeignKey(Subscription, null=True, on_delete=models.SET_NULL)
def __str__(self):
return self.subscription
# serializers.py
class UserInfoSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
fields = ('userID', 'username','email', 'name', 'balance', 'emailActivation', 'isSuspended')
read_only_fields = ('userID', 'username','email', 'name', 'balance', 'emailActivation', 'isSuspended')
# views.py
class UserInfoViewSet(viewsets.ModelViewSet):
queryset = get_user_model().objects.all()
serializer_class = UserInfoSerializer
def get_queryset(self):
uID = getattr(self.request.user,'userID')
return get_user_model().objects.filter(userID=uID)
def get_object(self):
uID = getattr(self.request.user,'userID')
return self.queryset.filter(userID=uID)
Again, I need to change the UserInfoSerializer in a way that would give me the user's current subscription's name, ID and expiration date which would be 30 days after the purchase date
If you are only interested in the returned data, you can override the function to_representation of your serializer and create a serializer for your related model. If I understood correctly, the current subscription of your user is the last one (if sorted by "dateOf"). So something like that could do the trick
class SubscriptionSerializer(serializers.ModelSerializer):
class Meta:
model = Subscription
fields = ('nameOf', 'id', 'saleExpiration ')
class UserInfoSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
fields = ('userID', 'username','email', 'name', 'balance', 'emailActivation', 'isSuspended')
read_only_fields = ('userID', 'username','email', 'name', 'balance', 'emailActivation', 'isSuspended')
def to_representation(self, instance):
data = super().to_representation(instance)
current_subs = instance.subpurchase_set.order_by('dateOf').last().subscription
data['current_subscription'] = SubscriptionSerializer(instance=current_subs).data
return data
you can use NestedSerializers to achieve what you are looking for
basically, nested serialization is a method in which you can return, create, put..., into a model from another model, it goes like this..
models.py
class User(AbstractBaseUser, PermissionsMixin):
....
#user model data
class SubPurchase(models.Model):
...
user = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE)
serializers.py
class SubscriptionSerializer(serializers.ModelSerializer):
class Meta:
model = Subscription
fields =["anyfield you wanna include"]
class SubPurchaseSerializer(serializers.ModelSerializer):
class Meta:
model = SubPurchase
fields =["anyfield you wanna include"]
class UserInfoSerializer(serializers.ModelSerializer):
subpurchace = SubPurchaseSerializer()
subscription= SubscriptionSerializer() #later included in the fields of this serializer
class Meta:
model = get_user_model()
fields = ('userID','subpurchace', 'subscription', 'username','email', 'name', 'balance', 'emailActivation', 'isSuspended')
read_only_fields = ('userID', 'username','email', 'name', 'balance', 'emailActivation', 'isSuspended')

Using serializer how to Create Category in django rest framework

I want to create category in django rest framework with serializer.
name will be provided from frontend input field.
I'm getting the user_id from user = request.user and cafe_id from request.user.cafe.
I need to create category with name, user_id and cafe_id.
How can I do this?
here is the model
class Category(models.Model):
user = models.ForeignKey(User, related_name="cat", blank=True, null=True, on_delete=models.CASCADE)
cafe = models.ForeignKey(Cafe, related_name="category", blank=True, null=True, on_delete=models.CASCADE)
name = models.CharField(max_length=255)
class Meta:
verbose_name_plural='Categories'
def __str__(self):
return self.name
Here is the serializer
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ['name']
and the views.py
#api_view(['POST'])
#permission_classes((IsAuthenticated,))
def categoryCreate(request):
user = request.user
user_id = Category(user = user)
cafe = request.user.cafe
cafe_id = Category(cafe = cafe)
serializer = CategorySerializer(user_id, cafe_id, data=request.data)
data={}
if serializer.is_valid():
serializer.save()
data["success"] = "Category Has Been Created!"
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Thank You In Advance
you can to this
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = "__all__"
class CafeSerializer(serializers.ModelSerializer):
class Meta:
model = Cafe
fields = "__all__"
class CategorySerializer(serializers.ModelSerializer):
user = UserSerializer(read_only=True)
cade = CafeSerializer(read_only=True)
class Meta:
model = Category
fields = ['name', 'user', 'cafe']

How i can serialized data to json with drf serializer

I have data models like:
from django.db import models
class Student(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
email = models.EmailField()
def __str__(self):
return self.first_name + ' ' + self.last_name
class Course(models.Model):
name = models.CharField(max_length=255)
description = models.TextField()
start_date = models.DateField(null=True)
end_date = models.DateField(null=True)
def __str__(self):
return self.name
class CourseParticipant(models.Model):
course = models.ForeignKey(Course, related_name='courses', on_delete=None)
student = models.ForeignKey(Student, related_name='students', on_delete=None)
completed = models.BooleanField(null=True, default=False)
def __str__(self):
return self.course
I have some serializer like:
class CourseSerializer(serializers.ModelSerializer):
class Meta:
model = Course
fields = ('name', 'end_date', 'start_date')
I need return data in json like:
{
"courses": [
{
"name": "Math",
"end_date": "2019-06-26",
"start_date": "2019-06-26",
"participant_students_count: 10
}
]
}
How I can get "participant_students_count" and return its data in json with other fields.
Thanks for help!
You can use SerializerMethodField of DRF serializer field. Also, see about how to follow Backward access of Foreign key relationship.
from rest_framework import serializers
class CourseSerializer(serializers.ModelSerializer):
participant_students_count = serializers.SerializerMethodField()
class Meta:
model = Course
fields = ('name', 'end_date', 'start_date', 'participant_students_count')
def get_participant_students_count(self, obj):
return obj.courseparticipant_set.count()
class CourseSerializer(serializers.ModelSerializer):
participant_students_count = serializers.SerializerMethodField()
def get_participant_students_count(self, obj):
return CourseParticipant.objects.filter(course=obj).count()
class Meta:
model = Course
fields = ('name', 'end_date', 'start_date', 'participant_students_count')

Django rest framework get data based on current userId/token

In my model, i have a family table where user are able to enter their family details and store their information. But how do i get/query all the family member based on current userId ?
For eg: userId=1 added 2 family member, mother and father. How do i get these 2 family member based on the query of the current user's userId ?
here is my code :
models
class MyUser(AbstractUser):
userId = models.AutoField(primary_key=True)
gender = models.CharField(max_length=6, blank=True, null=True)
nric = models.CharField(max_length=40, blank=True, null=True)
birthday = models.DateField(blank=True, null=True)
birthTime = models.TimeField(blank=True, null=True)
class Family(models.Model):
userId = models.ForeignKey(MyUser)
relationship = models.CharField(max_length=100)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
gender = models.CharField(max_length=6, blank=True, null=True)
serializers
class MyUserSerializer(serializers.ModelSerializer):
valid_time_formats = ['%H:%M', '%I:%M%p', '%I:%M %p']
birthTime = serializers.TimeField(format='%I:%M %p', input_formats=valid_time_formats, allow_null=True, required=False)
class Meta:
model = MyUser
fields = ['userId', 'username', 'email', 'first_name', 'last_name', 'gender', 'nric', 'birthday', 'birthTime']
read_only_fields = ('userId',)
extra_kwargs = {"password": {"write_only": True}}
def update(self, instance, validated_data):
for attr, value in validated_data.items():
if attr == 'password':
instance.set_password(value)
else:
setattr(instance, attr, value)
instance.save()
return instance
class FamilySerializer(serializers.ModelSerializer):
class Meta:
model = Family
fields = ('id', 'userId', 'first_name', 'last_name', 'gender', 'relationship')
views
class MyUserViewSet(viewsets.ModelViewSet):
permission_classes = [AllowAny]
queryset = MyUser.objects.all()
serializer_class = MyUserSerializer
filter_backends = (filters.SearchFilter,)
search_fields = ('=userId', 'username', 'email', 'first_name', 'last_name')
class FamilyViewSet(viewsets.ModelViewSet):
permission_classes = [AllowAny]
queryset = Family.objects.all()
serializer_class = FamilySerializer
def get_object(self, *args, **kwargs):
return self.request.user
def perform_update(self, serializer):
super(CurrentFamilyView, self).perform_update(serializer)
user = serializer.instance
if settings.SEND_ACTIVATION_EMAIL and not user.is_active:
context = {'user': user}
to = [MyUser(user)]
email.ActivationEmail(self.request, context).send(to)
Can anyone help me with get current user's family
You can try this:
class Family(models.Model):
userId = models.ForeignKey(MyUser, related_name='user_family')
relationship = models.CharField(max_length=100)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
gender = models.CharField(max_length=6, blank=True, null=True)
serializers.py
class FamilySerializer(serializers.ModelSerializer):
class Meta:
model = Family
fields = ('id', 'first_name', 'last_name', 'gender', 'relationship')
class MyUserSerializer(serializers.ModelSerializer):
valid_time_formats = ['%H:%M', '%I:%M%p', '%I:%M %p']
birthTime = serializers.TimeField(format='%I:%M %p', input_formats=valid_time_formats, allow_null=True, required=False)
my_family = FamilySerializer(many=True, source='user_family')
class Meta:
model = MyUser
fields = ('userId', 'username', 'email', 'first_name', 'last_name', 'gender', 'nric', 'birthday', 'birthTime', 'my_family')
read_only_fields = ('userId',)
extra_kwargs = {"password": {"write_only": True}}
MyUserSerializer now will show userid related family members. If you want to get current user family member you need to overwrite get_queryset method.
your views.py:
class MyUserViewSet(viewsets.ModelViewSet):
serializer_class = MyUserSerializer
get_queryset(self):
return MyUser.objects.get(id=self.request.user.id)
Now the view will return current user family members.
Updates
Added related_name in Family model.
Added source in MyUserSerializer
Let's assume we have a user with id=1
usr = MyUser.objects.get(id=1)
usr_famly = usr.family_set.values()
usr_famly will have all family data related to user with id=1

Additional field while serializing django rest framework

I am a newbie to django rest framework and have created a sample Employee model.
My models.py:
class Employees(models.Model):
created = models.DateTimeField(auto_now_add=True)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
My serializers.py:
class EmployeeSerializer(serializers.Serializer):
class Meta:
model = Employees
fields = ('first_name','last_name')
This works fine but I want an additional field full_name, which will be first_name + last_name.
How do I define this new field full_name in my serializers.py?
I see two ways here (I prefer the first way since you can reuse it in other parts of the app):
add a calculated property to your model and add it to your serializer
by using a readonly field with source=
# models.py
class Employees(models.Model):
created = models.DateTimeField(auto_now_add=True)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
#property
def full_name(self):
return self.first_name + self.last_name
# serializers.py
class EmployeeSerializer(serializers.ModelSerializer):
full_name = serializers.Field(source='full_name')
class Meta:
model = Employees
fields = ('first_name','last_name', 'full_name')
by using SerializerMethodField
(your model unchanged)
class EmployeeSerializer(serializers.ModelSerializer):
full_name = serializers.SerializerMethodField('get_full_name')
def get_full_name(self, obj):
return obj.first_name + obj.last_name
class Meta:
model = Employees
fields = ('first_name','last_name', 'full_name')
Provided that the Employee is a login user, then most of us will use django.auth.User, I will share how Employee can be implemented as another Profile (extension of django User). Also with the addition of full_name.read_only, first_name.write_only, and last_name.write_only
# models.py
class Employee(models.Model):
"""User Profile Model"""
user = models.OneToOneField('auth.User')
# serializers.py
class EmployeeSerializer(serializers.HyperlinkedModelSerializer):
username = serializers.CharField(source='user.username')
email = serializers.EmailField(source='user.email')
first_name = serializers.CharField(
source='user.first_name', write_only=True)
last_name = serializers.CharField(
source='user.last_name', write_only=True)
name = serializers.CharField(
source='user.get_full_name', read_only=True)
class Meta:
model = Employee
fields = (
'url', 'username', 'email',
'first_name', 'last_name', 'name')
depth = 1
SerializerMethodField works fine, and we can also store data in serializer object and let method get_field_name use that.
Example:
class MySerializer(serializers.ModelSerializer):
statistic = serializers.SerializerMethodField()
def __init__(self, instance=None, data=serializers.empty, statistic=None, **kwargs):
super(MySerializer, self).__init__(instance=instance, data=data, **kwargs)
self.statistic = statistic
def get_statistic(self, obj):
if self.statistic is None:
return serializers.empty
return self.statistic.get(obj.id, {})