Pass data from post to Serializer - django

I have some data {iddepart, idarrivee} to use in serializer. This data is not present in data model but used internally to compute some fields:
Here is my code and I get error : The field 'iddepart' was declared on serializer ReservationSerializer, but has not been included in the 'fields' option.
class TravelViewReserveSet(mixins.RetrieveModelMixin,
mixins.ListModelMixin,
mixins.DestroyModelMixin,
mixins.CreateModelMixin,
viewsets.GenericViewSet):
serializer_class = ReservationSerializer
permission_classes = (permissions.IsAuthenticated,)
Model = Travel
And serialiser :
class ReservationSerializer(serializers.ModelSerializer):
user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())
#user = UserSerializer()
#travel = TravelSerializer()
iddepart = serializers.SerializerMethodField('iddepart')
idarrivee = serializers.SerializerMethodField('idarrivee')
def create(self, validated_data):
#code= random_generator()
##code = random_generator()
reservation = Reservation(**validated_data)
reservation.code = random_generator()
reservation.save()
#iddepart = validated_data['iddepart']
#idarrivee = validated_data['idarrivee']
class Meta:
model = Reservation
fields = ('id','reservedplaces','code','datecreation','travel','user')

try this
def create(self, validated_data):
iddepart = validated_data.pop('iddepart','default value')
idarrivee = validated_data.pop('idarrivee', 'default value')
# do somthing with this data
#code= random_generator()
##code = random_generator()
reservation = Reservation(**validated_data)
reservation.code = random_generator()
reservation.save()
#iddepart = validated_data['iddepart']
#idarrivee = validated_data['idarrivee']

You need to add iddepart and idarrivee to fields option in the Meta.
Your Meta should look like this,
class Meta:
model = Reservation
fields = ('id','reservedplaces','code','datecreation','travel','user',
'iddepart','idarrivee')

Related

DjangoRestFramework, how to add optional field not coming from model to serializer

I have a model like this:
class Camper(models.Model):
location = models.PointField()
name = models.CharField(max_length=255)
and a viewset like this:
class CamperViewSet(viewsets.ModelViewSet):
...
def retrieve(self, request, *args, **kwargs):
"""Retrieve a Camper instance."""
show_weather = request.query_params.get('showWeather', False)
instance = self.get_object()
if show_weather:
lat = instance.location.y
lon = instance.location.x
instance.weather = getWeatherFromLatLon(lat, lon)
serializer = self.get_serializer(instance)
return Response(serializer.data)
So when I request /api/campers/8?showWeather=true I make another request in my view to get the weather from the current position.
How do I add it to my serializer ? It's an optional field so I need to manage this and it's only used in /campers/id so it will not be used in list/create/put/etc
My serializer looks like this:
class CamperSerializer(serializers.ModelSerializer):
camper_id = serializers.IntegerField(source='id')
class Meta:
model = Camper
fields = ('camper_id', 'name', 'location')
you can add custom serializer for retrive only todo it. I called CamperRetriveSerializer.
Inside CamperRetriveSerializer, you can use SerializerMethodField for define field not have in database.
And you want check param show_weather from request, best is pass value of it to context and get it in serializer.
Like this:
class CamperRetriveSerializer(serializers.ModelSerializer):
weather = serializers.SerializerMethodField()
camper_id = serializers.IntegerField(source='id')
def get_weather(self, obj):
show_weather = self.context.get('show_weather')
if show_weather:
lat = obj.location.y
lon = obj.location.x
return getWeatherFromLatLon(lat, lon)
# define default value if not show_weather in this
return ''
class Meta:
model = Camper
fields = ('camper_id', 'name', 'location', 'weather')
class CamperViewSet(viewsets.ModelViewSet):
...
def retrieve(self, request, *args, **kwargs):
"""Retrieve a Camper instance."""
instance = self.get_object()
show_weather = self.request.query_params.get('showWeather', False)
context = {
'show_weather': show_weather
}
serializer = CamperRetriveSerializer(instance, context=context)
return Response(serializer.data)
You can use two different serializers for this.
class CamperViewSet(viewsets.ModelViewSet):
serializer_class = CamperSerializer
def get_serializer_class(self):
serializer_class = self.serialzier_class
if self.request.method == 'GET':
serializer_class = CamperSerializerGet
return serializer_class
#Serializer for GET request
class CamperSerializerGet(serializers.ModelSerializer):
weather = serialziers.SerializerMethodField()
camper_id = serializers.IntegerField(source='id')
def get_weather(self, obj):
return obj.weather
class Meta:
model = Camper
fields = ('camper_id', 'name', 'location', 'weather')
#For other requests call this
class CamperSerializer(serializers.ModelSerializer):
camper_id = serializers.IntegerField(source='id')
class Meta:
model = Camper
fields = ('camper_id', 'name', 'location')

