Using Django REST framework I want to change the serializer response fields order dynamically by a list of given field names.
Output from DRF is the following:
{
"items": [
{
"name": "John",
"age": 25,
"id": 3
},
{
"name": "Sam",
"age": 20,
"id": 8
}
]
}
My filed order list is:
order_list = ['id', 'age', 'name']
What I want is:
{
"items": [
{
"id": 3,
"age": 25,
"name": "John"
},
{
"id": 8,
"age": 20,
"name": "Sam"
}
]
}
Serializer code:
class ItemSerializer(serializers.Serializer):
name = serializers.CharField()
id = serializers.IntegerField()
age = serializers.IntegerField()
To change the ordering, you will need to change the field definition in the serializer meta class.
class ItemSerializer(serializers.Serializer):
name = serializers.CharField()
id = serializers.IntegerField()
age = serializers.IntegerField()
class Meta(object):
fields = ( # this needs to be ordered properly
'id',
'age',
'name',
)
You can loop over the serializer data and order the fields using OrderedDict.
The data in the serializer is already using OrderedDict, but we can use it to further order accordingly.
from collections import OrderedDict
data = serializer.data
ordered_data = []
for item in data:
item_dict = OrderedDict()
item_dict['id'] = item['id']
item_dict['age'] = item['age']
item_dict['name'] = item['name']
ordered_data.append(item_dict)
Related
In Django Rest Framework, I want to group my serializer data by date, How can I do that.
I have to group it by date on the basis of timestamp date.
my model: mongo model with some more fields also but only uses these two fields
class MyModel(Document):
#mongo model
candidate_id = StringField(required=True, db_field='c')
timestamp = DateTimeField(required=True, db_field='d')
...
... more fields
My Views: my views file
class MyView(generics.ListAPIView):
serializer_class = MySerializer
def get_queryset(self):
recruiter_id = self.request.GET.get("recruiter_id")
activity_list = MyModel.objects.filter(recruiter_id=str(recruiter_id)).order_by('- timestamp')
return activity_list
my serializer: using serializermethod field to get data from other DB by using candidate id from activity model
class MySerializer(serializers.Serializer):
candidate_id = serializers.CharField()
name = serializers.SerializerMethodField()
designation = serializers.SerializerMethodField()
age = serializers.SerializerMethodField()
timestamp = serializers.DateTimeField(format="%H:%M")
def get_name(self, obj):
return something
def get_designation(self, obj):
return something
def get_age(self, obj):
return something
I want to group my response by Date like :
[
{
"date": "2022-12-05",
"candidates":[
{
"candidate_id": 1,
"name": "One",
"designation": "Lead",
"age": 30,
"timestamp": "14:30"
}
]
},
{
"date": "2022-12-04",
"candidates":[
{
"candidate_id": 2,
"name": "Two",
"designation": "Lead",
"age": 30,
"timestamp": "14:30",
}
]
}
]
my actual response is like:
[
{
"candidate_id": 1,
"name": "One",
"designation": "Lead",
"age": 30,
"activity_timestamp": "13:12"
},
{
"candidate_id": 2,
"name": "Two",
"designation": "Lead",
"age": 30,
"activity_timestamp": "13:12"
}
]
I am trying to get data in a particular format but i'm not able to get the desired output.
My Model:
class Category(models.Model):
name = models.CharField(max_length=40)
class Expense(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name="category_name")
description = models.CharField(max_length=200)
total_amount = models.IntegerField()
class Expense_Details(models.Model):
expense = models.ForeignKey(Expense, on_delete=models.CASCADE, related_name="payment")
user = models.IntegerField()
amount = models.FloatField()
type = models.CharField(max_length=100) ---->type is owe or lend
When I request /api/expenses/:
Expected Output
{
“total_expenses”: 10,
“Expenses”:
[{
“id”: 1,
“category”: 1,
“created_by”: 1, ------> user logged id
“description”: “lunch”,
“total_amount”: “105”,
“owe”: [{
“user_id”: 1,
“amount”: 10
},
{
“user_id”: 2,
“amount”: 95
}],
“lend”: [{
“user_id”: 3,
“amount”: 10
},
{
“user_id”: 4,
“amount”: 95
}],
}, ...
]
}
My output:
{
"results": [
{
"id": 1,
"category": 1,
"description": "lunch at the burj al arab",
"total_amount": 105,
"payment": [
{
"user": 1,
"amount": -10
},
{
"user": 2,
"amount": -95
},
{
"user": 3,
"amount": 10
},
{
"user": 4,
"amount": 95
}
]
}
]
}
My Serializer:
class ExpenseDetailsSerializer(serializers.ModelSerializer):
class Meta:
model = Expense_Details
fields = ['user', 'amount']
class ExpenseSerializer(serializers.ModelSerializer):
payment = serializers.SerializerMethodField()
def get_payment(self, obj):
return ExpenseDetailsSerializer(obj.payment.all(), many=True).data
class Meta:
model = Expense
fields = ['id', 'category', 'description', 'total_amount', 'payment',]
What Query should I use to get Output in the above format? How will my serializer look like? How can I separate own and lend? Also I have stored own and lend with + and - sign to differentiate between them.
Use a ListField for the same.
Documentation: https://www.django-rest-framework.org/api-guide/fields/#listfield
Also refer How to serialize an 'object list' in Django REST Framework
Here you can try something like:
class ExpenseSerializer(serializers.Serializer):
payment = serializers.ListField(child=ExpenseDetailsSerializer())
def get_payment(self, obj):
return ExpenseDetailsSerializer(obj.payment.all(), many=True).data
class Meta:
model = Expense
fields = ['id', 'category', 'description', 'total_amount', 'payment',]
I'm new to Django,i tryed to list all invoices from my model Invoices and im getting items as only its object, to make the code efficient i need to get the whole data of items in a single query how can i get the details of items along with the data instead of item objects
Here is what i have tryed
models.py
class ItemsInvoice(models.Model):
invoiceId = models.CharField(max_length=20)
product_Id = models.CharField(max_length=20)
item_price = models.CharField(max_length=20)
class Invoices(models.Model):
customer = models.CharField(max_length=10,null=True)
total_amount = models.CharField(max_length=12,null=True)
items = models.ManyToManyField(ItemsInvoice,related_name="item_invoice")
views.py
class InvoiceView(ListAPIView):
serializer_class = InvoiceSerializers
def get_queryset(self):
# queryset = Invoices.objects.prefetch_related('items').all().order_by('-id')
queryset = Invoices.objects.all().order_by('-id')
return queryset
serializers.py
class InvoiceSerializers(serializers.ModelSerializer):
class Meta:
model = Invoices
fields = '__all__'
if i run it on my postman, its response will be like this
API response what i have
[
{
"id": 69,
"customer": "4",
"total_amount": "25000",
"items": [
66,
67,
68
]
}
]
but actually i want my output like this , ie the item field should list all data inside in it
API response what i want
[
{
"id": 69,
"customer": "4",
"total_amount": "25000",
"items": [
{
"id": 66,
"invoiceId": "69",
"product_Id": "3",
"item_price": "300",
},
{
"id": 67,
"invoiceId": "69",
"product_Id": "4",
"item_price": "200",
},
{
"id": 68,
"invoiceId": "69",
"product_Id": "4",
"item_price": "200",
}
]
}
]
how can i achieve it by using django-orm or raw query
You must define ItemInvoiceSerializer and set many=true.
class ItemInvoiceSerializer(serializers.ModelSerializer):
class Meta:
model = ItemsInvoice
fields = '__all__'
class InvoiceSerializers(serializers.ModelSerializer):
items = ItemInvoiceSerializer(many=True) # i changed true to True
class Meta:
model = Invoices
fields = '__all__'
I'm struggling to write a Django GET that returns the following looking response:
{
"lists": [
{
"id": "123",
"list_order": [
{
"id": "123_1",
"order": 1,
"list_id": "123",
"item_id": 9876,
"item": {
"id": 9876,
"name": "item1",
"location": "California"
}
},
{
"id": "123_2",
"order": 2,
"list_id": "123",
"item_id": 2484,
"item": {
"id": 2484,
"name": "item2",
"location": "California"
}
}
],
"updated_date": "2018-03-15T00:00:00Z"
}
]
}
Given a list_id, the response returns the basic information on the list ("id", "updated_date"), as well as the order of items in the list. Inside each item in the list order, it also grabs the related item details (nested in "item"). I'm able to get this response without the "item" details ("id", "name", "location" fields) and with no error:
{
"lists": [
{
"id": "123",
"list_order": [
{
"id": "123_1",
"order": 1,
"list_id": "123",
"item_id": 9876
},
{
"id": "123_2",
"order": 2,
"list_id": "123",
"item_id": 2484
}
],
"updated_date": "2018-03-15T00:00:00Z"
}
]
}
Again there is no error, and I can retrieve the first nested level without any issue. The problem is getting the "item" information to show within each "list_order". Below are my models, serializers, and views.
models.py
class Lists(models.Model):
id = models.CharField(null=False, primary_key=True, max_length=900)
updated_date = models.DateTimeField(blank=True, null=True)
class Meta:
managed = False
db_table = 'tbl_lists'
class Items(models.Model):
id = models.BigIntegerField(primary_key=True)
name = models.TextField(blank=True, null=True)
location = models.TextField(blank=True, null=True)
class Meta:
managed = False
db_table = 'tbl_items'
class ListOrder(models.Model):
id = models.CharField(null=False, primary_key=True, max_length=900)
list_id = models.ForeignKey(Lists, db_column='list_id', related_name='list_order')
item_id = models.ForeignKey(Items, db_column='item_id', related_name='items')
order = models.BigIntegerField(blank=True, null=True)
class Meta:
managed = False
db_table = 'tbl_list_order'
serializers.py
class ItemsSerializer(serializers.ModelSerializer):
class Meta:
model = Items
fields = '__all__'
class ListOrderSerializer(serializers.ModelSerializer):
item = ItemsSerializer(many=False, read_only=True)
class Meta:
model = ListOrder
fields = '__all__'
class ListsSerializer(serializers.ModelSerializer):
list_order = ListOrderSerializer(many=True, read_only=True)
class Meta:
model = Lists
fields = '__all__'
views.py
class ListsViewSet(generics.ListCreateAPIView):
"""
API endpoint that returns a list with its meta-information
"""
queryset = Lists.objects.all()
serializer_class = ListsSerializer
def get_queryset(self):
list_id = self.kwargs['list_id']
filters = [Q(id=list_id)]
return Lists.objects.filter(*filters)
def list(self, request, list_id):
queryset = self.get_queryset()
list_serializer = ListsSerializer(queryset, many=True)
return Response({ 'lists': list_serializer.data })
I'm pretty new to Django and like what it offers so far, though maybe I'm thinking of doing this in too much of a "SQL" way. I've read about select_related() and prefetch_related(), but not sure how I would apply it to this case. Any assistance is greatly appreciated and let me know if there's any other information I can provide.
In your ListOrderSerializer you are trying to serialize item. while in ListOrder model you used the field name item_id
Solution:
In ListOrderSerializer:
class ListOrderSerializer(serializers.ModelSerializer):
item_id = ItemsSerializer(many=False, read_only=True)
...
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = ('id','product_id','sku', 'title','price','images')
class WishListSerializer(serializers.ModelSerializer):
product = ProductSerializer()
class Meta:
model = WishList
fields = ('wishlist_id','product',)
I have two serializers. Wishlist and Product. I want to list all wishlist products. It works fine now. But the product details is in "product" key element. Can I remove that product key, and show the product details along with the wishlist_id ?
Present result:
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"wishlist_id":1,
"product": {
"id": 1460,
"product_id": "04396134-3c90-ea7b-24ba-1fb0db11dbe5",
"sku": "bb4sd817",
"title": "Trinity Belt",
}
},
{
"wishlist_id":2,
"product": {
"id": 596,
"product_id": "52588d22-a62c-779b-8044-0f8d9892e853",
"sku": "ml346",
"title": "Martina Liana",
}
}
]
}
Expected result:
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"wishlist_id":1,
"id": 1460,
"product_id": "04396134-3c90-ea7b-24ba-1fb0db11dbe5",
"sku": "bb4sd817",
"title": "Trinity Belt",
},
{
"wishlist_id":2,
"id": 596,
"product_id": "52588d22-a62c-779b-8044-0f8d9892e853",
"sku": "ml346",
"title": "Martina Liana",
}
]
}
This is a very bad practice and you need a lot of effort to implement serialization and deserialization, especially in case of Post, Update etc.
I can think of 2 ways.
1) You could use in the WishListSerializer the missing fields as SerializerMethodField
example
product_id = serializers.SerializerMethodField()
def get_product_id(self, obj):
return obj.get_product().product_id
2)
class WishListSerializer(serializers.HyperlinkedModelSerializer):
product_id = serializers.CharField(source='product.product_id')
.......
class Meta:
model = WishList
fields = (product_id, ......)
You could "unnest" items in to_representation
docs on it https://www.django-rest-framework.org/api-guide/fields/#custom-fields
...
class WishListSerializer(serializers.ModelSerializer):
product = ProductSerializer()
class Meta:
model = WishList
fields = ('wishlist_id', 'product',)
# add
def to_representation(self, instance):
data = super().to_representation(instance)
flat_data = dict(wishlist_id=data['wishlist_id'], **data['product']) # construct (new dict) flat data
# or you could restructure same dict: data.update(data.pop('product'))
return flat_data