How do I get the whole JSON object in Django using DRF3? - python

When I make a call to my API (curl), I get the following:
{"id": 1, "name": "Sword", "persona": [1]}
I'm getting the 'id' of the persona, but not the properties within. How do I do this?
Models.py:
class Persona(models.Model):
name = models.CharField(max_length=255)
description = models.CharField(max_length=255)
icon = models.CharField(max_length=255,default='1')
def __str__(self):
return self.name
class Equipment(models.Model):
personas = models.ManyToManyField(Persona)
name = models.CharField(max_length=255)
def __str__(self):
return self.name
Serializers.py:
class EquipmentSerializer(serializers.ModelSerializer):
personas = serializers.PrimaryKeyRelatedField(queryset=Persona.objects.all(), many=True)
name = serializers.CharField(max_length=255)
class Meta:
model = Equipment
fields = ('id', 'name', 'persona')

You need two steps:
Create a Persona serializer class:
class PersonaSerializer(serializers.ModelSerializer):
class Meta:
model = Persona
Then you can "chain" this serializer to the Equipement one:
class EquipmentSerializer(serializers.ModelSerializer):
personas = PersonaSerializer(source='personas', many=True)
name = serializers.CharField(max_length=255)
class Meta:
model = Equipment
fields = ('id', 'name', 'personas')
For a deeper understanding of the above, have a look at this exemplary answer:
How do I include related model fields using Django Rest Framework?
Good luck :)

Related

how can i get category name instead of the ID

I'm working on a small project using Django Rest Framework, I have two models ( contacts and category)
So a contact can be in a category, I have a foreign key between the models, I would like to know how can I get data category name instead of getting the id number.
This is my code :
class Category(models.Model):
cat_name = models.CharField(blank=False, max_length=255)
comment = models.CharField(blank=False, max_length=255)
private = models.BooleanField(default=False)
allowed = models.BooleanField(default=False)
def __str__(self):
return self.name
class Contact(models.Model):
category = models.ForeignKey(Category, on_delete=models.DO_NOTHING)
first_name = models.CharField(max_length=60)
last_name = models.CharField(max_length=60)
My serializer
class ContactSerializer(serializers.ModelSerializer):
class Meta:
model = Contact
fields = "__all__"
Result I get :
"first_name": "John",
"last_name": "Doe",
"category": 1 ( i want to get the name of the category instead of the id )
This is one possible solution
class ContactSerializer(serializers.ModelSerializer):
class Meta:
model = Contact
fields = "__all__"
def to_representation(self, obj):
return {
"first_name": obj.first_name,
"last_name": obj.last_name,
"category": obj.category.cat_name
}
Try this:
class ContactSerializer(serializers.ModelSerializer):
category_name = serializers.SerializerMethodField('get_category_name')
def get_category_name(self, obj):
if obj.category_id:
return obj.category.cat_name
return ""
class Meta:
model = Contact
fields = "__all__"
I got into same situation.I think there is no need to write another function if you can achieve this by one line of code and adding it to fields using source.You can also try this:
class ContactSerializer(serializers.ModelSerializer):
category = serializers.CharField(source="category.cat_name", read_only=True)
class Meta:
model = Contact
fields = ['first_name','last_name', 'category']

Django Model serializer returning ID

