Django: ModelForm get ManyToMany Field in clean Function - django

i have a Model called Order and it's it has manytomanyfield to ProductModel
i want to get the values of selected products in clean function to make some calculations
but i cannot find product field
this is the modelform code
class OrderForm(ModelForm):
class Meta:
model = Order
fields = "__all__"
def clean_points(self):
products = self.cleaned_data["Product"]
print(self.cleaned_data.get(
'product', None))
points = 20
self.set_customer_points(self.cleaned_data["customer"], points=points)
return points
def set_customer_points(self, customer, points=0):
customer.points = customer.points + points
customer.save()
and this is OrderModel
class Order(models.Model):
customer = models.ForeignKey(
Customer, on_delete=models.SET_NULL, null=True)
description = models.TextField(max_length=100)
price = models.DecimalField(decimal_places=2, max_digits=100, )
discount = models.DecimalField(decimal_places=2, max_digits=100)
order_state = models.ForeignKey(
'OrderState', on_delete=models.DO_NOTHING, null=True)
points = models.IntegerField(default=0)
product = models.ManyToManyField(
"product.Product", )
def __str__(self):
return self.customer.name
class Product(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(max_length=100)
price = models.DecimalField(decimal_places=2, max_digits=100)
discount = models.DecimalField(decimal_places=2, max_digits=100)
image = models.ImageField(upload_to="products",)
points = models.IntegerField(default=0)
def __str__(self):
return self.name

Have you tried this (lower case)?
If it doesn't work, print(self.cleaned_data) and see the available fields for debugging.
def clean_points(self):
products = self.cleaned_data.get("product")

Related

How to associate quantity amount in Django's many to many relationship

In Django I have 2 models. One called Box and one called Product. A Box can have many different products and with different quantities of each product. For example box1 can have 1 productA and 2 productB.
My box model
class Box(models.Model):
boxName = models.CharField(max_length=255, blank = False)
product = models.ManyToManyField(Product)
def __str__(self):
return self.boxName
My product model
class Product(models.Model):
productName = models.CharField(max_length=200)
productDescription = models.TextField(blank=True)
productPrice = models.DecimalField(max_digits=9, decimal_places=0, default=0)
class Meta:
db_table = 'products'
ordering = ['-productName']
def __str__(self):
return self.productName
How do I set up this model allowing me to select quantity of a products when creating the box object?
Define an intermediary model that contains product + quantity.
class Box(models.Model):
boxName = models.CharField(max_length=255, blank = False)
product_set = models.ManyToManyField(ProductSet)
def __str__(self):
return self.boxName
class ProductSet(models.Model):
quantity = models.PositiveIntegerField()
product = models.ForeignKey(Product, on_delete = models.PROTECT)
class Product(models.Model):
productName = models.CharField(max_length=200)
productDescription = models.TextField(blank=True)
productPrice = models.DecimalField(max_digits=9, decimal_places=0, default=0)
class Meta:
db_table = 'products'
ordering = ['-productName']
def __str__(self):
return self.productName

how to deleting extra OrderItems in Orders admin panel?

this is my order admin. when a customer reserve a product it goes to order item section in the down. but there are some extra order items that they are empty. i want to when a customer adds a product just that product be in the admin panel. how i can remove that empty order items???
model:
class Order(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE, related_name='orders')
ref_code = models.CharField(max_length=20, blank=True, null=True)
# products = models.ManyToManyField(OrderItem)
address = models.ForeignKey(Address, on_delete=models.SET_NULL, null=True, blank=True, related_name='addresses')
created_date = models.DateTimeField(auto_now_add=True)
ordered_date = models.DateTimeField(null=True, blank=True)
ordered = models.BooleanField(default=False)
def __str__(self):
return self.user.full_name
class OrderItem(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='products')
ordered = models.BooleanField(default=False)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
quantity = models.PositiveSmallIntegerField(default=1)
def __str__(self):
return f"{self.quantity} of {self.product.name}"
serializer:
class OrderItemSerializer(serializers.ModelSerializer):
product = serializers.SerializerMethodField()
final_price = serializers.SerializerMethodField()
class Meta:
model = OrderItem
fields = (
'id',
'product',
'quantity',
'final_price'
)
def get_product(self, obj):
return ProductSerializer(obj.product).data
def get_final_price(self, obj):
return obj.get_final_price()
class OrderSerializer(serializers.ModelSerializer):
order_items = serializers.SerializerMethodField()
total = serializers.SerializerMethodField()
class Meta:
model = Order
fields = (
'id',
'order_items',
'total',
)
def get_order_items(self, obj):
return OrderItemSerializer(obj.products.all(), many=True).data
def get_total(self, obj):
return obj.total_price()
You need to change the TabularInline at admin.py file not serializers. extra = 0
class OrderItemInline(admin.TabularInline):
model = OrderItem
extra = 0
#admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
inlines = [OrderItemInline]

I am getting invalid keyword argument while posting product array in customer order. What should i do?

First i was getting an error like to create an explicit create method while serializing an array of product. So i added it but stiil im getting thhis error :
TypeError: 'customerorder' is an invalid keyword argument for this function
This is my serializers.py
class ProductSerializer(serializers.ModelSerializer):
product_id = serializers.IntegerField(required=False)
class Meta:
model = Product
fields = '__all__'
class CustOrderSerializer(serializers.ModelSerializer):
price = serializers.SlugRelatedField(slug_field='price', queryset=Price.objects.all())
# product = serializers.SlugRelatedField(slug_field='product', queryset=Product.objects.all())
area = serializers.SlugRelatedField(slug_field='address', queryset=Area.objects.all())
city = serializers.SlugRelatedField(slug_field='city', queryset=City.objects.all())
product = ProductSerializer(many=True)
class Meta:
model = CustOrder
fields = '__all__'
def create(self, validated_data):
product = validated_data.pop('product')
customerorder = CustOrder.objects.create(**validated_data)
for product in product:
Product.objects.create(**product, customerorder= customerorder)
return customerorder
This is models.py
class Product(models.Model):
product_id = models.AutoField(primary_key=True)
product = ArrayField(models.CharField(max_length=200, blank=True))
def __str__(self):
return str(self.product)
class CustOrder(models.Model):
Customer_id = models.AutoField(primary_key=True)
CustomerName = models.CharField(max_length=200)
email = models.EmailField(max_length=70,blank=True, null= True, unique= True)
gender = models.CharField(max_length=6, choices=GENDER_CHOICES)
phone = PhoneField(null=False, blank=True, unique=True)
landmark = models.PointField()
#landmark = models.TextField(max_length=400, help_text="Enter the landmark", default='Enter landmark')
houseno = models.IntegerField(default=0)
#product_name = models.CharField(max_length=200, choices=PRODUCT_CHOICES,default='Boneless chicken')
# product_id = models.ForeignKey(Product, on_delete=models.CASCADE,related_name='custorder_productid')
product = models.ManyToManyField(Product, blank=True,related_name='pricetag')
quantity = models.IntegerField(default=0)
# price_id = models.ForeignKey(Price)
price = models.ForeignKey(Price, on_delete=models.SET_NULL, null=True,related_name='pricetag')
#price = models.DecimalField(max_digits=50, decimal_places=5, default=48.9)
pay_method = models.CharField(max_length=200,choices=PAYMENT_CHOICES, default='RAZOR PAY')
city = models.ForeignKey(City, on_delete=models.SET_NULL, null=True)
area = models.ForeignKey(Area, on_delete=models.SET_NULL, null=True)
# Price.objects.aggregate(Sum('price'))
def __str__(self):
return self.CustomerName
There are several errors here.
Firstly for some reason you've set the related name from Product back to CustOrder as pricetag. That name does not appear to relate to either side of the relationship, so not sure why you've used it.
However even with that change, it still won't work, because you can't set many-to-many relationships at create time. You would need to create the product and then add it to the order.
But that still makes no sense, because you don't actually want to be creating products at all here; you want to add existing products to the order. So just do that:
customerorder = CustOrder.objects.create(**validated_data)
customerorder.product.add(*product)
Your Product model has not field customerorder. That is the reason why Django raises the error.

Django REST: How to filter related set?

I'm trying to create a Serializer which contains cities and for every city list of trips which belongs to the current user. The problem is that I'm getting all trips, not just users ones.
My expectation for example if user was two times in London and once in Prague:
[{<serialized London>,'trips':[<serialized the two London trips>]},
{<serialized Prague>, 'trips':[<serialized one trip to Prague]}]
Now I'm getting all trips connected with the city.
Models:
class City(models.Model):
place_id = models.CharField(max_length=1000, unique=True, null=True, blank=True)
lat = models.DecimalField(max_digits=6, decimal_places=3, db_index=True, null=True, blank=True)
lng = models.DecimalField(max_digits=6, decimal_places=3, db_index=True, null=True, blank=True)
class Trip(models.Model):
user = models.ForeignKey('auth.User', related_name='trips')
city = models.ForeignKey('locations.City', related_name='trips')
date_from = models.DateField(default=now)
date_to = models.DateField(default=now)
detail = models.TextField(null=True, blank=True)
View:
def ajax_get_my_trips(request):
trips = Trip.objects.filter(user=request.user)
cities = City.objects.filter(trips__in=trips)
response = MyCityTripsSerializer(cities,many=True).data
return JsonResponse(response, safe=False)
Serializers:
class MyTripsSerializer(serializers.ModelSerializer):
class Meta:
model = Trip
fields = ('date_from', 'date_to', 'detail')
def get_queryset(self):
user = self.request.user
return Trip.objects.filter(user=user)
class MyCityTripsSerializer(serializers.ModelSerializer):
trips = MyTripsSerializer(many=True)
class Meta:
model = City
fields = ('place_id', 'lat', 'lng', 'number_of_users_here_now', 'formatted_address', 'trips')
Do you know how to make it work?
class MyTripsSerializer(serializers.ModelSerializer):
user = serializers.PrimaryKeyRelatedField(queryset=UserModel.objects.all())
city = serializers.PrimaryKeyRelatedField(queryset=City.objects.all())
class Meta:
model = Trip
fields = ('date_from', 'date_to', 'detail')
def get_queryset(self):
user = self.request.user
return Trip.objects.filter(user=user)
class MyCityTripsSerializer(serializers.ModelSerializer):
trips = MyTripsSerializer(many=True)
class Meta:
model = City
fields = ('place_id', 'lat', 'lng', 'number_of_users_here_now', 'formatted_address', 'trips')
class Trip(models.Model):
user = models.ForeignKey('auth.User', related_name='user_trips')
city = models.ForeignKey('locations.City', related_name='trips')
date_from = models.DateField(default=now)
date_to = models.DateField(default=now)
detail = models.TextField(null=True, blank=True)
Related name must be unique for every ForeignKey.

django model ManyToManyField field join

--models.py--
class Products(models.Model):
name= models.CharField(max_length=120, unique=True)
slug = models.SlugField(unique=True)
price = models.IntegerField(default=100)
image1 = models.ImageField(upload_to='static/images/home', blank=True, null=True)
class Cart(models.Model):
user = models.ForeignKey(User, null=True, blank=True)
product = models.ManyToManyField(Products, blank=True)
--views.py--
#login_required
def cart(request):
try:
cart_user = Cart.objects.filter(user = request.user)
except:
cart_user = False
if cart_user != False:
j = Products.objects.filter(pk=Cart.objects.filter(user=request.user)) #Not getting results in j
now i want the list of products which is selected by user form Cart Model when he or she is logged in.
how to apply join in two models so that i get all the product list in 'p' variable which is in Cart.product model. Thanks
Shang Wang was right about model naming. Let's use those.
class Product(models.Model):
name= models.CharField(max_length=120, unique=True)
slug = models.SlugField(unique = True)
price = models.IntegerField(default=100)
image1 = models.ImageField(upload_to='static/images/home',blank=True,null=True)
class Cart(models.Model):
user = models.ForeignKey(User,null=True, blank=True)
products = models.ManyToManyField(Product, blank=True)
Now you can use filters like this.
products = Product.objects.filter(cart__user__id=1)
carts = Cart.objects.filter(articles__name__startswith="Something").distinct()