How to pass a query parameter to SerializerMethodField in django rest framework?

I want to filter out some instance based on the query parameter I get in the GET call.
class RevisionSerializer(serializers.ModelSerializer):
slot_info = serializers.SerializerMethodField(required=False, read_only=True)
batch_config = serializers.SerializerMethodField(required=False, read_only=True)
class Meta:
model = Revision
fields = ['id', 'status', 'revision_id', 'instructor', 'number_of_classes', 'start_date',
'slot', 'slot_info', 'tinyurl', 'zoom_link', 'batch_config']
read_only_fields = ['revision_id']
def get_batch_config(self, obj):
# filter this on the incoming data from the GET call
related_batches = CompensationClass.objects.select_related('style', 'instructor').filter(
compensation_class_id=obj.revision_id)
batch_config_values = related_batches.values('batch_id', 'age_group', 'level', 'course_version', 'style__name',
'class_number')
return batch_config_values
This is my serializer and I will be passing one date and based on that date I want to filter my serializermethodfield. How can I achieve this?
You can pass parameters to a Serializer using its context:
# views.py
class RevisionView(GenericAPIView):
serializer_class = RevisionSerializer
def get_serializer_context(self):
return {'revision_id': self.request.GET.get('revision_id')}
# serializers.py
class RevisionSerializer(serializers.ModelSerializer):
def get_batch_config(self, obj):
related_batches = CompensationClass.objects.select_related('style', 'instructor').filter(
compensation_class_id=self.context.get('revision_id'))
Thanks to #ThomasGth. I did it like this.
SERIALIZER
class RevisionSerializer(serializers.ModelSerializer):
slot_info = serializers.SerializerMethodField(required=False, read_only=True)
batch_config = serializers.SerializerMethodField(required=False, read_only=True,
)
class Meta:
model = Revision
# fields = '__all__'
fields = ['id', 'status', 'revision_id', 'instructor', 'number_of_classes', 'start_date',
'slot', 'slot_info', 'tinyurl', 'zoom_link', 'batch_config']
read_only_fields = ['revision_id']
def get_batch_config(self, obj):
calendar_date = self.context.get('calendar_date')
related_batches = CompensationClass.objects.select_related('style', 'instructor').filter(
compensation_class_id=obj.revision_id)
if calendar_date:
related_batches = related_batches.filter(calendar_date)
batch_config_values = related_batches.values('batch_id', 'age_group', 'level', 'course_version', 'style__name',
'class_number')
return batch_config_values
VIEWSET
class RevisionViewset(viewsets.ModelViewSet):
queryset = Revision.objects.all().order_by('-modified_at').select_related('instructor', 'slot')
serializer_class = RevisionSerializer
pagination_class = LimitOffsetPagination
filter_backends = [DjangoFilterBackend, filters.SearchFilter]
filterset_class = RevisionFilter
def get_serializer_context(self):
context = {'request': self.request}
calendar_date = self.request.GET.get('calendar_date')
if calendar_date:
context['calendar_date'] = calendar_date
return context

Django REST framework: how to combine the same type of model

