Django queryset question - django

class Ticket(models.Model):
event = models.ForeignKey(Event)
name = models.CharField('Name', max_length=255)
price = models.FloatField('Price', blank=True)
class CartItem(models.Model):
cart = models.ForeignKey(Cart)
ticket = models.ForeignKey(Ticket)
quantity = models.IntegerField()
How do I get Ticket.price * CartItem.Quantity where event = event

You'll need to add error checking but you could do something like this logic-wise:
total = 0
cart_items = CartItem.objects.filter(ticket__event=event) # assuming there are multiple cart items per event
for cart_item in cart_items:
new_total = cart_item.ticket.price * cart_item.quantity
total = total + new_total
That should give you total revenue for an event.

Related

How can I update my Django model using signals?

How can I keep adding to the total price, when a new instance is created in the CartItem model and also deduct the price when an item is deleted ? , at the moment my current signals is only showing the price of the current product that I update or create.
signals.py
#receiver([post_save, post_delete], sender=CartItem, dispatch_uid="update_total")
def add_cart_receiver(sender, instance, *args, **kwargs):
total = 0
product_price = instance.item.price
quantity = instance.quantity
updated_total = Decimal(product_price) * int(quantity)
total += updated_total
if instance.items_cart.subtotal != total:
instance.items_cart.subtotal = total
instance.items_cart.save()
models.py
class CartItem(models.Model):
item = models.ForeignKey(Product, on_delete=models.CASCADE, blank=True, null=True)
items_cart = models.ForeignKey('Cart', blank=True, on_delete=models.CASCADE, null=True)
quantity = models.IntegerField(null=True, blank=True)
updated = models.DateTimeField(auto_now=True)
timestamp = models.DateTimeField(auto_now_add=True)
def __str__(self):
return 'item:{} cart:{} quantity:{}'.format(self.item, self.items_cart, self.quantity)
class Cart(models.Model):
user = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE)
subtotal = models.DecimalField(default=0.00, max_digits=100, decimal_places=2)
total = models.DecimalField(default=0.00, max_digits=100, decimal_places=2)
updated = models.DateTimeField(auto_now=True)
timestamp = models.DateTimeField(auto_now_add=True, null=True)
def __str__(self):
return 'id:{} user:{} subtotal:{} total:{} updated:{}'.format(self.id, self.user, self.subtotal, self.total, self.updated)
views.py
def cart_add(request):
product_id = request.POST.get('product_id')
try:
product_obj = Product.objects.get(id=product_id)
quantity = request.POST.get('quantity_field')
cart_obj, new_obj = Cart.objects.new_or_get(request)
last_qty = CartItem.objects.filter(item=product_obj, items_cart=cart_obj).reverse()[0].delete()
new_qty = CartItem(item=product_obj, items_cart=cart_obj, quantity=quantity)
new_qty.save()
return redirect("cart:home")
except ValueError:
print("Unable to increase quantity")
return redirect("cart:home")
I figured out the problem I was having, below is my solution, to keep accumulating the total price of all items in my current cart, I have done this by looping over a Queryset of 'cart_items' and calculating the price * quantity, then adding it to a counter ('total'), then saving it to my 'Cart' model field 'total'. The receiver is collecting 'post_save' and 'post_delete' signals. Hopefully this will help someone else.
signals.py
#receiver([post_save,post_delete], sender=CartItem, dispatch_uid="update_total")
def add_cart_receiver(sender, instance, **kwargs):
cart = instance.items_cart.id
cart_items = CartItem.objects.filter(items_cart=cart)
cart_total = 0
for element in cart_items:
cart_total += (Decimal(element.item.price) * int(element.quantity))
instance.items_cart.subtotal = cart_total
instance.items_cart.save()

How to calculate the points based on the price of the total purchase in django models?