i've created the models and serializers as below
serializers.py
class ProductCategorySerializer(ModelSerializer):
class Meta:
model = ProductCategory
fields = ['id', 'name']
#staticmethod
def get_product_category_name(obj):
return obj.product_categories.name
class ProductSerializer(ModelSerializer):
product_categories = ProductCategorySerializer
class Meta:
model = Product
fields = ['id', 'name', 'default_price', 'description', 'product_categories']
models.py
class ProductCategory(models.Model):
class Meta:
db_table = 'itw_product_category'
verbose_name = 'product category'
verbose_name_plural = 'product categories'
name = models.CharField(max_length=50)
def __str__(self):
return self.name
class Product(models.Model):
class Meta:
db_table = 'itw_product'
verbose_name = 'product'
verbose_name_plural = 'products'
name = models.CharField(max_length=50)
default_price = models.FloatField(max_length=10)
description = models.TextField(max_length=50)
deleted = models.BooleanField(default=False)
product_categories = models.ManyToManyField(ProductCategory, verbose_name='product_categories', related_name='products')
Now, when i try to create a new model, product_categories returns only the id and not the name, what should i change?
Example:
{
"id": 25,
"name": "kms",
"default_price": 932.0,
"description": "kms",
"product_categories": [
5
]
}
You can display the string value in manytomanyfield fields with this method.
However, since you can update it with its numeric value when you want to update it, you will need to use a method or a separate serializer and view for updating, deleting and creating data to view the data.
class ProductCategory(models.Model):
product_categories = StringRelatedField(many=True)
class Meta:
db_table = 'itw_product_category'
verbose_name = 'product category'
verbose_name_plural = 'product categories'
name = models.CharField(max_length=50)
def __str__(self):
return self.name
Hope this can help you. Also, please read nested relationship.
class ProductSerializer(ModelSerializer):
product_categories = ProductCategorySerializer(many=True)

Django rest framework serializer with reverse relation

I have two models where employee have relation with person model but person have no relation with employee model.
Like:
class Person(models.Model):
name = models.CharField(max_length=100)
address = models.CharField(max_length=100)
class Employee(models.Model):
person = models.ForeignKey(Person, related_name='person_info')
code = models.CharField()
In such cases I want code field data in person serializer.
I can solved this with writing method in person model or using SerializerMethodField in person serializer
like this:
def get_employee_code(self):
return Employee.objects.get(person=self).id
and add this as source in person serializer
employee_code = serializers.CharField(source='get_employee_code')
Or adding employee serializer into person serialiszer
class PersonSerializer(serializers.ModelSerializer):
employee = EmployeeSerializer()
class Meta:
model = Person
fields = ('name', 'address', 'employee')
But i was trying to do this with reverse relation but i can't. I have tried like this, it gives an error
Serializer:
class PersonSerializer(serializers.ModelSerializer):
employee_code = serializers.CharField(source='person_info.code')
class Meta:
model = Person
fields = ('name', 'address', 'employee_code')
How can i solve this with reverse relation?
At the moment because you are using a ForeignKey field on the person attribute, it means that its returning a list when you access the reverse relation.
One solution would be to use a slug related field, though this must have many and read_only set to True, and will return a list because of the ForeignKey field.
class PersonSerializer(serializers.ModelSerializer):
employee_code = serializers.SlugRelatedField(
source='person_info',
slug_field='code',
many=True,
read_only=True,
)
class Meta:
model = Person
fields = ('name', 'address', 'employee_code')
The other option is to change your ForeignKey into a OneToOneField, which would still need read_only set to True but it will not return a list.
class Person(models.Model):
name = models.CharField(max_length=100)
address = models.CharField(max_length=100)
class Employee(models.Model):
person = models.OneToOneField(Person, related_name='person_info')
code = models.CharField()
class PersonSerializer(serializers.ModelSerializer):
employee_code = serializers.SlugRelatedField(
source='person_info',
slug_field='code',
read_only=True,
)
class Meta:
model = Person
fields = ('name', 'address', 'employee_code')
Or, if you don't want to change the ForeignKey, you could add a employee_code property method to the model instead to return the first employee code in the person_info relation.
class Person(models.Model):
name = models.CharField(max_length=100)
address = models.CharField(max_length=100)
#property
def employee_code(self):
employees = self.person_info.filter()
if employees.exists():
return employees.first().code
return ''
class Employee(models.Model):
person = models.OneToOneField(Person, related_name='person_info')
code = models.CharField()
class PersonSerializer(serializers.ModelSerializer):
employee_code = serializers.CharField(
read_only=True,
)
class Meta:
model = Person
fields = ('name', 'address', 'employee_code')
you can access the reverse relation with custom SerializerMethodField()
class PersonSerializer(serializers.ModelSerializer):
employee_code = serializers.SerializerMethodField()
def get_employee_code(self, obj):
return obj.person_info.code
class Meta:
model = Person
fields = ('name', 'address', 'employee_code')

Nested Relationship Serializer Rest Framework Not Displaying Properly