How to combine many models in one query set so that it would be possible to use HyperlinkedModelSerializer using pagination?
I need to connect many models with the same fields.
That's what I did, but it doesn’t suit me.:
#models.py
class Merketing(models.Model):
question = models.CharField(max_length=500, unique=True)
answer = models.CharField(max_length=500)
class Management(models.Model):
question = models.CharField(max_length=500, unique=True)
answer = models.CharField(max_length=500)
#serializers.py
class MerketingSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Merketing
fields = ['id','question', 'answer']
class ManagementSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Management
fields = ['id','question', 'answer']
class FiltersSerializers(serializers.Serializer):
model_1 = MerketingSerializer(read_only=True,many=True)
model_2 = ManagementSerializer(read_only=True,many=True)
#viesw.py
class MerketingViewSet(viewsets.ModelViewSet):
queryset = Merketing.objects.all().order_by('question')
serializer_class = MerketingSerializer
permission_classes = [permissions.IsAuthenticated]
filter_backends = [filters.SearchFilter]
search_fields = ['question']
class ManagementViewSet(viewsets.ModelViewSet):
queryset = Management.objects.all().order_by('question')
serializer_class = ManagementSerializer
permission_classes = [permissions.IsAuthenticated]
filter_backends = [filters.SearchFilter]
search_fields = ['question']
class FiltersView(APIView):
def get(self, request, *args, **kwargs):
filters = {}
filters['model_1'] = Merketing.objects.all().order_by('question')
filters['model_2'] = Management.objects.all().order_by('question')
serializer = FiltersSerializers(filters)
return Response (serializer.data, status=HTTP_200_OK)
Here is the solution to my problem !!!
class Fi2ViewSet(viewsets.ModelViewSet):
qs1 = Merketing.objects.all()
qs2 = Management.objects.all()
qs3= Macroeconom.objects.all()
qs4 = Kse.objects.all()
queryset = qs1.union(qs2,qs3,qs4).order_by('question')
serializer_class = Fi2Serializer
permission_classes = [permissions.IsAuthenticated]
filter_backends = [filters.SearchFilter]
search_fields = ['question']
serializers.py
class Fi2Serializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Merketing
fields = ['id','question', 'answer']

How to Change ManyToManyField Name in Serializer

I want to change ManyToManyField Name. user_groups is manytomanyfield. I tried to use ManyToManyRelatedField and also PrimaryKeyRelatedField but it is giving error. How can i change or with data type should i give like for character field i am giving CharField
class EmployeeProfileSerializer(serializers.ModelSerializer):
employee_id = serializers.CharField(source='user_employee_id')
payroll_id = serializers.CharField(source='user_payroll_id')
phone = serializers.CharField(source='user_phone')
hire_date = serializers.DateField(source='user_hire_date')
pay_rate = serializers.IntegerField(source='user_pay_rate')
salaried = serializers.CharField(source='user_salaried')
excempt = serializers.CharField(source='user_excempt')
state = serializers.CharField(source='user_state')
city = serializers.CharField(source='user_city')
zipcode = serializers.IntegerField(source='user_zipcode')
status = serializers.CharField(source='user_status')
class Meta:
model = UserProfile
fields = [
'employee_id',
'phone',
'payroll_id',
'hire_date',
'pay_rate',
'salaried',
'excempt',
'state',
'city',
'zipcode',
'status',
'user_groups',
]
You can use SerializerMethodField:
class EmployeeProfileSerializer(serializers.ModelSerializer):
...
your_custom_name = SerializerMethodField()
class Meta:
model = UserProfile
fields = ['your_custom_name ', ...]
def get_your_custom_name(self, obj):
# Return ids:
return list(obj.user_groups.all().values_list('pk', flat=True))
# Or using a serializer:
return MyUserGroupSerializer(obj.user_groups.all(), many=True).data
For create and update you have to override the create and update method to assign the new field:
class EmployeeProfileSerializer(serializers.ModelSerializer):
...
your_custom_name = IntegerField()
class Meta:
model = UserProfile
fields = ['your_custom_name', ...]
# If you need validation
def validate_your_custom_name(self, value):
if value:
if int(value) > 5:
return value
return None
def create(self, validated_data):
# Get the data for your new field
my_costum_data = validated_data.get('your_custom_name')
# Do something with it
profile_obj = UserProfile.objects.create(...)
if my_costum_data:
user_group = UserGroupModel.objects.get(pk=int(my_costum_data))
profile_obj.user_groups.add(user_group)
def update(self, instance, validated_data):
# Same as create()
...

