Queryset foreign key models - python

I have two models below which one of the models inherits a foreign key from the model
class Services(models.Model):
name = models.CharField(max_length=200, null=True)
price = models.FloatField(null=True)
class Order(models.Model):
customer = models.ForeignKey(Customer, null=True, on_delete = models.SET_NULL)
service = models.ForeignKey(Service, null=True, on_delete = models.SET_NULL)
I want to get the value of the total value of orders per service (per instance)
So for example
if the id = 1 of service has made orders of £10, £33, etc. I would like to get the total value of that of that service based on how many orders it has been made.
So far I have made an queryset below
Order.objects.all().values_list('service__price')
Which provides me the list of prices, but I would like the total per instance of service.
How would one achieve this?

Your Question is wrong due to the wrong model design.
If you want to have a service but with different prices you need to put price on you order table.
Change your models to :
class Service(models.Model):
name = models.CharField(max_length=200, null=True)
class Order(models.Model):
customer = models.ForeignKey(Customer, null=True, on_delete = models.SET_NULL)
service = models.ForeignKey(Service, null=True, on_delete = models.SET_NULL, related_name='orders')
price = models.FloatField(null=True)
Then you can query your sum of prices for one service:
from django.db.models import Sum
s = Service.objects.get(id=1)
s.orders.all().aggregate(Sum("price"))

Related

select special items from foregin key in django

