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
Related
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__'
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
I want to update a list of instances with the total number of books links to the category.
The response is as mentioned below. I have some books link to 'History' for example. How do I update the total number on the list whenever I call it?
[
{
"id": 1,
"category_name": "History",
"category_code": "his",
"is_tab": true,
"add_time": "2020-03-02T15:56:58.469917Z",
"total_number": 0
},
{
"id": 2,
"category_name": "Romance",
"category_code": "ROM",
"is_tab": true,
"add_time": "2020-05-22T17:02:47.919479Z",
"total_number": 0
},
{
"id": 3,
"category_name": "Sci-fic",
"category_code": "S-F",
"is_tab": true,
"add_time": "2020-05-22T17:04:57.896846Z",
"total_number": 0
}
]
serializer.py
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = BookCategory
fields = ('id', 'category_name', 'category_code', "is_tab", 'add_time', 'total_number')
view.py
class BookCategoryDetailView(ListCreateAPIView, RetrieveModelMixin):
queryset = BookCategory.objects.all()
serializer_class = CategorySerializer
model.py
class BookCategory(models.Model):
category_name = models.CharField(default="", max_length=30, verbose_name='Category name')
category_code = models.CharField(default="", max_length=30, verbose_name='Category code')
is_tab = models.BooleanField(default=False, verbose_name='is Navigate')
add_time = models.DateTimeField(auto_now_add=True, verbose_name='Added time')
total_number = models.BigIntegerField(default=0, verbose_name='Total Number', editable=False)
class Meta:
verbose_name = 'Type Category'
verbose_name_plural = verbose_name
db_table = 'Book Genre'
def __str__(self):
return self.category_name
book model
class Book(models.Model):
BOOK_STATUS = (
('Ongoing', u'Ongoing'),
('Completed', u'Completed')
)
book_name = models.CharField(default="", max_length=30, verbose_name='Book name', unique=True)
book_image = models.ImageField(default="", max_length=30, verbose_name='Book image')
book_status = models.CharField(choices=BOOK_STATUS, default='Ongoing', verbose_name='Book Status', max_length=150,
null=True)
book_author = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.SET_NULL,
verbose_name='author',
related_name='author',
null=True)
book_type = models.ForeignKey(BookCategory,
on_delete=models.CASCADE,
verbose_name='book type',
related_name='book_type',
null=True)
book_short_description = models.TextField(verbose_name='Short description', default='')
book_description = models.TextField(verbose_name='Book Description', default='')
# non-editable values
total_words = models.IntegerField(verbose_name='Total_words', default=0, editable=False)
chapter_count = models.IntegerField(verbose_name='Chapter Count', default=0, editable=False)
total_vote = models.IntegerField(verbose_name='Total vote', default=0, editable=False)
weekly_vote = models.IntegerField(verbose_name='Weekly vote', default=0, editable=False)
total_click = models.IntegerField(verbose_name='Total Click', default=0, editable=False)
fav_num = models.IntegerField(verbose_name='Total favorite number', default=0, editable=False)
added_time = models.DateTimeField(verbose_name='Added time', auto_now_add=True, editable=False)
last_update = models.DateTimeField(verbose_name='last update', auto_now=True, editable=False)
def get_chapter_number(self):
chapter_count = Chapter.objects.filter(self.id).count()
return chapter_count
def get_book_name(self):
return self.book_name
class Meta:
db_table = 'Books'
verbose_name = 'Novel'
verbose_name_plural = verbose_name
Any help would be much appreciated!
A common misconception is to give th related_name=… parameter [Django-doc] the same name as the relation itself. The related_name is the name of the relation in reverse, so the relation Django creates to obtain the Books from a given BookCategory for example. Therefore you can rename these to:
class Book(models.Model):
# …
book_author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET_NULL,
verbose_name='author',
related_name='authored_books',
null=True
)
book_type = models.ForeignKey(
BookCategory,
on_delete=models.CASCADE,
verbose_name='book type',
related_name='books',
null=True
)
# …
It is also better not to store duplicated (aggregate) data in the database, so storing the number of books is usually not a good idea. It turns out that keeping data in sync, even on the same database, is harder than one would expect. It means that if you create a book, delete a book, or change the category of a book, you need to update the count. Furthermore some removals will be triggered by other removals (cascading deletes), or by another tool than through the Django ORM, so that will only make the problem more complicated.
Therefore it is better to remove that field:
class BookCategory(models.Model):
category_name = models.CharField(default="", max_length=30, verbose_name='Category name')
category_code = models.CharField(default="", max_length=30, verbose_name='Category code')
is_tab = models.BooleanField(default=False, verbose_name='is Navigate')
add_time = models.DateTimeField(auto_now_add=True, verbose_name='Added time')
# no total_number
class Meta:
verbose_name = 'Type Category'
verbose_name_plural = 'Type categories'
db_table = 'Book Genre'
def __str__(self):
return self.category_name
You can obtain the number of books per BookCategory by annotating:
from django.db.models import Count
BookCategory.objects.annotate(
total_number=Count('books')
)
This means that the BookCategorys that arise from this queryset will have an extra attribute .total_number that contains the number of related Book objects.
Next we can update the serialzier to work with this total_number:
class CategorySerializer(serializers.ModelSerializer):
total_number = serializers.IntegerField(read_only=True)
class Meta:
model = BookCategory
fields = ('id', 'category_name', 'category_code', "is_tab", 'add_time', 'total_number')
and finally in the BookCategoryDetailView we pass the annotated queryset:
from django.db.models import Count
class BookCategoryDetailView(RetrieveModelMixin, ListCreateAPIView):
queryset = BookCategory.objects.annotate(total_number=Count('books'))
serializer_class = CategorySerializer
I have two models ProductTypeModel and ProductModel, product_type is the foreign key in the product. Then I wrote a ModelSerializer for a product to get all the entries of ProductModel and along with some additional info.
Now I'm unable to get product_sub_type from the ProductTypeModel in ProductSerializer
I have tried SlugRelatedField in serializers, tried to set slug_field=product_sub_type and slug_field=product_type__product_sub_type and slug_field=product_type.product_sub_type
models.py
class ProductType(models.Model):
"""Product type model."""
id = models.UUIDField(
primary_key=True,
default=uuid.uuid4,
editable=False
)
hsn = models.ForeignKey(
HSN,
related_name='product_types',
on_delete=models.SET_NULL,
null=True, blank=True
)
product_type = models.CharField(max_length=255, null=True, blank=True)
product_sub_type = models.CharField(max_length=255, db_index=True)
description = models.CharField(max_length=255, null=True, blank=True)
def __str__(self):
return str(self.product_type)
def get_sub_type(self):
return str(self.product_sub_type)
class Meta:
db_table = 'ProductTypes'
unique_together = ('product_type', 'product_sub_type')
class Product(models.Model):
"""Products model."""
product_id = models.UUIDField(
primary_key=True,
default=uuid.uuid4,
editable=False
)
product_type = models.ForeignKey(
ProductType,
related_name='related_products',
on_delete=models.SET_NULL,
blank=True, null=True
)
name = models.CharField(max_length=255, db_index=True)
code_name = models.CharField(max_length=255, null=True, blank=True)
href = models.CharField(max_length=500, blank=True, null=True)
full_name = models.CharField(max_length=255, null=True, blank=True, db_index=True)
manufacturer = models.ForeignKey(
Manufacturer,
related_name='manufactured_products',
on_delete=models.SET_NULL,
null=True, blank=True
)
packing = models.CharField(max_length=255, null=True, blank=True)
packing_detail = models.CharField(max_length=255, null=True, blank=True)
mrp = models.DecimalField(
max_digits=8,
decimal_places=2,
null=True, blank=True
)
created_at = models.DateTimeField(
'created at',
db_index=True,
default=timezone.now
)
def __str__(self):
return str(self.full_name)
class Meta:
db_table = 'Products'
unique_together = ('code_name', 'product_type')
serializers.py
class ProductTypeSerializer(serializers.ModelSerializer):
# Serialize/Deserialize ProductType instance.
class Meta:
model = ProductType
fields = (
'id', 'hsn',
'product_type', 'product_sub_type',
'description'
)
read_only_fields = ('id', )
class ProductSerializer(serializers.ModelSerializer):
# Serialize/Deserialize Product instance.
manufacturer = serializers.StringRelatedField()
manufacturer_id = serializers.PrimaryKeyRelatedField(read_only=True)
product_sub_type = serializers.SlugRelatedField(slug_field=????)
class Meta:
model = Product
fields = (
'product_id',
'product_type', 'product_sub_type',
'name', 'code_name',
'manufacturer', 'manufacturer_id',
'full_name',
'packing', 'packing_detail',
'mrp'
)
read_only_fields = (
'product_id', 'created_at',
'product_type', 'manufacturer_id'
)
with slug_field=product_sub_type it returns
ImproperlyConfigured at /products/
Field name product_sub_type is not valid for model Product.
with slug_field=product_type.product_sub_type it returns
AttributeError at /products/
Got AttributeError when attempting to get a value for field product_sub_type on serializer ProductSerializer.The serializer field might be named incorrectly and not match any attribute or key on the Product instance.
I want the serializer to return something like this:
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"product_id": "fffcf7ba-5c6d-4190-96d2-cc9125e18e71",
"product_type": "1b3dd955-b67e-4ca3-9561-6d1704ff7c91",
"product_sub_type": "Capsules",
"name": "Enshine Toothpaste",
"code_name": null,
"manufacturer": "Leeford Healthcare Ltd",
"manufacturer_id": 2524,
"full_name": "Enshine Toothpaste",
"packing": null,
"packing_detail": null,
"mrp": null
}
]
}
Providing the attributes slug_field and source works for a read-only SlugRelatedField. To allow writing in this field the queryset attribute must also be provided
class ProductSerializer(serializers.ModelSerializer):
...
product_sub_type = serializers.SlugRelatedField(
slug_field='product_sub_type',
source='product_type',
queryset=ProductType.objects.all()
)
According to documentation slug_field should be a field that uniquely identifies any given instance
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