Hello in my order model i have these fields :
class Order(models.Model):
product = models.ForeignKey(
Product, on_delete=models.CASCADE, related_name="product")
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
quantity = models.IntegerField(default=1)
fname = models.CharField(max_length=100, null=True)
address = models.CharField(max_length=1000, null=True)
phone = models.CharField(max_length=12, null=True)
price = models.IntegerField()
date = models.DateField(datetime.datetime.today, null=True)
status = models.ForeignKey(
Status, on_delete=models.CASCADE, blank=True, null=True)
payment_method = models.ForeignKey(
PaymentMethod, on_delete=models.CASCADE, blank=True, null=True)
total = models.IntegerField(null=True, blank=True)
From here i have total field where i want to create a result depend on quantity and price.For an example price * quantity = total
After that i want to fetch only the total
I am new in django really confused about this Please help
You suppose to correct your total field indentation. I do not know whether it is mistake or you are trying to do that way.
what you suppose to do is.
class Order:
total = models.IntegerField(blank=True, null=True)
For that you can overload Save method of the model. This is the way you can do is:
def save(self, *args, **kwargs):
self.total = self.quantity * self.price
return super().save(self,*args, **kwargs)
class Order(models.Model):
quantity = models.IntegerField(default=1)
price = models.IntegerField()
#property
def get_total(self):
total = self.price * self.quantity
return total
Related
I'm a beginner in Django.
I was trying to add a method inside the OrderItem class. But the visual studio code is showing an indentation error.
I'm not sure what is wrong here.
Anyone can help me, please?
Here is the code:
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Customer(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True)
name = models.CharField(max_length=200, null=True)
email = models.CharField(max_length=200, null=True)
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=200, null=True)
price = models.FloatField()
digital = models.BooleanField(default=False, null=True, blank=True)
#image needs to be added
image = models.ImageField(null=True, blank=True)
def __str__(self):
return self.name
#property
def imageURL(self):
try:
url = self.image.url
except:
url = ""
return URL
class Order(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.SET_NULL, null=True, blank=True)
date_ordered = models.DateTimeField(auto_now_add=True)
complete = models.BooleanField(default=False, null=True, blank=True)
transaction_id = models.CharField(max_length=200, null=True)
def __str__(self):
return str(self.id)
class OrderItem(models.Model):
product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True)
order = models.ForeignKey(Order, on_delete=models.SET_NULL, null=True)
quantity = models.IntegerField(default=1, null=True, blank=True)
date_added = models.DateTimeField(auto_now_add=True)
#property
def get_total(self):
return self.product.price * self.quantity
The indentation error is showing on the #property and get_total()
class OrderItem(models.Model):
product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True)
order = models.ForeignKey(Order, on_delete=models.SET_NULL, null=True)
quantity = models.IntegerField(default=0, null=True, blank=True)
date_added = models.DateTimeField(auto_now_add=True)
#property
def get_total(self):
total = self.product.price * self.quantity
return total
Pelase see the attached screenshot.
The #property decorator should be indented at the same level of the method and fields, so:
class OrderItem(models.Model):
product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True)
order = models.ForeignKey(Order, on_delete=models.SET_NULL, null=True)
quantity = models.IntegerField(default=1, blank=True)
date_added = models.DateTimeField(auto_now_add=True)
#property
def get_total(self):
return self.product.price * self.quantity
Likely you want the quantity to be by default 1. It is also not clear to me why that is a nullable field.
As a general rule-of-thumb please do not mix spaces and tabs. It might be better to always use spaces.
I am trying to filter my many to many variation fields with respect to the product. means, I only want the variations related to the current product to show in the admin page. now its showing all the variations available for every product.
I added formfield_for_manytomany() function to my admin.py but how can I get the current product(id) in the cart or order to filter the variations?
most of the questions in stack overflow Is based on the current user, which is easy to get? but how should I get the specific product(id) that is opened in the admin panel.
admin.py
from django.contrib import admin
from .models import *
from products.models import Variation
class CartAdmin(admin.ModelAdmin):
list_display = ('cart_id', 'date_created')
class CartItemAdmin(admin.ModelAdmin):
list_display = ('user','cart', 'product', 'quantity','is_active')
def formfield_for_manytomany(self, db_field, request, **kwargs):
if db_field.name == "variation":
product = Products.objects.get(id='??') # how I get the current product in the cart or order
kwargs["queryset"] = Variation.objects.filter(product=product.id)
return super().formfield_for_manytomany(db_field, request, **kwargs)
admin.site.register(Cart, CartAdmin)
admin.site.register(CartItem, CartItemAdmin)
CartItem Model
class CartItem(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, null=True)
cart = models.ForeignKey(Cart, on_delete=models.CASCADE, null=True)
product = models.ForeignKey(Products, on_delete=models.CASCADE)
variation = models.ManyToManyField(Variation, blank=True)
quantity = models.IntegerField()
is_active = models.BooleanField(default=True)
created_date = models.DateTimeField(auto_now_add=True)
def item_total(self):
return self.product.price * self.quantity
def __str__(self):
return self.product.name
Product and Variation Model
class Products(models.Model):
name = models.CharField(max_length=50, unique=True)
slug = AutoSlugField(populate_from='name', max_length=100, unique=True)
isbn = models.CharField(max_length=20, unique=True, blank=True, null=True)
sub_category = models.ForeignKey(SubCategory, on_delete=models.CASCADE)
language = models.ForeignKey(Language, on_delete=models.SET_NULL, null=True)
author = models.CharField(max_length=100)
Publisher = models.CharField(max_length=100, blank=True, default=None)
release_date = models.DateField(blank=True, null=True, default=None)
price = models.IntegerField(default=None)
stock = models.IntegerField(default=None)
is_available = models.BooleanField(default=True)
cover_image = models.ImageField(upload_to='images/products')
image1 = models.ImageField(upload_to='images/products', blank=True, default=None, null=True)
image2 = models.ImageField(upload_to='images/products', blank=True, default=None, null=True)
image3 = models.ImageField(upload_to='images/products', blank=True, default=None, null=True)
description = models.TextField(max_length=2000, blank=True, default=None)
create_date = models.DateTimeField(auto_now_add=True)
modified_date = models.DateTimeField(auto_now=True)
number_of_pages = models.IntegerField(blank=True, null=True)
weight = models.IntegerField(blank=True, null=True)
width = models.IntegerField(blank=True, null=True)
height = models.IntegerField(blank=True, null=True)
spine_width = models.IntegerField(blank=True, null=True)
class Meta:
verbose_name = 'Product'
verbose_name_plural = 'Products'
def get_url(self):
return reverse('product-view', args=[self.slug])
def __str__(self):
return self.name
class Variation(models.Model):
product = models.ForeignKey(Products, on_delete=models.CASCADE)
variation_category = models.CharField(max_length=100, choices=variation_category_choice)
variation_value = models.CharField(max_length=100, choices=variation_value_choice)
is_available = models.BooleanField(default=True)
date_added = models.DateTimeField(auto_now_add=True)
objects = VariationManager()
def __str__(self):
return self.variation_value
I have a method that creates orders from the user's cart. For the courier to take an order from different restaurants, the order is divided into several. But at the moment I'm splitting the order just by the dish in the cart. How to make an order split by restaurants? that is, if a user orders 5 dishes from two different restaurants, then 2 orders were formed.
views.py
#action(methods=['PUT'], detail=False, url_path='current_customer_cart/add_to_order')
def add_cart_to_order(self, *args, **kwargs):
cart = Cart.objects.get(owner=self.request.user.customer)
cart_meals = CartMeal.objects.filter(cart=cart)
data = self.request.data
for cart_meal in cart_meals:
order = Order.objects.create(customer=self.request.user.customer,
cart_meal=cart_meal,
first_name=data['first_name'],
last_name=data['last_name'],
phone=data['phone'],
address=data.get('address', self.request.user.customer.home_address),
restaurant_address=cart_meal.meal.restaurant.address,
)
order.save()
return response.Response({"detail": "Order is created", "added": True})
models.py
class Order(models.Model):
"""User's order"""
customer = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name='related_orders')
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
phone = models.CharField(max_length=20)
cart_meal = models.ForeignKey(CartMeal, on_delete=models.CASCADE, null=True, blank=True)
restaurant_address = models.CharField(max_length=1024, null=True)
address = models.CharField(max_length=1024)
status = models.CharField(max_length=100, choices=STATUS_CHOICES, default=STATUS_NEW)
created_at = models.DateTimeField(auto_now=True)
delivered_at = models.DateTimeField(null=True, blank=True)
courier = models.OneToOneField('Courier', on_delete=models.SET_NULL, null=True, blank=True)
class CartMeal(models.Model):
"""Cart Meal"""
user = models.ForeignKey('Customer', on_delete=models.CASCADE)
cart = models.ForeignKey('Cart', verbose_name='Cart', on_delete=models.CASCADE, related_name='related_meals')
meal = models.ForeignKey(Meal, verbose_name='Meal', on_delete=models.CASCADE)
qty = models.IntegerField(default=1)
final_price = models.DecimalField(max_digits=9, decimal_places=2)
class Meal(models.Model):
"""Meal"""
title = models.CharField(max_length=255)
description = models.TextField(default='The description will be later')
price = models.DecimalField(max_digits=9, decimal_places=2)
discount = models.IntegerField(default=0)
restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE, null=True)
slug = models.SlugField(unique=True)
class Restaurant(models.Model):
"""Restaurant"""
name = models.CharField(max_length=255)
slug = models.SlugField(unique=True)
address = models.CharField(max_length=1024)
owner = models.ForeignKey('Restaurateur', on_delete=models.CASCADE, null=True)
meals = models.ManyToManyField('Meal', related_name='related_restaurant', blank=True)
How can I do this, please help me
You can group your meals with respect to resturants.
import itertools
from core.models import CartMeal, Order
for restaurant, cart_meals in itertools.groupby(CartMeal.objects.order_by('meal__restaurant'), lambda s: s.meal.restaurant):
order = Order.objects.create(
customer=self.request.user.customer,
first_name=data['first_name'],
last_name=data['last_name'],
phone=data['phone'],
address=data.get('address', self.request.user.customer.home_address),
restaurant_address=cart_meal.meal.restaurant.address,
)
order.cart_meal.set([cart_meal for cart_meal in cart_meals])
Ref: The answer is formulated by taking help from following answer.
https://stackoverflow.com/a/57897654/14005534
I have 3 differents tables : Price, Recipe and Item
class Item(models.Model):
def __str__(self):
return self.name
name = models.CharField(max_length=200, unique=True)
image = models.URLField()
class Recette(models.Model):
item = models.OneToOneField(Item, on_delete=models.CASCADE)
qte_ressource_1 = models.IntegerField(null=True)
ressource_1 = models.ForeignKey(Item, on_delete=models.SET_NULL, blank=True, null=True, related_name='ressource_1')
qte_ressource_2 = models.IntegerField(null=True)
ressource_2 = models.ForeignKey(Item, on_delete=models.SET_NULL, blank=True, null=True, related_name='ressource_2')
qte_ressource_3 = models.IntegerField(null=True)
ressource_3 = models.ForeignKey(Item, on_delete=models.SET_NULL, blank=True, null=True, related_name='ressource_3')
qte_ressource_4 = models.IntegerField(null=True)
ressource_4 = models.ForeignKey(Item, on_delete=models.SET_NULL, blank=True, null=True, related_name='ressource_4')
qte_ressource_5 = models.IntegerField(null=True)
ressource_5 = models.ForeignKey(Item, on_delete=models.SET_NULL, blank=True, null=True, related_name='ressource_5')
qte_ressource_6 = models.IntegerField(null=True)
ressource_6 = models.ForeignKey(Item, on_delete=models.SET_NULL, blank=True, null=True, related_name='ressource_6')
qte_ressource_7 = models.IntegerField(null=True)
ressource_7 = models.ForeignKey(Item, on_delete=models.SET_NULL, blank=True, null=True, related_name='ressource_7')
qte_ressource_8 = models.IntegerField(null=True)
ressource_8 = models.ForeignKey(Item, on_delete=models.SET_NULL, blank=True, null=True, related_name='ressource_8')
class Prix_x1(models.Model):
def __str__(self):
return self.item.name
prix = models.IntegerField(null=True)
saved_at = models.DateTimeField()
item = models.ForeignKey(Item, on_delete=models.CASCADE)
Each Item can have a Recipe and a recipe is composed of 1 to 8 items with a quantity associated to each ingredient.
And all of the items have a price.
Here is what i want :
For all item that have a recipe, i want to calcul the total price of this recipe, that mean to get the price of all the ingredients. The problem is that i defined my recipe model to have a maximum of of 8 ingredients but a recipe can have only 2 for exemple, so the rest of the ingredient is set to None.
I tried something like that :
items = Item.objects.all().select_related('recette').exclude(recette__isnull=True).annotate(
prix1=Subquery(
Prix_x1.objects.filter(
item=OuterRef('pk')
).values('prix').order_by('-saved_at')[:1]
)
)
for item in items:
prix_craft, is_recette_ok = item.recette.get_recette_price()
prix = item.prix1
if is_recette_ok and prix:
gain = prix - prix_craft
prices.append({'name': item.name,
'key': item.pk,
'prix_hdv': prix,
'prix_craft': prix_craft,
'gain': gain,
'pourcentage_gain': np.around((gain / prix_craft) * 100)})
and i created a get_recette_price() like that :
def get_fields(self):
values = []
for field in Recette._meta.fields:
if field.value_to_string(self) != 'None':
if field.name not in ('item', 'id'):
values.append(int(field.value_to_string(self)))
return values
def get_recette_price(self):
fields = self.get_fields()
quantites = fields[::2]
ressources = Item.objects.filter(id__in=fields[1::2]).annotate(
prix1=Subquery(
Prix_x1.objects.filter(item=OuterRef('pk')).values('prix').order_by('-saved_at')[:1]
)
).values_list('prix1', flat=True)
is_recette_ok = True
total = 0
for quantite, ressource in zip(quantites, ressources):
if quantite and ressource:
total += quantite * ressource
else:
is_recette_ok = False
break
return total, is_recette_ok
But the code is really long to execute.
I don't know how to optimise it and deal with the None value if the recipe doesnt have 8 ingredients.
Thanks for your help !
I want to calculate the sum of total_amount property. Here is my models.py
class Orders(models.Model):
order_id = models.AutoField(primary_key=True)
order_item = models.ForeignKey('Product', models.DO_NOTHING, db_column='order_item', blank=True, null=True,
related_name='ordered_item')
order_status = models.CharField(max_length=100, blank=True, null=True)
delivery_address = models.TextField(blank=True, null=True)
customer = models.ForeignKey('User', models.DO_NOTHING, db_column='customer', blank=True, null=True)
quantity = models.IntegerField()
date_time = models.DateTimeField()
#property
def total_amount(self):
rate = Product.objects.get(pk=self.order_item.product_id)
total_amount = rate.price * self.quantity
return total_amount
#property
def unit_rate(self):
rate = Product.objects.get(pk=self.order_item.product_id)
return rate.price
You do not need a property method for that. Instead use annotate like this:
from django.db.models import Sum, F, ExpressionWrapper, DecimalField
Orders.objects.filter(date_time__month=6).annotate(
total_amount = ExpressionWrapper(
F('order_item__price')*F('quantity'),
output_field=DecimalField()
)
).aggregate(monthly_total=Sum('total_amount'))['monthly_total']