Validation fail - field is required. ManyToMany serialization Django - django

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

Related

How to retrieve data from model that current user created and list it for another model's field in django

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
\

Unable to get data of Foreign key tables in same serializer

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)

Limit Choices of Foreign Keys in DRF

I have model Commodity:
class Commodity(models.Model):
shop = models.ForeignKey(Shop, related_name='commodity', on_delete=models.CASCADE)
brand = models.ForeignKey(Brand, blank=True, null=True, on_delete=models.CASCADE)
price_old = models.DecimalField(max_digits=10, decimal_places=2)
price_new = models.DecimalField(max_digits=10, decimal_places=2)
I tried to use limit_choices_to and it didn't work.
I have a Serializer:
class CommoditySerializer(serializers.ModelSerializer):
image = CommodityImageSerializer(many=False)
def get_queryset(self):
user = self.context['request'].user
queryset = Commodity.objects.filter(shop__company__user=user)
return queryset
class Meta:
model = Commodity
fields = ('id', 'shop', 'brand', 'price_old', 'price_new')
This get_queryset also dont help me.
Finally I have a regular CreateAPIView, and this method also dont help me.
How can I limit usage of foreign keys? I need to let create commodities to my user only within user's Shops. THanks!
I suppose you can simply implement validate_shop method for this:
class CommoditySerializer(serializers.ModelSerializer):
image = CommodityImageSerializer(many=False)
def validate_shop(self, value):
user = self.context['request'].user
if value.company.user == user:
return value
raise serializers.ValidationError('Invalid shop!')
class Meta:
model = Commodity
fields = ('id', 'shop', 'brand', 'price_old', 'price_new')

Django Rest Framework how to save a manyToMany with Related Field

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:

Saving OnetoOne field manually in django

I have following models:
class Person(User):
first_name = models.CharField(verbose_name=_('first name'), max_length=30)
last_name = models.CharField(verbose_name=_('last name'), max_length=30)
class Service(models.Model):
person = models.ForeignKey(Person, related_name='services')
price_from = models.DecimalField(_('price form'), max_digits=10, decimal_places=2, validators=[MinValueValidator(Decimal('0.01'))])
price_to = models.DecimalField(_('price to'), max_digits=10, decimal_places=2, validators=[MinValueValidator(Decimal('0.01'))])
class WorkPlace(models.Model):
service = models.OneToOneField('Service', related_name='work_place', primary_key=True)
city = CharField(verbose_name=_('city'), max_length=255)
street = CharField(verbose_name=_('street'), max_length=255)
I also registered Person in admin and made Service an inline admin.
Due to design, city and address are entered as multivalue field.
The problem is that I can't save WorkPlace manually.
Here are the forms:
class WorkPlaceForm(forms.ModelForm):
class Meta:
model = WorkPlace
fields = '__all__'
class PersonForm(forms.ModelForm):
class Meta:
model = Person
fields = '__all__'
class ServiceForm(forms.ModelForm):
class Meta:
fields = '__all__'
model = Service
multi_work_place = MyMultiValueField()
def save(self, commit=True):
service = super(ServiceForm, self).save(commit=commit)
if self.cleaned_data['multi_work_place']:
work_place = WorkPlace(**{
'city': self.cleaned_data['multi_work_place'][0],
'street': self.cleaned_data['multi_work_place'][1],
})
# when there is brand new object is created, there is no service.pk
work_place.service = service # how???
work_place.save()
return service
Moreover, if I write service = super(ServiceForm, self).save(commit=True) on new object, this will raise Error as there is no Person created.
How can I solve this problem? Recall, that I'm working in admin.
class ServiceForm(forms.ModelForm):
class Meta:
fields = '__all__'
model = Service
multi_work_place = MyMultiValueField()
def save(self, commit=True):
service = super(ServiceForm, self).save(commit=False)
service.member_id = service.member.pk # here is the key command
service.save()
if self.cleaned_data['multi_work_place']:
work_place = WorkPlace(**{
'city': self.cleaned_data['multi_work_place'][0],
'street': self.cleaned_data['multi_work_place'][1],
})
# when there is brand new object is created, there is no service.pk
work_place.service = service # how???
work_place.save()
return service
I just needed to add member pk to service model
try this:
class ServiceForm(forms.ModelForm):
class Meta:
fields = '__all__'
model = Service
multi_work_place = MyMultiValueField()
def save(self, commit=True):
service = save_instance(self, self.instance, self._meta.fields,
fail_message, commit, self._meta.exclude,
construct=False)
service.save()
if self.cleaned_data['multi_work_place']:
work_place = WorkPlace(**{
'city': self.cleaned_data['multi_work_place'][0],
'street': self.cleaned_data['multi_work_place'][1],
})
# when there is brand new object is created, there is no service.pk
work_place.service = service
work_place.save()
return service