I am trying to create points earned by users after buying something and placed an order from the frontend. Also, I need to save the points on the database because users later use that points to buy something.
The points system looks like this.
Point System for % of the total purchase
Upto 10,000 = 1 %
10k to 50k =2.75%
50K plus = 5%
I haven't saved the price in DB, I just used it as a property so that it remains safe and cant be changed by anyone. It calculates whenever the get or post API is called.
class Order(models.Model):
ORDER_STATUS = (
('To_Ship', 'To Ship',),
('Shipped', 'Shipped',),
('Delivered', 'Delivered',),
('Cancelled', 'Cancelled',),
)
user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True)
order_status = models.CharField(max_length=50,choices=ORDER_STATUS,default='To_Ship')
ordered_date = models.DateTimeField(auto_now_add=True)
ordered = models.BooleanField(default=False)
#property
def total_price(self):
# abc = sum([_.price for _ in self.order_items.all()])
# print(abc)
return sum([_.price for _ in self.order_items.all()])
def __str__(self):
return self.user.email
class Meta:
verbose_name_plural = "Orders"
ordering = ('-id',)
class OrderItem(models.Model):
orderItem_ID = models.CharField(max_length=12, editable=False, default=id_generator)
order = models.ForeignKey(Order,on_delete=models.CASCADE, blank=True,null=True,related_name='order_items')
item = models.ForeignKey(Product, on_delete=models.CASCADE,blank=True, null=True)
order_variants = models.ForeignKey(Variants, on_delete=models.CASCADE,blank=True,null=True)
quantity = models.IntegerField(default=1)
ORDER_STATUS = (
('To_Ship', 'To Ship',),
('Shipped', 'Shipped',),
('Delivered', 'Delivered',),
('Cancelled', 'Cancelled',),
)
order_item_status = models.CharField(max_length=50,choices=ORDER_STATUS,default='To_Ship')
#property
def price(self):
total_item_price = self.quantity * self.order_variants.price
return total_item_price
Updated Code:
class Points(models.Model):
order = models.OneToOneField(Order,on_delete=models.CASCADE,blank=True,null=True)
points_gained = models.IntegerField(default=0)
def collect_points(sender,instance,created,**kwargs):
if created:
if instance.total_price <= 10000:
abc = 0.01* (instance.total_price)
else:
abc = 0.75 * (instance.total_price)
return abc
post_save.connect(collect_points,sender=Order)
def save(self,*args,**kwargs):
self.points_gained = self.collect_points()
super(Points, self).save(*args, **kwargs)
I tried using Django signals and overwrite save function to create points. But when I check db, there are no rows in points table although order is made.
OrderCreate API
class OrderSerializer(serializers.ModelSerializer):
billing_details = BillingDetailsSerializer()
order_items = OrderItemSerializer(many=True)
user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())
#total_price = serializers.SerializerMethodField(source='get_total_price')
class Meta:
model = Order
fields = ['id','user','ordered_date','order_status', 'ordered', 'order_items', 'total_price', 'billing_details']
# depth = 1
def create(self, validated_data):
user = self.context['request'].user
if not user.is_seller:
order_items = validated_data.pop('order_items')
billing_details = validated_data.pop('billing_details')
order = Order.objects.create(user=user,**validated_data)
BillingDetails.objects.create(user=user,order=order,**billing_details)
for order_items in order_items:
OrderItem.objects.create(order=order,**order_items)
order.save()
return order
else:
raise serializers.ValidationError("This is not a customer account.Please login as customer.")
This answer is based on the comments and updated code.
I would have a relationship between the user and the points model, as the points belong to a user and not an order. Also this enables you to update the points whenever the same user orders again.
This results in the following model and post save signal:
def update_points(sender, instance, created, **kwargs):
if created:
if instance.total_price <= 10000:
points_gained = 0.01 * instance.total_price
else:
points_gained = 0.75 * instance.total_price
try:
# Check if user already has points and update if so
points = Points.objects.get(user=instance.user)
points.points_gained = points_gained
points.save(update_fields=['points_gained'])
except Points.DoesNotExist:
# User does not have points yet, create points
Points.objects.create(user=instance.user,
points_gained=points_gained)
post_save.connect(update_points, sender=Order)
class Points(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, blank=False, null=False)
points_gained = models.IntegerField(default=0)

Difference between two Foreign key model fields

I have a model named 'CarAdd', and two other models are connected with a foreign key to this CarAdd model that are ShippingDetails, MaintenanceDetails. and each foreign key model has an item and price field." foreign key have more than 2 items under one id"
I need to find the profit amount of each car
profit = sold_amount - (purchased amount + total shipping cost + total maintenance cost)
class CarAdd(models.Model):
# Car Details
name = models.CharField(max_length=60)
purchased_amount = models.DecimalField()
# there 3 choices in STATUS shipped, maintenance, sold
status = models.CharField(max_length=12, choices=STATUS)
sold_amount = models.DecimalField(max_digits=15, decimal_places=1)
profit_amount = models.DecimalField(max_digits=15, decimal_places=1)
def save(self, *args, **kwargs):
if self.status == 'sold':
sum_invested = self.purchased_amount + ShippingDetails.price + MaintenanceDetails.price
profit = self.sold_amount - sum_invested
self.profit_amount = profit
super().save(*args, **kwargs)
class ShippingDetails(models.Model):
car = models.ForeignKey(CarAdd, related_name='shipping_details', on_delete=models.CASCADE)
item = models.CharField(max_length=60)
price = models.DecimalField(max_digits=15, decimal_places=1,)
class MaintenanceDetails(models.Model):
car = models.ForeignKey(CarAdd, related_name='maintenance_details', on_delete=models.CASCADE)
item = models.CharField(max_length=60)
price = models.DecimalField(max_digits=15, decimal_places=1)
how do I calculate the profit amount if status is 'sold' and save to profit_amount field
You need to aggregate on the related models:
from django.db.models import Sum
from django.db.models.functions import Coalesce
sum_invested = self.purchased_amount
+ self.shipping_details.aggregate(total_price=Coalesce(Sum('price'), 0))['total_price']
+ self.maintenance_details.aggregate(total_price=Coalesce(Sum('price'), 0))['total_price']

