I have some problem with Django Rest Framework and manyToMany relation with Related Field. Whenn i list I have a error and when I save, it fill data in databasebut it cant display the result.
My model.py
class Product(models.Model):
name = models.CharField(max_length=100,unique=True)
description = models.TextField()
price = models.DecimalField(max_digits=9,decimal_places=3)
created = models.DateTimeField(auto_now_add=True)
edited = models.DateTimeField(auto_now_add=True)
state = models.ForeignKey('ProductState', default=1)
tax = models.ForeignKey('Tax')
categories = models.ManyToManyField('ProductCategory')
class OrderProduct(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
order = models.ForeignKey(Order, on_delete=models.CASCADE)
qty = models.IntegerField()
tax = models.ForeignKey('Tax')
class Order(models.Model):
ref = models.CharField(max_length=100,blank=True)
created = models.DateTimeField(auto_now_add=True)
state = models.ForeignKey('OrderState')
user = models.ForeignKey(User)
orderproducts = models.ManyToManyField(Product, through='OrderProduct')
my serializer.py
class OrderProductSerializer(serializers.ModelSerializer):
product = ProductSerializer(required=True)
class Meta:
model = OrderProduct
exclude = ()
read_only_fields = ('order','tax',)
def create(self, validated_data):
product = validated_data.pop('product')
return OrderProduct.objects.create(tax=product['product'].tax, **product)
class OrderSerializer(serializers.ModelSerializer):
orderproducts = OrderProductSerializer(many=True, required=True)
def create(self, validated_data):
products = validated_data.pop('orderproduct')
order = Order.objects.create(**validated_data)
for product in products:
op = OrderProduct.objects.create(product=product['product'], tax=product['product'].tax, order=order, qty=product['qty'] )
op.save()
order.save()
return order;
class Meta:
model = Order
exclude = ()
read_only_fields = ()
class ProductSerializer(serializers.ModelSerializer):
categories = ProductCategorySerializer(many=True, required=True)
tax = TaxSerializer(many=False, required=True)
state = OrderStateSerializer(many=False, required=False)
class Meta:
model = Product
exclude = ()
and my view.py
class ClientOrderViewSet(viewsets.ModelViewSet):
queryset = Order.objects.all()
serializer_class = OrderSerializer
when i try to list I get this error:
Exception Type: AttributeError at /api/order/
Exception Value: Got AttributeError when attempting to get a value for field product on serializer OrderProductSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the Product instance.
Original exception text was: 'Product' object has no attribute 'product'.
Request information:
Related
Let us imagine that I have two models.
First model contains curse details and user that created this course
class Course(models.Model):
course_name = models.CharField(max_length=100, null=False)
description = models.CharField(max_length=255)
user_profile = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
and my second model is:
class Lesson(models.Model):
course = models.OneToOneField(Course, on_delete=models.CASCADE) #
# inside the course I want my APIVIEW to list only the courses that current user created.
# OnetoOne relationship does not solve the problem.
status = models.CharField(choices=STATUS, null=False, default=GOZLEMEDE,max_length=20)
tariffs = models.FloatField(max_length=5,null=False,default=0.00)
continues_off = models.CharField(max_length=2)
user_profile = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
My serializers for both Models:
class LessonSerializer(serializers.ModelSerializer):
class Meta:
model = models.Lesson
fields = ('course', 'status', 'tariffs', 'continues_off', 'user_profile')
def create(self, validated_data):
lesson = models.Lesson.objects.create(
course = validated_data['course'],
status = validated_data['status'],
tariffs=validated_data['tariffs'],
continues_off=validated_data['continues_off'],
user_profile=validated_data['user_profile']
)
return lesson
class CourseSerializer(serializers.ModelSerializer):
"""Serializers Course content"""
class Meta:
model = models.Course
fields = '__all__'
def create(self,validated_data):
course = models.Course.objects.create(
course_name = validated_data['course_name'],
description=validated_data['description'],
user_profile=validated_data['user_profile']
)
return course
My Viewset:
class LessonViewset(viewsets.ModelViewSet):
model = models.Lesson
serializer_class = serializers.LessonSerializer
authentication_classes = (SessionAuthentication,)
permission_classes = (IsAuthenticated,BasePermission,)
def get_queryset(self):
user_current = self.request.user.id
return models.Lesson.objects.filter(user_profile=user_current)
How can I get the desired result. I want to get the courses for the current user and show them as a dropdown list in my API view. Just only the courses that user created should be in the dropdown list not all.
OnetoOne relationship gives all results of course table.
i think change your view code to :
def get_queryset(self,id):
return model.objects.filter(user_profile=id)
#You do not need to call it again when you put the Lesson on the model
\
I want many to many fields to be displayed in module serializer instead of id, these are my serializers
class TrainerSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', ]
class ModuleSerializer(serializers.ModelSerializer):
trainer = serializers.CharField(source='trainer.username')
class Meta:
model = Module
fields = ['id', 'title', 'duration', 'trainer',
'publish_choice']
class Trainer(models.Model):
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
def __str__(self):
return str(self.user)
class Meta:
ordering = ['pk']
class Module(models.Model):
title = models.CharField(max_length=80, unique=True)
duration = models.IntegerField(verbose_name='Duration in Days/ Weeks', blank=True, null=True)
trainer = models.ManyToManyField(Trainer, blank=True)
detail = models.TextField(verbose_name='Program Details', blank=True, null=True)
notify = models.BooleanField(default=False)
publish_choice = models.CharField(verbose_name='Publish/ Draft',
max_length=80, choices=PUBLISH_CHOICES, default='publish')
and this is the error message
Got AttributeError when attempting to get a value for field trainer on serializer ModuleSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the Module instance.
Original exception text was: 'ManyRelatedManager' object has no attribute 'username'.
We have a depth parameter in the serializer MetaClass. we can make use of it like below. depth=1 will retrieve all fields of a relation.
class ModuleSerializer(serializers.ModelSerializer):
class Meta:
model = Module
fields = ['id', 'title', 'duration', 'trainer', 'publish_choice']
depth = 1
for reference DRF-Documentation on serializers
Its raise exception because serializers.CharField(source='trainer.username') not match ManyRelatedManager in model trainer = models.ManyToManyField(Trainer, blank=True).
If you want get all username instead of id, you can try add Custom type serialzier like this:
class ModuleSerializer(serializers.ModelSerializer):
trainer = serializers.SerializerMethodField()
def get_trainer(self, obj):
results = []
for item in obj.trainers.all():
results.append(item.username)
return results
class Meta:
model = Module
fields = ['id', 'title', 'duration', 'trainer', 'publish_choice']
trainer will return array of username relation with Module
I have form data that I want to serialize to create two objects, Account and AccountClub. AccountClub is the in between table between Account and Club with additional fields, rakeback and chip_value.
I can serialize the formdata but when i call the is.valid() function before saving, I get returned an error with the manytomany fields empty
Here is my models:
class Account(models.Model):
nickname = models.CharField(max_length=64)
club_account_id = models.IntegerField()
agent_players = models.ManyToManyField(
AgentPlayer, related_name="accounts")
clubs = models.ManyToManyField(
Club, through='AccountClub', related_name='accounts')
def __str__(self):
return f"{self.nickname} ({self.club_account_id})"
class AccountClub(models.Model):
account = models.ForeignKey(
Account, on_delete=models.CASCADE, related_name='club_deal')
club = models.ForeignKey(
Club, on_delete=models.CASCADE, related_name='account_deal')
rakeback_percentage = models.DecimalField(
max_digits=3, decimal_places=3, validators=[MinValueValidator(Decimal('0.01'))])
chip_value = models.DecimalField(max_digits=3, decimal_places=2, validators=[
MinValueValidator(Decimal('0.01'))])
def __str__(self):
return f"{self.account.nickname} belongs to {self.club.name} with rakeback of {self.rakeback_percentage} and chip value of {self.chip_value}"
Serializers:
class AgentPlayerSerializer(serializers.ModelSerializer):
class Meta:
model = AgentPlayer
fields = "__all__"
class ClubSerializer(serializers.ModelSerializer):
agent_players = AgentPlayerSerializer(many=True)
class Meta:
model = Club
fields = '__all__'
class AccountSerializer(serializers.ModelSerializer):
agent_players = AgentPlayerSerializer(many=True)
clubs = ClubSerializer(many=True)
class Meta:
model = Account
fields = [
'nickname',
'club_account_id',
'agent_players',
'clubs',
]
def create(self, validated_data):
rakeback_percentage = validated_data.pop('rakeback_percentage')
chip_value = validated_data.pop('chip_value')
club = validated_data.club
account = Account.objects.create(**validated_data)
account.account_club.rakeback_percentage = rakeback_percentage
account.account_club.chip_value = chip_value
AccountClub.create(account=account, club=club,
rakeback_percentage=rakeback_percentage, chip_value=chip_value)
return account
views.py:
def create_account(request):
data = FormParser().parse(request)
serializer = AccountSerializer(data=data)
if serializer.is_valid():
serializer.save()
next = request.POST.get('next', '/')
return HttpResponseRedirect(next, status=201)
return JsonResponse(serializer.errors, status=400)
your clubs field on the Account model is not blank=True so you can not create an account without at least a club. so you can not do
account = Account.objects.create(**validated_data)
and then do
AccountClub.create(account=account, club=club, rakeback_percentage=rakeback_percentage, chip_value=chip_value)
you may change your Account model code to:
clubs = models.ManyToManyField(Club, through='AccountClub', blank=True, related_name='accounts')
also checkout these links:
https://stackoverflow.com/a/6996358/6484831
https://stackoverflow.com/a/10116452/6484831
Order table
class Orders(models.Model):
restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE, blank=True, null=True)
tableid=models.IntegerField()
orderid=models.IntegerField()
total_amount = models.DecimalField(max_digits=10, decimal_places=2)
Articles table to save articles like pizza
class OrderArticle(models.Model):
order = models.ForeignKey(Orders, on_delete=models.CASCADE)
article = models.ForeignKey(Articles, on_delete=models.CASCADE)
# article_options = models.ManyToManyField(ArticlesOptions)
Article options to save extra topping or any option available
class OrderArticleOptions(models.Model):
# order = models.ForeignKey(Orders, on_delete=models.CASCADE)
article_option = models.ForeignKey(ArticlesOptions, on_delete=models.CASCADE)
order_article = models.ForeignKey(OrderArticle, on_delete=models.CASCADE)
quantity = models.IntegerField(default=1)
price = models.DecimalField(max_digits=10, decimal_places=2)
EDIT
Article Option table
class ArticlesOptions(models.Model):
articleoptionrestaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE , blank=True, null=True)
optionname = models.ForeignKey(ArticlesOptionsName, on_delete=models.CASCADE, related_name="optionnames")
min = models.IntegerField()
max = models.IntegerField()
choice_price = models.DecimalField(max_digits=10, decimal_places=2)
choice = models.CharField(max_length=255)
def __str__(self):
return str(self.optionname)
So Now issue is When I try to get all data in one serialize I am not able to get . I am using this example to get
https://www.django-rest-framework.org/api-guide/relations/
EDIT
My serilizers are
class OrderSerializer(serializers.ModelSerializer):
restaurant=RestaurantSerializer(required=False)
class Meta:
model = Orders
fields = ['restaurant','tableid', 'orderid', 'total_amount']
class ArticlesSerializer(serializers.ModelSerializer):
order = OrderSerializer(read_only=True)
article=ListArticleSerializer(read_only=True)
class Meta:
model = OrderArticle
fields = ['order', 'article']
class ArticlesOptionSerializer(serializers.ModelSerializer):
article_option = ListCategoriesSerializer( read_only=True)
order_article=ArticlesSerializer(read_only=True)
class Meta:
model = OrderArticleOptions
fields = ['article_option','order_article','quantity','price']
depth=1
My view.py is
class OrderedArticles(APIView):
def get(self, request, restid):
Options=OrderArticleOptions.objects.filter(order_article=1)
orderserlizer=ArticlesOptionSerializer(Options , many=True)
return Response(success_response({'orders': orderserlizer.data},
"Restaurant with this all data."), status=status.HTTP_200_OK)
My JSON Response is
"article_option":{ },
"order_article":{
"order":{
"restaurant":{ },
"tableid":12,
"orderid":1,
"total_amount":"0.00"
},
"article":{
"id":1,
"category":{ },
"ingredient":[ ],
"articleoptionnames":{ },
"restaurant":{ },
"articlename":"Article1",
"price":"1.90",
"pickuptax":6,
"dineintax":21,
"description":"This is a tekst field with more information about the product",
"image":"/media/Article/c1.264f3b28_sxcPiqi.png"
}
},
While I want these "article_option" to be as child of article like Article {article_option1, article_option2} but its creating new objects with every new article option.
If I understand you correctly, you want to return a representation of OrderArticle which have ArticleOption objects as its children. Which means you should instantiate an ArticlesSerializer in your view, but also modify ArticlesSerializer so that it includes all related article_options as a list (using the source attribute). Something like the following:
class ArticlesOptionSerializer(serializers.ModelSerializer):
article_option = ListCategoriesSerializer(read_only=True)
class Meta:
model = OrderArticleOptions
fields = ['article_option', 'order_article', 'quantity', 'price']
class ArticlesSerializer(serializers.ModelSerializer):
order = OrderSerializer(read_only=True)
article = ListArticleSerializer(read_only=True)
article_options = ArticlesOptionSerializer(read_only=True, source='orderarticleoptions_set', many=True)
class Meta:
model = OrderArticle
fields = ['order', 'article', 'article_options']
Then in your view, you should instantiate your ArticlesSerializer with the appropriate OrderArticle object:
class OrderedArticles(APIView):
def get(self, request, restid):
order_article = OrderArticle.objects.get(pk=1) # get pk/id from request
serializer = ArticlesSerializer(order_article)
return Response(serializer.data, status=status.HTTP_200_OK)
I've been trying to use a nested serializer with DRF but it won't display the related item in the output.
Here's my model.py :
class Categorie(models.Model):
nom = models.CharField(max_length=100)
def __unicode__(self):
return unicode(self.nom)
class Item(models.Model):
nom = models.CharField(max_length=100)
disponible_a_la_vente = models.BooleanField(default = True)
nombre = models.IntegerField()
prix = models.DecimalField(max_digits=5, decimal_places=2)
history = HistoricalRecords()
categorie = models.ForeignKey(Categorie, models.CASCADE)
class Meta:
verbose_name = "item"
verbose_name_plural = u"inventaire"
ordering = ['categorie', 'nom']
def __unicode__(self):
return u'{nom} - {nombre}'.format(nom = self.nom, nombre = self.nombre)
and my serializers.py
class ItemSerializer(serializers.ModelSerializer):
class Meta:
model = Item
fields = ('nom',)
class CategorieSerializer(serializers.ModelSerializer):
items = ItemSerializer(many=True)
class Meta:
model = Categorie
fields = ('nom', 'id', 'items')
The view i'm currently testing is very basic :
class InventaireDetail(generics.RetrieveAPIView):
queryset = Categorie.objects.all()
serializer_class = CategorieSerializer
but it gives the error:
AttributeError: Got AttributeError when attempting to get a value for
field items on serializer CategorieSerializer. The serializer
field might be named incorrectly and not match any attribute or key on
the Categorie instance. Original exception text was: 'Categorie'
object has no attribute 'items'.
I've been looking for a while now but i can't get it working even with the help of the doc.
Categorie.items does not exist. By default the reverse relation would get the name Categorie.item_set. You can fix that in two ways.
EITHER: add related_name to your foreign key.
class Item(models.Model):
categorie = models.ForeignKey(Categorie, models.CASCADE, related_name='items')
OR: another solution is to change the CategorieSerializer
class CategorieSerializer(serializers.ModelSerializer):
items = ItemSerializer(many = True, read_only=True, source='item_set')