Django get queryset with column from another model - django

Hello this is my model related to default AUTH_USER_MODEL by OneToOneField:
class Additional(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
vut_id = models.IntegerField()
edit_right = models.BooleanField(default = False)
add_access_right = models.BooleanField(default = False)
and I need to get Queryset of data Additional model with username from model AUTH_USER_MODEL.
If used select_related (Additional.objects.select_related('user').all() ) it returned only id of user:
{
"model": "authentication.additional",
"pk": 13,
"fields": {
"user": 15,
"vut_id": 123456,
"edit_right": false,
"add_access_right": false
}
}
how i want it to looks like:
{
"model": "authentication.additional",
"pk": 13,
"fields": {
"username": "user1",
"vut_id": 123456,
"edit_right": false,
"add_access_right": false
}
}

Additional.objects.select_related("user").all().values("user_id","user__username", "user__first_name","user__last_name", ...other fields whichever you want)

Related

Django: Creating endpoint for fetching subcategories within a category

I am new to Django and wanted to create an endpoint that allows me to push all the existing subcategories within a category. I have seen methods where one can fetch specific data points within a given category but I am confused about how to create such custom endpoints.
Here's my Serializers:
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ('id', 'categoryType')
class SubCategorySerializer(serializers.ModelSerializer):
categoryTitle = serializers.CharField(source="categoryType.categoryType", read_only=True)
class Meta:
model = SubCategory
fields = ('id', 'categoryTitle', 'subcategoryType')
#fields = '__all__'
Here's my model:
class Category(models.Model):
categoryType = models.CharField(max_length=100,blank = False, unique = True, null = False)
def __str__(self):
return self.categoryType
class SubCategory(models.Model):
subcategoryType = models.CharField(max_length=100)
categoryType = models.ForeignKey(Category,on_delete=models.CASCADE, null = True, related_name='category_type')
def __str__(self):
return f'{self.categoryType} :: {self.subcategoryType}'
When I hit subcategory endpoint, I get the data in following format:
[
{
"id": 2,
"categoryTitle": "Electronics",
"subcategoryType": "Mobile"
},
{
"id": 3,
"categoryTitle": "Electronics",
"subcategoryType": "Tablet"
},
{
"id": 4,
"categoryTitle": "Electronics",
"subcategoryType": "HardDisk"
},
{
"id": 5,
"categoryTitle": "Electronics",
"subcategoryType": "Laptop"
},
{
"id": 6,
"categoryTitle": "Sports",
"subcategoryType": "Tennis"
},
{
"id": 7,
"categoryTitle": "Sports",
"subcategoryType": "Cricket"
},
{
"id": 8,
"categoryTitle": "Sports",
"subcategoryType": "Football"
},
{
"id": 9,
"categoryTitle": "Sports",
"subcategoryType": "BasketBall"
}
]
but what I am interested in is getting the data of all the subcategories within a category passing category id in the endpoint:
something like this:
GET http://localhost:8000/categories/<categoryId> HTTP/1.1
which should return the data in the following way: (Since id 1 belongs to electronics, it should return all the subcategories that fall under electronics category)
[
{
"id": 2,
"subcategoryType": "Mobile"
},
{
"id": 3,
"subcategoryType": "Tablet"
},
{
"id": 4,
"subcategoryType": "HardDisk"
}
]
You need to add a nested serializer as below:
class CategorySerializer(serializers.ModelSerializer):
subCategories = SubCategorySerializer(source='category_type', many=True)
class Meta:
model = Category
fields = ('id', 'categoryType', 'subCategories')
Please note, you need to mention the related name in source, and have to add many=True, as one category can have many subcategories.
Use subcategory_set field.
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ('id', 'categoryType', 'subcategory_set')
This will give you one more field in the output, that is subcategory_set. This will be a list, containing all the subcategory ID.
If you want complete data, use depth option
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ('id', 'categoryType', 'subcategory_set')
depth = 1
Reference : https://www.django-rest-framework.org/api-guide/serializers/#specifying-nested-serialization

Reformat Django REST Framework Serializer to get Output

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',]

django rest framework: customize nested serializer

I have the following Django model structure:
class TypeOfIngredient(models.Model):
name = models.CharField(max_length=200,unique=True,null=False)
slug = models.SlugField(unique=True)
class Ingredient(models.Model):
name = models.CharField(max_length=200,unique=True,null=False)
slug = models.SlugField(unique=True)
typeofingredient = models.ForeignKey(TypeOfIngredient, related_name='typeof_ingredient',null=True, blank=True,on_delete=models.PROTECT)
Serializer:
class IngredientListSerializer(ModelSerializer):
class Meta:
model = Ingredient
fields = '__all__'
With the above serializer i see the following api output:
"results": [
{
"id": 1,
"name": "adrak",
"slug": "adrak",
"typeofingredient": null
},
{
"id": 2,
"name": "banana",
"slug": "banana",
"typeofingredient": 1
},
How to get "typeofingredient": "fruit" where fruit is the name field of the typeofingredient. What i am getting is the id.
I tried nested:
class IngredientListSerializer(ModelSerializer):
class Meta:
model = Ingredient
fields = '__all__'
depth = 1
Then i get the api output as:
"results": [
{
"id": 1,
"name": "adrak",
"slug": "adrak",
"typeofingredient": null
},
{
"id": 2,
"name": "banana",
"slug": "banana",
"typeofingredient": {
"id": 1,
"name": "fruit",
"slug": "fruit"
}
},
Here is showing all the details of the typeofingredient. Rather than this can i have directly "typeofingredient": "fruit"
Use serializers.ReadOnlyField
class IngredientListSerializer(ModelSerializer):
typeofingredient = serializers.ReadOnlyField(source='typeofingredient.name')
class Meta:
model = Ingredient
fields = '__all__'
You can add str method on models.py
class TypeOfIngredient(models.Model):
name = models.CharField(max_length=200,unique=True,null=False)
slug = models.SlugField(unique=True)
def __str__(self):
return str(self.name)
class Ingredient(models.Model):
name = models.CharField(max_length=200,unique=True,null=False)
slug = models.SlugField(unique=True)
typeofingredient = models.ForeignKey(TypeOfIngredient, related_name='typeof_ingredient',null=True, blank=True,on_delete=models.PROTECT)

Change the order of fields in normal serializer response

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)

django rest framework: include related model fields in same path

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