I am trying to serialize related models for an API view.
class Dashboard(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
modified_at = models.DateTimeField(auto_now=True)
user = models.ForeignKey(IamUser, on_delete=models.CASCADE, related_name='dashboards')
title = models.CharField(max_length=100)
type = models.CharField(max_length=100)
position = models.IntegerField()
config = models.CharField(max_length=5000, blank=True, null=True)
class WidgetLayout(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
modified_at = models.DateTimeField(auto_now=True)
user = models.ForeignKey(IamUser, on_delete=models.CASCADE, related_name='widgets')
dashboard = models.ForeignKey(Dashboard, on_delete=models.CASCADE, related_name='widgets')
type = models.ForeignKey(Widget, on_delete=models.CASCADE)
position = models.IntegerField()
width = models.IntegerField()
config = models.CharField(max_length=5000, blank=True, null=True)
with the following serializers
class WidgetLayoutSerializer(serializers.ModelSerializer):
class Meta:
model = WidgetLayout
fields = ['id', 'type', 'position', 'width', 'config']
class DashboardSerializer(serializers.ModelSerializer):
class Meta:
widgets = WidgetLayoutSerializer(many=True)
model = Dashboard
fields = ['id', 'title', 'position', 'config', 'type', 'widgets']
The view calls the serializers like this:
dashboards = request.user.dashboards.all()
serializer = DashboardSerializer(dashboards, many=True)
The expected output would be a list of Widgets in their JSON serialization for each Dashboard, however, I get only a list of Widget-IDs. I discovered that, if i remove the widgets = WidgetLayoutSerializer(many=True), the result is the same, so I suspect, the serializer is not being used or referenced properly. I went through https://www.django-rest-framework.org/api-guide/relations/#example and tried to spot any difference, but could not find it.
Adding the prefetch_related for the widgets to the .all() in the view made no difference.
depth=1 is not really helpful, as I want to specify each serializer explicitly.
This is definitely not correct that 2 fields have the same related_name:
user = models.ForeignKey(IamUser, on_delete=models.CASCADE, related_name='widgets')
dashboard = models.ForeignKey(Dashboard, on_delete=models.CASCADE, related_name='widgets')
Remove widgets from user.
Also the field should be a base class property, not a Meta class property.
class DashboardSerializer(serializers.ModelSerializer):
widgets = WidgetLayoutSerializer(many=True)
class Meta:
model = Dashboard
fields = ['id', 'title', 'position', 'config', 'type', 'widgets']
Everything else seems good for me.
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__'
class EntityServiceSerializer(serializers.ModelSerializer):
class Meta:
model = Service
fields = '__all__'
class EntityCreateSerializer(serializers.ModelSerializer):
entity_service = EntityServiceSerializerThrough(read_only=True, source='serviceschedule_set', many=True)
class Meta:
model = Entity
fields = '__all__'
Model looks like this
class Entity(models.Model):
entity_service = models.ManyToManyField(Service, through='ServiceSchedule')
class ServiceSchedule(models.Model):
service = models.ForeignKey(Service, on_delete=models.CASCADE)
entity = models.ForeignKey(Entity, on_delete=models.CASCADE)
class Service(models.Model):
service_name = models.CharField(max_length=256, null=True)
slug = models.SlugField(max_length=128, unique=True, null=False, editable=False)
created_at = models.DateTimeField(editable=False, default=timezone.now)
updated_at = models.DateTimeField(default=timezone.now)
animal = models.ForeignKey(Animal, on_delete=models.CASCADE, default=None)
I have these serializers (there are more fields in entity model, but they're irrelevant since the only problem i have is with the Many2Many)
The thing is, when i put in body "entity_service": [1,2] in the response i still get = []. Even though i have in my database Services with pk 1,2,3,4.
Do you know how can i make it work?
Try it without a source as the field name is the same as the model field name
class EntityCreateSerializer(serializers.ModelSerializer):
entity_service = EntityServiceSerializerThrough(read_only=True, many=True)
class Meta:
model = Entity
fields = '__all__'
models
class CreatorRawArtwork(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=500)
descripton = models.TextField()
editions = models.IntegerField(null=True, blank=True)
price = models.CharField(max_length=500)
created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True)
medias = models.FileField(null=True, blank=True, upload_to="raw-medias")
user = models.ForeignKey(to=Login, on_delete=models.CASCADE, related_name="creatorrawartwork", null=True, blank=True
)
collection = models.ForeignKey(
to=DesignerCollection, on_delete=models.CASCADE, related_name="creatorrawartwork", null=True, blank=True)
categories = models.ManyToManyField(DesignerCategories, related_name='creatorrawartwork')
def __str__(self):
return self.title
serializer
class CreatorRawArtworkSerializer(serializers.ModelSerializer):
categories = serializers.PrimaryKeyRelatedField(queryset=DesignerCategories.objects.all(), many=True)
class Meta:
model = CreatorRawArtwork
fields = "__all__"
depth=1
views
class CreatorRawArtworkView(viewsets.ModelViewSet):
queryset = CreatorRawArtwork.objects.all()
serializer_class = CreatorRawArtworkSerializer
Here i am trying to create manytomany fields using drf serialier it is showing some error
plese check the screenshot for parameter and responses
What can be the issue please take a look
class CreatorRawArtworkSerializer(serializers.ModelSerializer):
collection = DesignerCollectionSerializer(read_only=True) #assuming you have already defined serializer for *DesignerCollectionSerializer*
categories = DesignerCategoriesSerializer(many=True)
class Meta:
model = CreatorRawArtwork
fields = "__all__"
depth=1
I tested with your code and your code is working fine
just make sure your request data is json
I want to create a JSON object which will
Search the particular Projects from the model "EmpProject" by a specific emp_id
Search whose project status is "Pending" from the model "Project" with the help of (1.) Search result
I am using JSON Parser (no models or generic view)
Models
Below are my models I have not use many to many field instead I created a Intermediate Table if the solution is also possible by using manytomanyfield than also suggest
class Employee(models.Model):
employeeid = models.IntegerField()
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
phone_no = models.CharField(max_length=10)
date_of_birth = models.DateField()
email = models.EmailField(unique=True)
password = models.CharField(max_length=50)
designation = models.CharField(max_length=50)
dept_id = models.ForeignKey(Department, on_delete=models.SET_NULL, null=True, blank=True)
class Meta:
ordering = ('id',)
def __str__(self):
return self.emp_name
class Project(models.Model):
projectname = models.CharField(max_length=50, unique=True,)
project_status = models.CharField(max_length=50)
description = models.TextField()
start_date = models.DateField(auto_now_add=True)
due_date = models.DateField()
class Meta:
ordering = ('id',)
def __str__(self):
return self.projectname
class EmpProject(models.Model):
emp_id = models.ForeignKey(Employee,on_delete=models.SET_NULL, null=True, blank=True)
project_id = models.ForeignKey(Project, on_delete=models.SET_NULL, null=True, blank=True)
class Meta:
unique_together = [['emp_id','project_id']]
ordering = ('project_id',)
def __str__(self):
return self.emp_id
Serializer
class EmployeeSerializer(serializers.ModelSerializer):
dept_id = serializers.SlugRelatedField(queryset=Department.objects.all(), slug_field='dept_name')
class Meta:
model = Employee
fields = [
'id',
'employeeid',
'first_name',
'last_name',
'phone_no',
'date_of_birth',
'email',
'password',
'designation',
'dept_id',
]
class ProjectSerializer(serializers.ModelSerializer):
class Meta:
model = Project
fields = [
'id',
'projectname',
'project_status',
'description',
'start_date',
'due_date' ,
]
class EmpProjectSerializer(serializers.ModelSerializer):
emp_id=serializers.SlugRelatedField(queryset=Employee.objects.all(),slug_field='employeeid')
project_id=serializers.SlugRelatedField(queryset=Project.objects.all(),slug_field='projectname')
class Meta:
model = EmpProject
fields = [
'emp_id',
'project_id',
]
You can try something like this:
Project.objects.filter(id__in=EmpProject.objects.filter(id__in=emp_id).values("project_id"), project_status="Pending")
Few points worth mentioning:
It's good idea to use a intermediate table when we want to have extra data related to association. But for that kindly have a look at through attribute supported in ManyToManyField https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.ManyToManyField.through
project_status is CharField, I think you should consider ChoiceField, charfield may introduce lots of dirty data in database.
I'm trying to serialize nested relations, but got an error during create model from request: 'MeasureUnit' object has no attribute 'unit'
What am I doing wrong? I'm just trying to create model MeasureItem, but got error in MeasureUnit somehow.
My models:
from django.db import models
from measure_unit.models import MeasureUnit
from main_user.models import MainUser
class Item(models.Model):
code = models.CharField(unique=True, max_length=15)
current_code = models.CharField(blank=True, null=True, max_length=15)
title = models.CharField(default='', max_length=100)
description = models.TextField(blank=True, null=True)
measure_units = models.ManyToManyField(MeasureUnit, through='MeasureItem', through_fields=('item', 'unit'), blank=True)
class Meta:
ordering = ('created_at',)
class MeasureItem(models.Model):
item = models.ForeignKey(Item, on_delete=models.CASCADE, blank=True, null=True)
unit = models.ForeignKey(MeasureUnit, on_delete=models.CASCADE, blank=True, null=True)
quantity = models.IntegerField(default=0)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ('created_at',)
My serializer:
from rest_framework import serializers
from .models import Item, MeasureItem
class MeasureUnitSerializer(serializers.ModelSerializer):
class Meta:
model = MeasureItem
fields = ('id', 'unit')
class ItemAdminSerializer(serializers.ModelSerializer):
measure_units = MeasureUnitSerializer(many=True)
class Meta:
model = Item
fields = ('id', 'code', 'current_code', 'title', 'description', 'measure_units')
def create(self, validated_data):
units_data = validated_data.pop('measure_units')
item = Item.objects.create(**validated_data)
for unit_data in units_data:
try:
measure_unit = unit_data['unit']
MeasureItem.objects.create(unit=measure_unit, item=item)
except Exception as e:
print(str(e))
return item
return item
MeasureUnitSerializer is ModelSerializer for MeasureItem model, but you use it for MeasureUnit model in ItemAdminSerializer:
measure_units = MeasureUnitSerializer(many=True)
Since MeasureUnit doesn't have unit field you see error.
You could try to specify source argument of measure_units field:
measure_units = MeasureUnitSerializer(source='measureitem_set', many=True)