How to join models in django serializers? - python

I'm trying to join two models, but I got the wrong result. How to do it right?
My models:
class MoocherPage(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=False)
name = models.CharField(max_length=48, unique=True, blank=False, null=False)
bio = models.TextField(blank=False, null=False)
class MoocherResource(models.Model):
url = models.URLField(blank=False, null=False)
moocher = models.ForeignKey(MoocherPage, on_delete=models.CASCADE)
And serializers:
class MoocherResourceSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
URL_FIELD_NAME = 'url'
model = MoocherResource
fields = ('url', )
class MoocherPageSerializer(serializers.ModelSerializer):
resources = MoocherResourceSerializer(many=True, read_only=True)
class Meta:
model = MoocherPage
fields = ('name', 'bio', 'resources')
depth = 1
I expected
{
"name": "KissofLove",
"bio": "I'm the kiss of love and I collect money for all lovers of the world.",
"resources": ["https://stackoverflow.com/users/KissofLove"]
}
But the resources was not included.
When I change read_only=True to False in the nested serializer an error appears.
AttributeError: Original exception text was: 'MoocherPage' object has no attribute 'resources'.

Your models
class MoocherPage(models.Model):
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=False)
name = models.CharField(max_length=48, unique=True, blank=False, null=False)
bio = models.TextField(blank=False, null=False)
class MoocherResource(models.Model):
url = models.URLField(blank=False, null=False)
moocher = models.ForeignKey(MoocherPage, on_delete=models.CASCADE)
and your serializers,
from rest_framework.serializers import *
class ResourceListingField(RelatedField):
def to_representation(self, value):
return value.url
class MoocherPageSerializer(ModelSerializer):
resources = ResourceListingField(many=True, source='moocherresource_set', read_only=True)
class Meta:
model = MoocherPage
fields = ['name', 'bio', 'resources']
This returns the desired
{
"name": "KissOfLove",
"bio": "I'm the kiss of love and I collect money for all lovers of the world.",
"resources": ["https://stackoverflow.com/users/KissofLove"]
}
response.
Check out Custom relational fields

Related

DRF: How can I show all fields of a m2m field instead of just the name

I'm building a simple Lead Generator using Django Rest Framework.
I'm trying to show a list of "assigned facilities" inside a lead using django's many to many fields. But all it will show inside the API is the id of each of the facilities associated to the many to many field. How do I access more than just the name using DRF? I basically need to show the name, a description and a picture of the facility from each facility record.
serializers.py
class LeadUpdateSerializer(serializers.ModelSerializer):
is_owner = serializers.SerializerMethodField()
class Meta:
model = Lead
fields = (
"id",
"first_name",
"last_name",
"PrimaryAddress",
"assigned_facilities",
)
read_only_fields = ("id", "is_owner")
def get_is_owner(self, obj):
user = self.context["request"].user
return obj.agent == user
models.py
class Facility(models.Model):
UUID = models.CharField(max_length=150, null=True, blank=True)
Name = models.CharField(max_length=150, null=True, blank=False)
mainimage = models.ImageField(null=True, blank=True)
FacilityDescription = models.TextField(max_length=1000, null=True, blank=True)
def __str__(self):
return self.Name
class Lead(models.Model):
assigned_facilities = models.ManyToManyField(Facility, related_name='assigned_facilities')
created_at = models.DateTimeField(auto_now_add=True)
first_name = models.CharField(max_length=40, null=True, blank=True)
last_name = models.CharField(max_length=40, null=True, blank=True)
def __str__(self):
return f"{self.first_name} {self.last_name}"
We can like below:
class FacilitySerializer(serializers.ModelSerializer)
class Meta:
fields = (
"id",
"Name",
"mainimage",
"FacilityDescription",
)
class LeadUpdateSerializer(serializers.ModelSerializer):
assigned_facilities = FacilitySerializer(many=True)
is_owner = serializers.SerializerMethodField()
class Meta:
model = Lead
fields = (
"id",
"first_name",
"last_name",
"PrimaryAddress",
"assigned_facilities",
)
read_only_fields = ("id", "is_owner")
def get_is_owner(self, obj):
user = self.context["request"].user
return obj.agent == user

DRF display nested JSON