Django Rest Framework serilize relations

How to serialize a fields in related models.
I got a models:
class Order(models.Model):
order_id = models.BigIntegerField(verbose_name='Order ID', unique=True)
order_name = models.CharField(verbose_name='Order name', max_length=255)
order_type = models.IntegerField(verbose_name='Campaign type')
class Types(models.Model):
delimiter = models.CharField(verbose_name='Delimiter', max_length=255)
status = models.BooleanField(verbose_name='Status', default=True)
title = models.CharField(verbose_name='Title', max_length=255)
class User(models.Model):
name = models.CharField(verbose_name='User name', max_length=200, unique=True)
class Report(models.Model):
order = models.ForeignKey(Order, to_field='order_id', verbose_name='Order ID')
user = models.ForeignKey(User, verbose_name='User ID')
ad_type = models.ForeignKey(Types, verbose_name='Type')
imp = models.IntegerField(verbose_name='Total imp')
month = models.DateField(verbose_name='Month', default=datetime.datetime.today)
View:
class ReportLisAPIView(ListAPIView):
serializer_class = ReportSerializer
def get_queryset(self):
month = parse_date(self.kwargs['month']) - relativedelta(day=1)
queryset = (
Report.objects.filter(month=month)
.values_list(
'user', 'user__name', 'order__order_id',
'order__order_name', 'order__order_type'
).all().annotate(Sum('imp'))
)
return queryset
Serializer:
class ReportSerializer(ModelSerializer):
class Meta:
model = Report
depth = 1
I need to get all field like in 'queryset' in get_queryset()
but I got an error:
Got AttributeError when attempting to get a value for field imp on
serializer ReportSerializer. The serializer field might be named
incorrectly and not match any attribute or key on the tuple
instance. Original exception text was: 'tuple' object has no attribute
'imp'.
But if I return in get_queryset() just Report.objects.filter(month=month).all() I'll get all objects and related object with all field, without aggregate of imp and not grouping.
So the question is how to make serializer return structure that set in queryset?
The get_queryset method requires to return a queryset but you are returning a tuple beacause of values_list. Either drop it to return a queryset or go with a more generic view like APIView.
I found a way how to do it.
As I use .values_list() it return list object instead of queryset object. So for serializer do understand what is inside the list I defined all fields in serializer. And in to_representation() I return dictionary like it should be.
Serializer:
class ReportSerializer(serializers.ModelSerializer):
user = serializers.IntegerField()
user_name = serializers.CharField()
order_id = serializers.IntegerField()
order_name = serializers.CharField()
order_type = serializers.IntegerField()
imp = serializers.IntegerField()
class Meta:
model = Report
fields = [
'user', 'user_name', 'order_id', 'order_name',
'order_type', 'imp'
]
depth = 1
def to_representation(self, instance):
Reports = namedtuple('Reports', [
'user',
'user_name',
'order_id',
'order_name',
'order_type',
'imp',
])
return super(ReportSerializer, self).to_representation(
Reports(*instance)._asdict()
)
View:
class ReportLisAPIView(ListAPIView):
serializer_class = ReportSerializer
def get_queryset(self):
month = parse_date(self.kwargs['month']) - relativedelta(day=1)
queryset = (
Report.objects.filter(month=month)
.values_list(
'user', 'user__name', 'order__order_id',
'order__order_name', 'order__order_type'
).all().annotate(Sum('imp'))
)
return queryset
def list(self, *args, **kwargs):
queryset = self.get_queryset()
serializer = self.serializer_class(queryset, many=True)
# actualy that's it! part of which is below can be pass and just
# return Response(serializer.data)
result = {
'month': parse_date(self.kwargs['month']).strftime('%Y-%m'),
'reports': []
}
inflcr = {}
for item in serializer.data:
inflcr.setdefault(item['user'], {
'id': item['user'],
'name': item['user_name'],
'campaigns': []
})
orders = {
'id': item['order_id'],
'name': item['order_name'],
'type': item['order_type'],
'impressions': item['imp'],
}
inflcr[item['user']]['campaigns'].append(orders)
result['reports'] = inflcr.values()
return Response(result)