I have two models
class Product(models.Model):
name = models.CharField(max_length=50)
averageRating = models.IntegerField(null=True, blank=True)
ratingCount = models.IntegerField(null=True, blank=True)
cover = models.ImageField(upload_to='images/', default=None, blank=True, null=True)
...
and
class VariantProduct(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
mainPrice = models.IntegerField()
discountPrice = models.IntegerField(null=True, blank=True)
this means different variant of products have different prices.
I need the variant of each product that have minimum mainPrice
in SQL i think this code works for my purpose
SELECT *, min(discountPrice) as minPrice
FROM variant GROUP BY product
but I don't know how can I get this result in Django
You can use an annotation to attach the minimum price of VariantProducts attached to Product objects:
from django.db.models import Min
Product.objects.annotate(minimum_main_price=Min('variantproduct__mainPrice'))

handling many to many relation in django models

I am working on a project named "Super Market Inventory Management System". There are some models requiring many-to-many relation among them.
I tried to add ManyToManyField(to=model, on_delete=models.CASCADE). However, it works but I need to add some extra fields to the bridge table between the two tables.
How can I do It?
Given below is my models.py
class Purchase(models.Model):
pay_status = models.CharField(max_length=50, choices=PAYSTATUS_CHOICES, default="Pending")
date_of_purchase = models.DateTimeField(auto_now_add=True)
last_payment = models.DateTimeField(auto_now=True)
class Product(models.Model):
name = models.CharField(max_length=200)
barcode = models.IntegerField(blank=True, null=True)
description = models.TextField(blank=True, null=True)
# image =
weight = models.TextField(blank=True, null=True)
status = models.BooleanField(default=True)
price = models.FloatField()
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class PurchaseProduct(models.Model):
purchase_id = models.ForeignKey(to=Purchase, on_delete=models.CASCADE)
product_id = models.ForeignKey(to=Product, on_delete=models.CASCADE)
unit_price = models.FloatField()
quantity = models.IntegerField()
price = models.FloatField()
In the bridge table I also want to add the unit price and the quantity how can I do?
OR
Is there any alternate way of doing???
However if I do not add unit price and quantity I don't need to create this bridge table all the endings will be done by Django itself but I must require the above mentioned fields in my model

Django sales campaign model with list of foreign keys that can only appear in one sales campaign?

I want to create a sales campaign which stores a list of books (Items). But the book should only be applied to one sales campaign — ie. it should not be able to appear in two campaigns.
I have the following model:
class Campaign(models.Model):
campaign_name = models.CharField(max_length=50, null=False, blank=False, default='Special Offer')
included_items = models.ManyToManyField(Item, blank=True)
active = models.BooleanField(default=True)
fixed_price = models.DecimalField(max_digits=6, blank=True, null=True, decimal_places=2)
But I think the included_items field might be of the wrong field type. From reading other questions and the Django manual, I think I may be approaching this back to front. Perhaps I should be tackling this from the Item model instead? (Shown below for reference)
class Item(models.Model):
sku = models.CharField(
max_length=10, null=True, blank=True,
default=create_new_sku)
title = models.CharField(max_length=254)
genre = models.ManyToManyField('Genre', blank=True)
author = models.ManyToManyField('Author', blank=True)
description = models.TextField()
age_range = models.ManyToManyField(
'Age_range')
image_url = models.URLField(max_length=1024, null=True, blank=True)
image = models.ImageField(null=True, blank=True)
price = models.DecimalField(max_digits=6, decimal_places=2, default=0.00)
discount = models.DecimalField(max_digits=2, decimal_places=0, default=0)
set_sale_price = models.DecimalField(max_digits=6, decimal_places=2, default=0.00)
original_sale_price = models.DecimalField(max_digits=6, decimal_places=2, null=True, blank=True)
final_price = models.DecimalField(max_digits=6, decimal_places=2, null=True, blank=False, editable=False)
If each item can only belong to one campaign you should be using a ForeignKey to campaign in the Item model to create your many-to-one relationship
Actually your design is fine.
Using a ForeignKey from #Henty's answer on the Item model still runs into issues where if a campaign becomes inactive (active=False), the Item model needs to nullify the ForeignKey to allow other campaigns to offer it. In addition, an Item model's data should only have information about that instance. To me I think it's weird having a foreign key to a campaign in an Item model since that data is irrelevant to a book. You probably want to read up on data normalization.
That being said, you should manually specify your many-to-many intermediary table as you'll need to apply a unique constraint in it so that only one active campaign can offer the book.
This intermediary table will also have fields such as the discount or sale_price of the book since different campaigns can offer different discounts/prices. I'm assuming price in your Item model is the base retail price on your book so discount, set_sale_price, original_sale_price, and final_price are not needed - again, refer back to data normalization.
In addition, you will need to copy over the active field from your Campaign instance to your intermediary table because it will be needed for the unique constraint. This is done by overriding the save method on your intermediary table to copy over the active value from the Campaign instance.
You'll also have to override the save method on your Campaign model to update the active field on your intermediary instances when you activate/deactivate a campaign.
class Campaign(models.Model):
campaign_name = ...
included_items = models.ManyToManyField(
Item,
through='CampaignItem',
through_fields=('campaign', 'item')
)
active = ...
fixed_price = ...
def save(self, *args, **kwargs):
# pre-save, update associated campaign-item instances
CampaignItem.objects.filter(campaign=self).update(active=self.active)
super().save(*args, **kwargs)
class CampaignItem(models.Model):
campaign = models.ForeignKey(Campaign, on_delete=models.CASCADE)
item = models.ForeignKey(Item, on_delete=models.CASCADE)
active = models.BooleanField(editable=False)
discount = ...
sale_price = ...
# add any other relevant fields related to this campaign item
class Meta:
# add constraint where item can only be in one active campaign
constraints = [
UniqueConstraint(fields=['item'],
condition=Q(active=True),
name='unique_active_item')
]
def save(self, *args, **kwargs):
# copy over the `active` value from campaign
self.active = self.campaign.active
super().save(*args, **kwargs)

Django: access model instances

I have a model called OrderItem
class OrderItem(models.Model):
customer = models.ForeignKey(
User, on_delete=models.SET_NULL, blank=True, null=True)
product = models.ForeignKey(
Product, on_delete=models.SET_NULL, blank=True, null=True)
order = models.ForeignKey(
Order, on_delete=models.SET_NULL, blank=True, null=True)
quantity = models.IntegerField(default=0, null=True, blank=True)
date_added = models.DateTimeField(auto_now_add=True)
and a model called Order
class Order(models.Model):
customer = models.ForeignKey(
User, on_delete=models.SET_NULL, blank=True, null=True)
date_ordered = models.DateTimeField(auto_now_add=True)
complete = models.BooleanField(default=False, null=True, blank=False)
transaction_id = models.CharField(max_length=200, null=True)
Now in my views.py I have an OrderItem model order instance. And in my Order model I need to set its order instance to complete. I'm trying something as follows:
orderID = OrderItem.objects.filter(order_id=4)
#lets say there are more than one order_id with the value of 4
for order in orderID:
order = Order.objects.get(id=orderID)
order.complete=True
order.save()
this code gives me:
ValueError: The QuerySet value for an exact lookup must be limited to one result using slicing.
How to fix this?
orderID in your example can be list, possibly of size greater than one.
This makes the following to fail:
orderID=OrderItem.objects.filter(order_id=4)
#lets say there are more than one order_id with the value of 4
for order in orderID:
order = Order.objects.get(id=orderID) # FAIL: list passed as ID
order.complete=True
order.save()
You should pass order as an argument to .get() function or use related model, like
order_items=OrderItem.objects.filter(order_id=4)
for order_item in order_items:
order = order_item.order
order.complete=True
order.save()
orderID = OrderItem.objects.filter(order_id=4)
Here you are selecting all OrderItem instances related to an Order with id=4.
Then you are cycling on all OrderItem objects and you are trying to set a flag complete=True on the order associated to each OrderItem.
But the query is constructed such as all OrderItem instances will be related to the same Order. So the following will suffice and it's a single query on the DB:
Order.objects.filter(id=4).update(complete=True)

Django Models, on delete set pk

This is my models:
class Customer(models.Model):
nome = models.CharField(max_length=40)
indirizzo = models.CharField(max_length=40)
class Appo(models.Model):
appo = models.CharField(max_length=40)
customer = models.ForeignKey(Customer, on_delete=models.SET_NULL, null=True, blank=True, default=1,related_name='appocli')
now, if I delete a Customer I need SQL set in Appo models a specific PK for customer Foreign Key. For example 1.
Something like: on delete set 1
Please help
You can use SET_DEFAULT to set your foreign key to a default value
customer = models.ForeignKey(Customer, on_delete=models.SET_DEFAULT, default=1)

Categories