I have 3 models which are related to each other via ManytoMany relation like this:
class DemandEvents(models.Model):
date = models.DateTimeField(blank=True, null=True)
quantity = models.IntegerField(default=0)
class DemandFlows(models.Model):
events = models.ManyToManyField(DemandEvents)
flow = models.ForeignKey(Flow, on_delete=models.CASCADE)
kit = models.ForeignKey(Kit, on_delete=models.CASCADE)
monthly_quantity = models.IntegerField(default=0)
class Demand(models.Model):
demand_flows = models.ManyToManyField(DemandFlows)
delivery_month = models.DateTimeField(blank=True, null=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
I am trying to create the serializers for this but keep getting confused how to handle the multi-level nesting
Serializer.py
class DemandEventsSerializer(serializers.ModelSerializer):
class Meta:
model = DemandEvents
fields = "__all__"
class DemandFlowsSerializer(serializers.ModelSerializer):
class Meta:
model = DemandFlows
fields = "__all__"
class DemandSerializer(serializers.ModelSerializer):
demand_flows = DemandFlowsSerializer(many=True)
class Meta:
model = Demand
fields = "__all__"
def create(self, validated_data):
items_objects = validated_data.pop('form_list', None)
prdcts = []
for item in items_objects:
i = DemandFlows.objects.create(**item)
prdcts.append(i)
instance = Demand.objects.create(**validated_data)
instance.demand_flows.set(prdcts)
return instance
How do I add events data to this DemandFlows?
Related
I have this model that represents a bookmark or favorite. It has multiple foreign keys to other models. In the api I would like to pull in the data from each of the models that is referenced in the particular bookmark.
The model:
class Bookmark(models.Model):
marktype = models.CharField(max_length=10)
post = models.OneToOneField(Post, on_delete=models.CASCADE, null=True, blank=True)
question = models.OneToOneField(Question, on_delete=models.CASCADE, null=True, blank=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True, verbose_name="created at")
updated_at = models.DateTimeField(auto_now=True, verbose_name="updated at")
class Meta:
verbose_name = "bookmark"
verbose_name_plural = "bookmarks"
ordering = ["created_at"]
db_table = "bookmarks"
def __str__(self):
return "{}'s bookmark".format(self.owner.username)
I tried to use a SerializerMethodField but I get an error: 'NoneType' object has no attribute 'id'
Here is the serializer
class BookmarkSerializer(serializers.ModelSerializer):
post = serializers.SerializerMethodField()
question = serializers.SerializerMethodField()
class Meta:
model = Bookmark
fields = '__all__'
def get_post(self, obj):
obj = Post.objects.get(id=obj.post.id)
post = ShortPostSerializer(obj)
return post.data
def get_question(self, obj):
obj = Question.objects.get(id=obj.question.id)
question = ShortQuestionSerializer(obj)
return question.data
what am I doing wrong please?
You can update your serializer like the following (You can short it as you want or use your ShortQuestionSerializer as well instead of QuestionSerializer),
class QuestionSerializer(serializers.ModelSerializer):
class Meta:
model = Question
fields = '__all__'
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = '__all__'
class BookmarkSerializer(serializers.ModelSerializer):
post = PostSerializer()
question = QuestionSerializer()
class Meta:
model = Bookmark
fields = '__all__'
I would like to minimize number of queries to get data. I have 3 models:
class SubCategory(models.Model):
game = models.ForeignKey(Game, verbose_name=_("Gra"), on_delete=models.CASCADE)
name = models.CharField(verbose_name=_("Nazwa"), max_length=40)
...
class GameTask(CloneModel):
game = models.ForeignKey(Game, verbose_name='Gra', related_name='tasks', on_delete=models.CASCADE)
name = models.CharField(verbose_name='Nazwa', max_length=200)
subcategory = models.ForeignKey(SubCategory, verbose_name=_("Podkategoria"), on_delete=models.SET_NULL, blank=True, null=True)
class TaskLevel(CloneModel):
name = models.CharField(max_length=50)
master_task = models.ForeignKey(GameTask, related_name='sub_levels', on_delete=models.CASCADE)
My subcategory view looks like:
class SubCategoryList(ListAPIView, PermissionMixin):
permission_classes = (permissions.IsAuthenticated,)
serializer_class = SubCategorySerializer
def get_queryset(self):
return SubCategory.objects.filter(game=self.get_game()).order_by("slug")
and my SubCategorySerializer:
class SubCategorySerializer(serializers.ModelSerializer):
developments = SubCategoryDevelopmentSerializer(many=True, read_only=True)
in_progress = serializers.SerializerMethodField()
class Meta:
model = SubCategory
fields = ("id", "name", "slug", "description", "image", "developments", "in_progress")
def get_in_progress(self, obj: SubCategory):
user = self.context["request"].user
subcategory_tasks = obj.gametask_set.all()
// rest of the logic
All I want to achieve is to return only tasks, which are related to TaskLevel model as master_task. I was trying using
subcategory_tasks = obj.gametask_set.all().prefetch_related("sub_levels")
but the amount of queries was the same. Could somebody give my any hint how to solve this?
Trying to add 3rd nested serializer using django rest framework
how to add 3rd nested realation in given code -
models.py
class Category(models.Model):
cate_id = models.AutoField(primary_key=True)
cate_name = models.CharField(max_length=45)
class Meta:
managed = False
db_table = 'category'
class SubCategory(models.Model):
sub_cate_id = models.AutoField(primary_key=True)
sub_cate_name = models.CharField(max_length=45)
sub_fk = models.ForeignKey('Category', models.CASCADE, db_column='sub_fk')
class Meta:
managed = False
db_table = 'sub_category'
class Products(models.Model):
pro_id = models.AutoField(primary_key=True)
pro_name = models.CharField(max_length=45)
description = models.CharField(max_length=45, blank=True, null=True)
price = models.IntegerField()
quantity = models.IntegerField()
pro_cate_fk = models.ForeignKey('Category', models.CASCADE, db_column='pro_cate_fk')
pro_sub_fk = models.ForeignKey('SubCategory', models.CASCADE, db_column='pro_sub_fk')
image = models.CharField(max_length=205)
class Meta:
managed = False
db_table = 'products'
from rest_framework import serializers
from .models import Category,SubCategory,Products
class ProductsSerializer(serializers.ModelSerializer):
# x= ChildTable.objects.all().values
class Meta:
model = Products
fields = ('pro_id','pro_name','description','price','quantity','image')
class SubCategorySerializer(ProductsSerializer):
products_set = ProductsSerializer(many=True, read_only=True)
class Meta:
model = SubCategory
fields = ('sub_cate_name','sub_cate_id','products_set')
class CategorySerializer(SubCategorySerializer):
subcategory_set = ProductsSerializer(many=True, read_only=True,)
# pro_subcate_set = SubCategorySerializer(many=True, read_only=True)
class Meta:
model = Category
fields = ('cate_name','cate_id','subcategory_set')
Got this error while attempting -
Got AttributeError when attempting to get a value for field `pro_name` on serializer `ProductsSerializer`. The serializer field might be named incorrectly and not match any attribute or key on the `SubCategory` instance. Original exception text was: 'SubCategory' object has no attribute 'pro_name'.
Is it possible to connect 2 already connected serializer to another serializer?
Make a test and see if it works.
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ('cate_id', 'cate_name')
class SubCategorySerializer(serializers.ModelSerializer):
class Meta:
model = SubCategory
fields = ('sub_cate_id', 'sub_cate_name', 'sub_fk')
def to_representation(self, instance):
response = super().to_represntation(instance)
response['sub_fk'] = CategorySerializer(instance.sub_fk).data
return response
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Products
fields = ('pro_id', 'pro_name', 'description', 'price', 'quantity', 'pro_cate_fk', 'pro_sub_fk', 'image')
def to_representation(self, instance):
response = super().to_representation(instance)
response['pro_cate_fk'] = CategorySerializer(instance.pro_cate_fk).data
response['pro_sub_fk'] = ProductSerializer(instance.pro_sub_fk).data
return response
I want to add json data from the listserializer to the DetailSerializer class. The serializer looks something like this:
serializer.py
class ListSerializer(serializers.ModelSerializer):
class Meta:
model = Fastest_laps
fields = '__all__'
class DetailSerializer(serializers.ModelSerializer):
listserializer = ListSerializer( read_only=True, many=True)
class Meta:
model = Driver
fields =
('place_of_birth','driver','listserializer','picture')
But i dont really see the data once i view it, i only see the detailserializer data( Driver model)
class Fastest_laps(models.Model):
driver_name = models.CharField(max_length=25, null=True)
grand_prix = models.CharField(max_length=15, blank=True)
car_model = models.CharField(max_length=50)
time_taken = models.CharField(blank=True, max_length=8)
def __str__(self):
return self.driver_name
class Driver(models.Model):
place_of_birth = models.CharField(max_length=25)
driver = models.ForeignKey(Fastest_laps,
db_column='driver_name')
picture = models.ImageField(blank=True, null=True)
def __str__(self):
return str(self.driver)
api.py
class FastLapsSet(ModelViewSet):
queryset = Fastest_laps.objects.all()
serializer_class = ListSerializer
class DriverSet(ModelViewSet):
queryset = Driver.objects.all()
serializer_class = DetailSerializer
you should rename your property as model name field:
class DetailSerializer(serializers.ModelSerializer):
driver = ListSerializer(read_only=True)
# ^^^
class Meta:
model = Driver
fields =
('place_of_birth','driver','driver','picture')
or add the source attribute:
class DetailSerializer(serializers.ModelSerializer):
listserializer = ListSerializer(source='driver', read_only=True)
#^^^^
class Meta:
model = Driver
fields =
('place_of_birth','driver','listserializer','picture')
I have a django model named Event, which references Customer model.
event_name = models.CharField(max_length=200, unique=True)
customer = models.ForeignKey(customer_models.Customer, db_index=True,
on_delete=models.SET_NULL,
related_name='customer_events', null=True)
event_location = models.CharField(max_length=200, default='')
event_date = models.DateField()
I need to get the customer list along with the latest event name for each user in the API.
Customer serializers.py file is
class CustomerSerializer(serializers.ModelSerializer):
class Meta:
model = Customer
fields = '__all__'
Customer views.py file is
class CustomerViewSet(viewsets.ModelViewSet):
queryset = Customer.objects.all()
serializer_class = CustomerSerializer
How can I accomplish this?
In your Customer model you can have a property that returns the latest event name for a Customer instance:
class Customer(models.Model):
...
#property
def latest_event_name(self):
"""Return latest event name."""
# self.customer_events.order_by('event_date').last()
latest_event = self.customer_events.order_by('-event_date').first()
return latest_event.event_name if latest_event else None
In your serializer you can then add a ReadOnlyField for latest_event_name:
class CustomerSerializer(serializers.ModelSerializer):
latest_event_name = serializers.ReadOnlyField()
class Meta:
model = Customer
fields = '__all__'