How to generate oracle specific queries django

How can I get Django to produce/submit the exact query below:
SELECT "MESSAGE"."MSG_NO", "MESSAGE"."MSG_TYPE", "MESSAGE"."DIRECTION", "MESSAGE"."SESSION_NO", "MESSAGE"."SEQUENCE_NO", "MESSAGE"."REF_SESSION", "MESSAGE"."REF_SEQUENCE", "MESSAGE"."ACKTIME", "MESSAGE"."ACKNAKSTATUS", "MESSAGE"."PRIORITY", "MESSAGE"."DELIVMONITOR", "MESSAGE"."OBSOLESCENCE", "MESSAGE"."DISPOSITION", "MESSAGE"."TRAILER", "MESSAGE"."BYPASSED", "MESSAGE"."RESPONSE_QUEUE", "MESSAGE"."SOURCE_QUEUE", "MESSAGE"."QUEUE", "MESSAGE"."QUEUE_PRIORITY", "MESSAGE"."DATE_CREATED", "MESSAGE"."DATE_ROUTED", "MESSAGE"."INPUT_FILE", "MESSAGE"."OUTPUT_FILE", "MESSAGE"."STATUS1", "MESSAGE"."STATUS2", "MESSAGE"."STATUS3", "MESSAGE"."USERID", "MESSAGE"."TMSTAMP"
FROM "MESSAGE"
WHERE ("MESSAGE"."DATE_CREATED" >= (SYSDATE-3)
AND "MESSAGE"."DIRECTION" = 0
AND "MESSAGE"."STATUS1" = 0)
The below code produces a query that does not work:
Message.objects.using(queue_db_env).filter(STATUS1=0, DIRECTION=0, DATE_CREATED__gte=time_threshold)
Below is the query produced by the code above and it does not work when I run it manually:
SELECT "MESSAGE"."MSG_NO", "MESSAGE"."MSG_TYPE", "MESSAGE"."DIRECTION", "MESSAGE"."SESSION_NO", "MESSAGE"."SEQUENCE_NO", "MESSAGE"."REF_SESSION", "MESSAGE"."REF_SEQUENCE", "MESSAGE"."ACKTIME", "MESSAGE"."ACKNAKSTATUS", "MESSAGE"."PRIORITY", "MESSAGE"."DELIVMONITOR", "MESSAGE"."OBSOLESCENCE", "MESSAGE"."DISPOSITION", "MESSAGE"."TRAILER", "MESSAGE"."BYPASSED", "MESSAGE"."RESPONSE_QUEUE", "MESSAGE"."SOURCE_QUEUE", "MESSAGE"."QUEUE", "MESSAGE"."QUEUE_PRIORITY", "MESSAGE"."DATE_CREATED", "MESSAGE"."DATE_ROUTED", "MESSAGE"."INPUT_FILE", "MESSAGE"."OUTPUT_FILE", "MESSAGE"."STATUS1", "MESSAGE"."STATUS2", "MESSAGE"."STATUS3", "MESSAGE"."USERID", "MESSAGE"."TMSTAMP"
FROM "MESSAGE"
WHERE ("MESSAGE"."DATE_CREATED" >= 2018-09-15 12:47:43.784709
AND "MESSAGE"."DIRECTION" = 0
AND "MESSAGE"."STATUS1" = 0)
This is due to "MESSAGE"."DATE_CREATED" >= 2018-09-15 12:47:43.784709 , query only works when I swap out the DATE_CREATE clause with "MESSAGE"."DATE_CREATED" >= (SYSDATE-3)
My views.py has the code of:
class MessageList(APIView):
def get(self, request, queue_db_env, queue_name, queue_id, format=None):
#
# time_threshold = datetime.now() - timedelta(hours=36)
now = timezone.now()
time_threshold = now - datetime.timedelta(hours=36)
print(time_threshold.timestamp())
str_time_threshold = time_threshold.timestamp()
#
messages = Message.objects.using(queue_db_env).filter(STATUS1=0, DIRECTION=0, DATE_CREATED__gte=time_threshold)
print(messages.query)
serializer = MessageSerializer(messages, many=True)
return Response({"Queue": queue_name, "Queue_ID": queue_id, "Queue_Messages": serializer.data})
My models.py is:
from django.db import models
class Message(models.Model):
MSG_NO = models.IntegerField(primary_key=True,)
MSG_TYPE = models.IntegerField()
DIRECTION = models.IntegerField()
SESSION_NO = models.IntegerField()
SEQUENCE_NO = models.IntegerField()
REF_SESSION = models.IntegerField()
REF_SEQUENCE = models.IntegerField()
ACKTIME = models.DateTimeField(max_length = 7)
ACKNAKSTATUS = models.IntegerField()
PRIORITY = models.CharField(max_length = 1)
DELIVMONITOR = models.IntegerField()
OBSOLESCENCE = models.IntegerField()
DISPOSITION = models.IntegerField()
TRAILER = models.IntegerField()
BYPASSED = models.IntegerField()
RESPONSE_QUEUE = models.IntegerField()
SOURCE_QUEUE = models.IntegerField()
QUEUE = models.IntegerField()
QUEUE_PRIORITY = models.IntegerField()
DATE_CREATED = models.DateTimeField()
DATE_ROUTED = models.DateTimeField()
INPUT_FILE = models.IntegerField()
OUTPUT_FILE = models.IntegerField()
STATUS1 = models.IntegerField()
STATUS2 = models.IntegerField()
STATUS3 = models.IntegerField()
USERID = models.CharField(max_length = 8)
TMSTAMP = models.DateTimeField()
I want to filter on last 3 days on DATE_CREATED colument
I am using an oracle database and I am failing to filter on date.
time_threshold = now - datetime.timedelta(hours=36)
There are twenty-four hours in a day. So 36 hours = 1.5 days. If you want to filter on the last three days you need
timedelta(hours=72)