I have my DRF app. In my case, one wallet can have many entries such as income or expense. When I call my endpoint (viewset) I get data in this format:
[
{
"id": "d458196e-49f1-42db-8bc2-ee1dba438953",
"owner": 1,
"viewable": [],
"entry": []
}
]
How can I get the content of "entry" variable?.
class Category(models.Model):
name = models.CharField(max_length=20, unique=True)
def __str__(self):
return self.name
class BudgetEntry(models.Model):
STATE= [
('income','income'),
('expenses','expenses'),
]
amount = models.IntegerField()
entry_type = models.CharField(max_length=15, choices=STATE, null=True)
entry_category = models.ForeignKey(Category, null=True, blank=True, on_delete=models.SET_NULL)
class WalletInstance(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='owner', on_delete=models.CASCADE)
viewable = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='can_view', blank=True)
entry = models.ManyToManyField(BudgetEntry, related_name='BudgetEntry', blank=True)
Serializers.py:
class BudgetEntrySerializer(serializers.ModelSerializer):
class Meta:
model = BudgetEntry
fields = '__all__'
class WalletInstanceSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.id')
class Meta:
model = WalletInstance
fields = '__all__'
Views.py:
class WalletViewset(viewsets.ModelViewSet):
permission_classes = [IsAuthenticated]
serializer_class = WalletInstanceSerializer
def get_queryset(self):
user_id = self.request.user.id
available = WalletInstance.objects.filter(
Q(owner=user_id)
)
return available
Change your serializer like this:
class WalletInstanceSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.id')
entry = BudgetEntrySerializer(many=True, read_only=True)
class Meta:
model = WalletInstance
fields = '__all__'

How to join multiple Model in Django Rest Framework serializer

In Django, I have the following models.
class Property(models.Model):
address1 = models.CharField(max_length=512)
address2 = models.CharField(max_length=128, blank=True, null=True)
property_type = models.ForeignKey('PropertyType', models.DO_NOTHING, null=True, blank=True, default=None)
geo_info = models.ForeignKey(GeoInfo, models.DO_NOTHING)
class Meta:
indexes = [
models.Index(fields=['address1', ]),
]
db_table = 'property'
class PropertyType(models.Model):
name = models.CharField(max_length=128, blank=True, null=True)
category = models.CharField(max_length=45, blank=True, null=True)
color = models.CharField(max_length=45, blank=True, null=True)
class Meta:
db_table = 'property_type'
indexes = [
models.Index(fields=['name', ]),
]
class GeoInfo(models.Model):
zipcode = models.CharField(max_length=25, blank=True, null=True)
city = models.CharField(max_length=45, blank=True, null=True)
state = models.CharField(max_length=45, blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True, null=True)
updated_at = models.DateTimeField(auto_now=True, null=True)
class Meta:
db_table = 'geo_info'
indexes = [
models.Index(fields=['zipcode', ]),
models.Index(fields=['city', ]),
]
def __str__(self):
return '%s %s' % (self.zipcode, self.city)
I'm trying to use Django REST Framework to serialize PROPERTY model as follows.
class GeoSerializer(serializers.ModelSerializer):
class Meta:
model = GeoInfo
fields = ['zipcode', 'city', 'state']
class PropertyTypeSerializer(serializers.ModelSerializer):
class Meta:
model = PropertyType
class PropertySerializer(serializers.ModelSerializer):
address_geo = GeoSerializer(many=False, read_only=True)
prop_type = PropertyTypeSerializer(many=True, read_only=True)
class Meta:
model = Property
fields = ['id', 'address1', 'address_geo', 'prop_type']
My expected outcome for each item is like
{
"id": 1,
"address1": "test address",
"geo_info":{
"zipcode":"12121",
"city":"12121",
"state":"12121",
},
"property_type": "unknown",
}
and currently, I'm just getting the property data like
{
"id": 1,
"address1": "test address"
}
So can you help me figure out how to serialize these models?
Also, it would be great if you can help me how to flatten the outcome and avoid nested node if possible
your question is not clear fully. You asked for no nesting. This may help you -
class PropertySerializer(serializers.ModelSerializer):
zipcode=serializers.SerializerMethodField()
city=serializers.SerializerMethodField()
state=serializers.SerializerMethodField()
class Meta:
model = Property
fields = ('id','address1','zipcode','city','state','property_type')
def get_zipcode(self,instance):
return instance.geo_info.zipcode
def get_city(self,instance):
return instance.geo_info.city
def get_state(self,instance):
return instance.geo_info.state

Django Rest Framework serialization error: Object of type type is not JSON serializable

