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)
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'm trying to show my all children category from parent category. I want to just hit one API end and show all tables which is related to that item. I want to hit "Master-Category" and show all releated "Category","Sub-Category" and "Root-Item" in Hierarchy form. I display all the data but cannot in Hierarchy form. Can anyone please give me the solution for this problem.
Model.py
from django.db import models
from django.contrib.auth.models import User
class MasterCategory(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True,
verbose_name="Created By")
title = models.CharField(max_length=100, null=False, blank=False)
description = models.TextField(default='')
def __str__(self):
return str(self.title)
#property
def category(self):
data = NewCategory.objects.filter(master_category__id=self.id).values
return data
#property
def sub_category(self):
data = NewSubcategory.objects.filter(category__id=self.id).values
return data
#property
def root_item(self):
data = Rootitem.objects.filter(sub_category__id=self.id).values
return data
class NewCategory(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True,
verbose_name="Created By")
title = models.CharField(max_length=100, null=False, blank=False)
description = models.TextField(default="")
master_category = models.ForeignKey(
MasterCategory, on_delete=models.CASCADE, null=True, blank=True)
def __str__(self):
return str(self.title)
class NewSubcategory(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True,
verbose_name="Created By")
title = models.CharField(max_length=100, null=False, blank=False)
description = models.TextField(default="")
category = models.ForeignKey(NewCategory, on_delete=models.CASCADE, null=True,
blank=True)
def __str__(self):
return str(self.title)
class Rootitem(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True,
verbose_name="Created By")
title = models.CharField(max_length=100, null=False, blank=False)
description = models.TextField(default="")
sub_category = models.ForeignKey(NewSubcategory, on_delete=models.CASCADE,
null=True, blank=True)
def __str__(self):
return str(self.title)
Serializers.py
I add #property function name in MasterCategorySerializer fields, "category", "sub_category", "root_item"
from .models import MasterCategory, NewCategory, NewSubcategory, Rootitem
from rest_framework import serializers
class MasterCategorySerializer(serializers.ModelSerializer):
class Meta:
model = MasterCategory
fields = ["title", 'category', 'sub_category', 'root_item']
class NewCategorySerializer(serializers.ModelSerializer):
class Meta:
model = NewCategory
fields = "__all__"
class NewSubcategorySerializer(serializers.ModelSerializer):
new_cat = NewCategorySerializer(source='category',read_only=True, many=True)
class Meta:
model = NewSubcategory
fields = "__all__"
class RootitemSerializer(serializers.ModelSerializer):
class Meta:
model = Rootitem
fields = "__all__"
**Viewset.py**
from API_app.models import MasterCategory
from API_app.serializers import MasterCategorySerializer
from rest_framework import viewsets
class MasterCategoryViewSet(viewsets.ModelViewSet):
queryset = MasterCategory.objects.all()
serializer_class = MasterCategorySerializer
My Desired Output, what i want.
{
Electronics <---- Master-Category
{
Smart-Phone <---- Category
{
Samsung <---- Sub-Category
{
Samsung S20 Ultra <---- Root-Item
}
}
}
}
Change your serializers as below. For this nested structure you don't need properties. As tables are connected with foreign key you can define related name between models and assign to its serializer. Default related name between table is tablename_set.
class RootitemSerializer(serializers.ModelSerializer):
class Meta:
model = Rootitem
fields = "__all__"
class NewSubcategorySerializer(serializers.ModelSerializer):
rootitem_set = RootitemSerializer(many=True)
class Meta:
model = NewSubcategory
fields = "__all__"
class NewCategorySerializer(serializers.ModelSerializer):
newsubcategory_set = NewSubcategorySerializer(many=True)
class Meta:
model = NewCategory
fields = "__all__"
class MasterCategorySerializer(serializers.ModelSerializer):
newcategory_set = NewCategorySerializer(many=True)
class Meta:
model = MasterCategory
fields = "__all__"
We have relationship between MasterCategory and NewCategory. As you don't define related_name therefore related name is newcategory_set and its response is NewCategorySeralizer. Make many=True because they are related with foreign key as there can be multiple newcategory related to mastercategory. Other relations are same as above explanation.
If you want to change this default related name then look at related_name, you can define it inside models.ForeignKey()
I have problem with Django restframe work i have 2 table that one of them is a foreign key to another i have used RelatedField in serializer but i get an error:'Relational field must provide a queryset argument,
can someone help me in this case
my code is as below:
class DocTable(models.Model):
project = models.CharField(max_length=1000, null=True, blank=True)
document_no = models.CharField(max_length=1000, null=True, blank=True)
document_title = models.TextField(null=True, default='', blank=True)
class PlanTable(models.Model):
document = models.ForeignKey(DocTable, on_delete=models.CASCADE, related_name='doctable')
work_type = models.CharField(max_length=1000, null=True, blank=True)
description_work = models.TextField(null=True, default='', blank=True)
serializers.py
class DocTableSerializer(serializers.ModelSerializer):
doctable = serializers.RelatedField(many=True)
class Meta:
model = DocTable
fields = ['pk', 'project', 'document_no', 'doctable']
read_only_fields = ['pk']
class PlanTableSerializer(serializers.ModelSerializer):
class Meta:
model = PlanTable
fields = ['pk', 'document', 'work_type', 'description_work']
read_only_fields = ['pk']
views.py
class DocTableListView(generics.ListAPIView):
lookup_field = 'pk'
serializer_class = DocTableSerializer
def get_queryset(self):
return PlanTable.objects.all()
def get_object(self):
pk = self.kwargs.get('pk')
return PlanTable.objects.get(pk=pk)
You have to provide queryset in RelatedField like this.
class DocTableSerializer(serializers.ModelSerializer):
doctable = serializers.RelatedField(many=True, queryset=DocTable.objects.all())
Or if you only want to use this related field for retrieving data, you can mark it as read only
doctable = serializers.RelatedField(many=True, read_only=True)
Need some advice. I set up seralization. There are no errors. But at the output I get empty tags. I broke my head, what am I doing wrong?
models.py:
class kv(models.Model):
title = models.CharField(max_length=200)
price = models.IntegerField()
address = models.CharField(max_length=200)
property_type = models.CharField(choices=realty_type_choices_admin, default='kv',
max_length=200, blank=True)
country = models.CharField(default='Россия', max_length=200)
region = models.CharField(max_length=200)
state = models.CharField(choices=state_choices_admin, default='DGO', max_length=200, blank=True, null=True)
locality_name = models.CharField(max_length=200, blank=True, null=True)
address_xml = models.CharField(max_length=200, blank=True, null=True)
city = models.CharField(max_length=100, blank=True, null=True)
serializers.py
from rest_framework import serializers
from listings.models import kv
class kvSerializerLocation(serializers.ModelSerializer):
class Meta:
model = kv
fields = ['country', 'region', 'state', 'locality_name', 'address_xml', 'city']
class kvSerializer(serializers.ModelSerializer):
category = serializers.CharField(source='get_property_type_display')
url = serializers.CharField(source='get_absolute_url', read_only=True)
country = kvSerializerLocation()
class Meta:
model = kv
fields = ['title', 'price', 'address', 'category', 'url', 'country']
views.py
from listings.models import *
from rest_framework import viewsets
from rest_framework_xml.renderers import XMLRenderer
from .serializers import kvSerializer
class KvXMLRenderer(XMLRenderer):
root_tag_name = 'feed'
item_tag_name = 'offer'
def _to_xml(self, xml, data):
super()._to_xml(xml, data)
class kvViewSet(viewsets.ModelViewSet):
queryset = Kvartiry.objects.all().filter(is_published=True)
serializer_class = kvSerializer
renderer_classes = [KvXMLRenderer]
Result:
<country>
<state/>
<locality_name/>
<address_xml/>
<city/>
</country>
It’s strange. Tags are empty, there is no region tag at all
Thank!
I don't think your implemenration would work for country because its a field, and there is no way to map that country value to your kv instance which can be utilized by kvSerializerLocation. Instead use SerializerMethodField:
class kvSerializer(serializers.ModelSerializer): # please use PascalCase for defining class name
category = serializers.CharField(source='get_property_type_display')
url = serializers.CharField(source='get_absolute_url', read_only=True)
kv_country = serializers.SerializerMethodField()
class Meta:
model = kv
fields = ['title', 'price', 'address', 'category', 'url', 'kv_country']
def get_kv_country(self, obj):
return kvSerializerLocation(obj).data
Currently I have a site, and I want the user to be able to view their liked articles. I want this to be included in the user api view that is already set up. I have tried the tracks = serializers.StringRelatedField(many=True)that is in the drf docs yet this didn't work. I have also tried the following:
from rest_framework import serializers
from articles.models import Article, CustomUser,FavoriteArticles
class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = ('title', 'content')
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = CustomUser
fields = '__all__'
class FavoriteArticleSerializer(serializers.ModelSerializer):
class Meta:
model = FavoriteArticles
fields = '__all__'
class UserProfileSerializer(serializers.ModelSerializer):
fav_title = FavoriteArticleSerializer(read_only=False)
class Meta:
model = CustomUser
fields = 'username, git, email, fav_article, fav_title, homepage'
and my models:
from django.db import models
# users/models.py
from django.contrib.auth.models import AbstractUser
from django.db.models.signals import post_save
from django.dispatch import receiver
import uuid
class ProgrammingLanguage(models.Model):
programming_language = models.CharField(max_length=120, null=False, primary_key=True, default="React")
def __str__(self):
return self.programming_language
class Article(models.Model):
title = models.CharField(max_length=25, primary_key=True)
content = models.TextField()
usedfor = models.TextField()
url=models.CharField(max_length=200, null=True)
article_programming_language = models.ForeignKey(ProgrammingLanguage, on_delete=models.CASCADE, related_name="article_programming_language", default="react")
score = models.IntegerField(max_length=5, null=0)
def __str__(self):
return self.title
class CustomUser(AbstractUser):
username = models.CharField(max_length=50, unique=True, primary_key=True)
git = models.CharField(max_length=200, null=True)
homepage = models.CharField(max_length=250, null=True)
user_programming_language = models.ForeignKey(ProgrammingLanguage, on_delete=models.CASCADE, related_name="most_used_programming_language", default="react")
def __str__(self):
return str(self.username)
class FavoriteArticles(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
fav_title = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='fav_title')
reasons_liked = models.CharField(max_length=120, null=True)
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name="user", default="tom" )
def __unicode__(self):
return '%s: %s' % (self.fav_title, self.reasons_liked)
I think you misunderstood what related_name means. It specifies how you would access a model from its reverse relationship. So I'd recommend you remove it from fields in your FavoriteArticles model and use the default Django already provides (in this case favoritearticles_set):
class FavoriteArticles(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
fav_title = models.ForeignKey(Article, on_delete=models.CASCADE)
reasons_liked = models.CharField(max_length=120, null=True)
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, default="tom")
def __unicode__(self):
return '%s: %s' % (self.fav_title, self.reasons_liked)
This way, you can access favorite articles of a user via my_user.favoritearticles_set.all(). Then, you can change your UserSerializer to include a liked_articles field which is populated from the favoritearticles_set reverse relationship to a user's FavoriteArticles using a source attribute:
class UserSerializer(serializers.ModelSerializer):
liked_articles = FavoriteArticleSerializer(source='favoritearticles_set', many=True, read_only=True)
class Meta:
model = CustomUser
# explicitly include other fields as required
fields = ('username', 'git', 'user_programming_language', 'liked_articles')
Note that we've made this a read_only field, so it will only get populated if you perform a GET request.