Why add() method for m2m not working for single object - django

I am trying to add object to m2m with add method but neither its showing error nor adding item, I can't understand why
Here is my view :
class UpdateCartView(generic.UpdateView):
model = Cart
fields = ['products']
template_name = 'update_cart.html'
success_url = reverse_lazy('carts:home')
def form_valid(self,form):
product = ProductCreateModel.objects.get(pk = self.request.POST.get('product'))
size = Size.objects.get(pk = self.request.POST.get('size'))
colour = Colour.objects.get(pk = self.request.POST.get('colour'))
products = Products.objects.create(product = product,
size = size,
quantity = int(self.request.POST.get('quantity')),
colour = colour)
product.save()
cart = self.get_object()
print(products)
cart.products.add(products)
cart.save()
return super(UpdateCartView,self).form_valid(form)
def get_object(self):
cart_obj, cart_created = Cart.objects.new_or_get(self.request)
return cart_obj
Here is my models :
class Products(models.Model):
product = models.ForeignKey(ProductCreateModel,on_delete=models.CASCADE,related_name='cart_product')
quantity = models.PositiveIntegerField(default=1,validators=[MinValueValidator(1)])
size = models.ForeignKey(Size,related_name='cart_product_size',on_delete=models.CASCADE,null=True,blank=False)
colour = models.ForeignKey(Colour,related_name='cart_product_colour',on_delete=models.CASCADE,null=True,blank=False)
def __str__(self):
return '{product}({quantity})'.format(product=self.product,quantity=self.quantity)
class Cart(models.Model):
MESSAGE_CHOICES = (
('A' , 'Items are added to you cart'),
('R' , 'Items are removed from cart'),
('PC' , 'Price of some items has changed'),
)
messages = models.CharField(max_length=1, choices=MESSAGE_CHOICES,null=True,blank=True)
user = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE)
products = models.ManyToManyField(Products, blank=True)
subtotal = models.DecimalField(default=0.00, max_digits=100, decimal_places=2)
total = models.DecimalField(default=0.00, max_digits=100, decimal_places=2)
updated = models.DateTimeField(auto_now=True)
timestamp = models.DateTimeField(auto_now_add=True)
objects = CartManager()
def __str__(self):
return str(self.id)
def m2m_changed_cart_receiver(sender, instance, action, *args, **kwargs):
if action == 'post_add' or action == 'post_remove' or action == 'post_clear':
products = instance.products.all()
total = 0
for x in products:
total += (x.product.final_price * x.quantity)
if instance.subtotal != total:
instance.subtotal = total
instance.save()
def pre_save_cart_receiver(sender, instance, *args, **kwargs):
if instance.subtotal > 0:
instance.total = Decimal(instance.subtotal) * Decimal(1.08) # 8% tax
else:
instance.total = 0.00
Everything is working fine, no errors, also print the products but in my admin panel its showing empty cart means cart.products.add(products) not added products why ?