I am new to both django and python and currently trying to implement a REST api using django-rest-framework. I know there are a lot of alike questions but they are serializing objects using .json, and i am not.
I have 2 models captain and boat as follows:
//models.py
from django.db import models
class Captain(models.Model):
name = models.CharField(max_length=255, blank=False, unique=False)
last_name = models.CharField(max_length=255, blank=False, unique=False)
government_id = models.CharField(max_length=55, blank=False, unique=True)
company_name = models.CharField(max_length=255, blank=False, unique=False)
phone_number = models.CharField(max_length=55, blank=False, unique=False)
tax_id = models.CharField(max_length=55, blank=False, unique=True)
date_created = models.DateTimeField(auto_now_add=True)
date_modified = models.DateTimeField(auto_now=True)
class Boat(models.Model):
captain = models.ForeignKey(Captain, on_delete=models.CASCADE, null=True, blank=True, related_name='boats')
name = models.CharField(max_length=55, blank=False)
journey_type = models.CharField(max_length=55, null=True, blank=True)
category = models.CharField(max_length=55, null=True, blank=True)
passenger_capacity = models.IntegerField()
crew_count = models.IntegerField()
have_ac = models.IntegerField(default=0)
year_built = models.DateField
year_restored = models.DateField(blank=True)
engine = models.CharField(max_length=255, blank=True, null=True)
generator = models.CharField(max_length=255, blank=True, null=True)
width = models.CharField(max_length=255, null=True)
height = models.CharField(max_length=255, null=True)
length = models.CharField(max_length=255, null=True)
wc_count = models.IntegerField(null=True)
master_cabin_count = models.IntegerField(null=True)
standart_cabin_count = models.IntegerField(blank=False, null=False)
date_created = models.DateTimeField(auto_now_add=True)
date_modified = models.DateTimeField(auto_now=True)
As you can see each boat has one captain and one captain can have many boats. So in database there is a captain_id field for Boat table. I have defined two serializers for each model:
//serializers.py
from rest_framework import serializers
from .models import Captain, Boat
class CaptainSerializer(serializers.ModelSerializer):
class Meta:
model = Captain
fields = ('id', 'name', 'last_name', 'government_id', 'company_name', 'phone_number', 'tax_id', 'date_created', 'date_modified','boats')
class BoatSerializer(serializers.ModelSerializer):
captain = serializers.PrimaryKeyRelatedField(many=False, read_only=True)
class Meta:
model = Boat
fields = ('id', 'captain', 'name', 'journey_type', 'category', 'passenger_capacity', 'crew_count', 'have_ac', 'year_built', 'year_restored', 'wc_count', 'standart_cabin_count')
Then i have defined views for each model.
//views.py
from django.shortcuts import render
from rest_framework import generics
from .serializers import CaptainSerializer, BoatSerializer
from .models import Captain, Boat
class CaptainCreateView(generics.ListCreateAPIView):
queryset = Captain.objects.all()
serializer_class = CaptainSerializer
def perform_create(self, serializer):
serializer.save()
class CaptainDetailsView(generics.RetrieveUpdateDestroyAPIView):
lookup_field = 'pk'
serializer_class = CaptainSerializer
queryset = Captain.objects.all()
class BoatCreateView(generics.ListCreateAPIView):
queryset = Boat.objects.all()
serializer_class = BoatSerializer
def perform_create(self, serializer):
serializer.save()
When i go to page localhost:port/captains/ (or /GET/captains from postman) i can have captain models including the boats he has.
But The problem is : when i go to localhost:port/boats (or postman) it gives,
Object of type type is not JSON serializable
Exception Type: TypeError at /boats/
Exception Value: Object of type type is not JSON serializable
Any ideas how can i fix this? Thanks in advance.
I think the year_built field in the Boat model is not well defined (you're assigning the class DateField but not creating an instance of it):
class Boat(models.Model):
year_built = models.DateField # should be models.DateField()

Django - Serialize parents associations

I am trying to create a serialized RESTful response from a One to N relationship.
I have a table Lexicon, primary key lexicon_id, I have another table lexicon_attributes, primary key lexicon_attribute_id, foreign key lexicon_id
class Lexicons(models.Model):
"""
Holds all words
"""
lexicon_id = models.BigIntegerField(primary_key=True)
word = models.TextField(blank=True, null=True)
date_created = models.DateTimeField(blank=True, null=True)
date_modified = models.DateTimeField(blank=True, null=True)
class Meta:
managed = True
db_table = 'lexicons'
class LexiconAttributes(models.Model):
class Meta:
managed = True
db_table = 'lexicon_attributes'
lexicon_attribute_id = models.AutoField(primary_key=True)
lexicon_id = models.ForeignKey('Lexicons', db_column='lexicon_id', related_name="lexicon_attributes")
is_verb = models.CharField(max_length=1, blank=True, null=True)
is_plural = models.CharField(max_length=1, blank=True, null=True)
is_past_tense = models.CharField(max_length=1, blank=True, null=True)
serializer
class LexiconAttributesSerializer(serializers.ModelSerializer):
class Meta:
model = LexiconAttributes
fields = '__all__'
class LexiconsSerializer(serializers.ModelSerializer):
lexicon_attributes = LexiconAttributesSerializer(source='*', many=False)
class Meta:
model = Lexicons
When I make a request for /lexicons/2/
{
"lexicon_id": 2,
"lexicon_attributes": {
"lexicon_id": 2
},
"word": "computer",
"date_created": "2015-07-30T20:29:19Z",
"date_modified": "2015-07-30T20:29:19Z"
}
How do I get the other fields in lexicon_attributes table
FYI I am week two into Django, my app was originally done in Cakephp3
class LexiconsSerializer(serializers.ModelSerializer):
lexicon_attributes = LexiconAttributesSerializer()
class Meta:
model = Lexicons
fields = '__all__'
fixed the problem for me after 3 days

Categories