I'm trying to display the attributes in the Disease Model and Evidence Model, but the attributes that is displayed on the end link are only those attributes that are present in the Rule Model.
Models.py :-
class Rule(models.Model):
disease = models.ForeignKey(Disease, default=0,related_name="DRules")
evidence = models.ForeignKey(Evidence, default=0,related_name="ERules")
measure_of_belief = models.PositiveIntegerField( \
help_text="The measure of belief (percentage) that a disease is present given this evidence exists", \
default=0,validators=[MinValueValidator(0), MaxValueValidator(100)])
measure_of_disbelief = models.PositiveIntegerField( \
help_text="The measure of disbelief (percentage) that a disease is present given an evidence does not exists", \
default=0,validators=[MinValueValidator(0), MaxValueValidator(100)])
archived = models.BooleanField(default=False)
def __str__(self):
return "{}-{}".format(self.disease, self.evidence)
class Meta:
verbose_name = "Rule"
verbose_name_plural = "Rules"
unique_together = ('disease', 'evidence',)
class Disease(models.Model):
"""
The model where the category will be stored
"""
name = models.CharField(max_length=255)
advise = models.CharField(max_length=500,blank=True)
archived = models.BooleanField(default=False)
def __str__(self):
return self.name
class Meta:
verbose_name = "Disease"
verbose_name_plural = "Diseases"
class Evidence(models.Model):
evidence_choices = {
("Observable Evidence", ("Observable Evidence")),
("Cause", ("Cause"))
}
name = models.CharField(max_length=255)
question = models.CharField(max_length=500)
evidence_type = models.CharField(choices = evidence_choices,max_length=20,default="Observable Evidences")
archived = models.BooleanField(default=False)
image_name = models.ImageField(upload_to='media/', default='media/None/no-img.jpg')
def __str__(self):
return self.name
class Meta:
verbose_name = "Evidence"
verbose_name_plural = "Evidences"
Serializers.py
class DiseaseSerializer(serializers.ModelSerializer):
class Meta:
model = Disease
fields = '__all__'
class EvidenceSerializer(serializers.ModelSerializer):
class Meta:
model = Evidence
fields = '__all__'
class RuleSerializer(serializers.ModelSerializer):
DRules = DiseaseSerializer(many=True,read_only=True)
ERules = EvidenceSerializer(many=True,read_only=True)
class Meta:
model = Rule
fields = ('measure_of_belief','disease','evidence','DRules','ERules')
views.py:-
class ShowDiseaseProfile(APIView):
def get(self,request,profileid):
profile = Rule.objects.filter(
disease_id=profileid)
serializer = RuleSerializer(
profile,many=True)
return Response(serializer.data)
What I'm trying to accomplish is to display all data that is present on the disease, evidence, and rule.
There is no error or crashing, the value from the disease model and evidence model is just not displaying.
Here's the result
EDIT: previous answer was incorrect. Updated the answer.
You are using incorrect field names in your serializer. Below is the correct one:
class RuleSerializer(serializers.ModelSerializer):
disease = DiseaseSerializer(many=True,read_only=True)
evidence = EvidenceSerializer(many=True,read_only=True)
class Meta:
model = Rule
fields = ('measure_of_belief','disease','evidence','DRules','ERules')
related_name param on the foreign key field is used for reverse lookups. Checkout the docs for a proper explanation. For example:
disease = Disease.objects.get(id=200)
d_rules = disease.DRules.all()
Use select_related query to optimize the sql query. Select related uses a join to fetch the data in one sql operation.
class ShowDiseaseProfile(APIView):
def get(self,request,profileid):
profile = (Rule.objects.filter(disease_id=profileid)
.select_related('disease', 'evidence'))
serializer = RuleSerializer(
profile,many=True)
return Response(serializer.data)

Django REST Framework Serializer returning object instead of data

I am writing a simple database for the condo I live in which has a list of people, units, unit type (home vs parking space), and unitholder (join table for many-to-many relationship between a person and a unit) - one person can be the owner of a unit type of "home" while renting a parking space.
This is my model:
class Person(models.Model):
first_name = models.CharField(max_length=30, null=False)
last_name = models.CharField(max_length=30, null=False)
phone = models.CharField(max_length=20)
email = models.EmailField(max_length=20)
class UnitType(models.Model):
description = models.CharField(max_length=30)
class Unit(models.Model):
unit_number = models.IntegerField(null=False, unique=True)
unit_type = models.ForeignKey(UnitType, null=False)
unitholders = models.ManyToManyField(Person, through='UnitHolder')
class UnitHolderType(models.Model):
description = models.CharField(max_length=30)
class UnitHolder(models.Model):
person = models.ForeignKey(Person)
unit = models.ForeignKey(Unit)
unitholder_type = models.ForeignKey(UnitHolderType)
This is my view:
class PersonViewSet(viewsets.ModelViewSet):
queryset = Person.objects.all()
serializer_class = PersonSerializer
class UnitHolderTypeViewSet(viewsets.ModelViewSet):
queryset = UnitHolderType.objects.all()
serializer_class = UnitHolderTypeSerializer
class UnitViewSet(viewsets.ModelViewSet):
queryset = Unit.objects.all()
serializer_class = UnitSerializer
class UnitHolderViewSet(viewsets.ModelViewSet):
queryset = UnitHolder.objects.all()
serializer_class = UnitHolderSerializer
class UnitTypeViewSet(viewsets.ModelViewSet):
queryset = UnitType.objects.all()
serializer_class = UnitTypeSerializer
This is my serializer:
class UnitSerializer(serializers.ModelSerializer):
unit_type = serializers.SlugRelatedField(
queryset=UnitType.objects.all(), slug_field='description'
)
class Meta:
model = Unit
fields = ('unit_number', 'unit_type', 'unitholders')
class UnitTypeSerializer(serializers.ModelSerializer):
class Meta:
model = UnitType
class PersonSerializer(serializers.ModelSerializer):
class Meta:
model = Person
class UnitHolderSerializer(serializers.ModelSerializer):
person = serializers.PrimaryKeyRelatedField(many=False, read_only=True)
unit = serializers.PrimaryKeyRelatedField(many=False, read_only=True)
class Meta:
model = UnitHolder
fields = ('person', 'unit', 'unitholder_type')
class UnitHolderTypeSerializer(serializers.ModelSerializer):
class Meta:
model = UnitHolderType
The problem:
When I query the /units endpoint like the following:
u = requests.get('http://localhost:8000/units').json()
My response looks like this:
[{'unit_type': 'Home', 'unit_number': 614, 'unitholders': [1]}]
What I want back is something like this:
[
{
'unit_type': 'Home',
'unit_number': 614,
'unitholders': [
{
'id: 1,
'first_name': 'myfirstname',
'last_name': 'mylastname',
'unitholder_type': 'renter'
}
]
}
]
I'm pretty sure my problem is in my UnitSerializer but I am brand new to DRF and read the through the documentation but still can't seem to figure it out.
An easy solution would be using depth option:
class UnitSerializer(serializers.ModelSerializer):
unit_type = serializers.SlugRelatedField(
queryset=UnitType.objects.all(), slug_field='description'
)
class Meta:
model = Unit
fields = ('unit_number', 'unit_type', 'unitholders')
depth = 1
This will serialize all nested relations 1 level deep. If you want to have fine control over how each nested field gets serialized, you can list their serializers explicitly:
class UnitSerializer(serializers.ModelSerializer):
unit_type = serializers.SlugRelatedField(
queryset=UnitType.objects.all(), slug_field='description'
)
unitholders = UnitHolderSerializer(many=True)
class Meta:
model = Unit
fields = ('unit_number', 'unit_type', 'unitholders')
Also as a side note, you need to look into modifying your querysets inside views to prefetch related objects, otherwise you will destroy the app performance very quickly (using something like django-debug-toolbar for monitoring generated queries is very convenient):
class UnitViewSet(viewsets.ModelViewSet):
queryset = Unit.objects.all().select_related('unit_type').prefetch_related('unitholders')
serializer_class = UnitSerializer
Perhaps you must doing somethings so:
class UnitHolderViewSet(viewsets.ModelViewSet):
queryset = UnitHolder.objects.all()
unitholders = UnitHolderSerializer(read_only=True, many=True)
Django rest framework serializing many to many field

Categories

Resources