I'm trying to build an Inventory Model for a Django App that handles the sale of seeds. Seeds are stored and sold in packs of 3, 5, or 10 seeds of a single variety (for example: 3 pack of mustard seeds).
I want to add x amount of products to inventory with a price for each entry, and sell that product at that price for as long as that entry has items left(quantity field > 0) even if later entries have been made for the same product and presentation but at a different price, so i have the following model:
class Product(models.Model):
name = models.CharField(max_length=100)
class Presentation(models.Model):
seed_qty = models.IntegerField()
class Stock(models.Model):
date = models.DateField(auto_now=True)
quantity = models.IntegerField()
product = models.ForeignKey(Product, on_delete=models.CASCADE)
presentation = models.ForeignKey(Presentation, on_delete=models.CASCADE)
cost = models.FloatField(null=True, blank=True)
sell_price = models.FloatField(null=True, blank=True)
I'm wondering if I should actually relate Product and Stock with a ManyToMany field through a GeneralEntry intermediate model in which I'd store date_added, presentation and cost/price.
My issue is that when I add multiple Stock entries for the same product and presentation, I can't seem to query the earliest prices for each available (quantity>0) stock entry for each product.
What I've tried so far has been:
stock = Stock.objects.filter(quantity__gt=0).order_by('-date')
stock = stock.annotate(min_date=Min('date')).filter(date=min_date)
But that returns that max_date isn't defined.
Any ideas on how to query or rearrange this model ?
Thanks!
*** UPDATE : I wasn't using F() function from django.db.models.
Doing it like this works:
stock = Stock.objects.filter(quantity__gt=0).order_by('-date')
stock = stock.annotate(min_date=Min('date')).filter(date=F('min_date'))
Turns out I wasn't using F() function from django.db.models.
Doing it like this works:
stock = Stock.objects.filter(quantity__gt=0).order_by('-date')
stock = stock.annotate(min_date=Min('date')).filter(date=F('min_date'))
Related
I'm working on a django backend and I'm trying to model a database and want to do it the best practice way.
I need a "User" table, a "Portfolios" table and a "Stocks" table. A user can have multiple portfolios which consist of multiple stocks.
This is my code so far:
class User(models.Model):
user_id = models.AutoField(primary_key=True)
username = models.CharField(max_length=25)
in_cash = models.DecimalField(max_digits=15, decimal_places=2)
class Portfolios(models.Model):
portfolio_id = models.AutoField(primary_key=True)
user_id = models.ForeignKey("User", on_delete=models.CASCADE)
stock_id = models.ForeignKey("Stocks", on_delete=models.CASCADE)
buy_datetime = models.DateTimeField(default=datetime.now, blank=True)
number_of_shares = models.IntegerField()
class Stocks(models.Model):
stock_id = models.AutoField(primary_key=True)
stock_symbol = models.CharField(max_length=12)
In my head I would have an entry in the "Portfolios" table for each stock of a portfolio.
So "Portfolios" would look like
portfolioid 1, userid: 1, stockid: 1, buydate: 12.01.2019, shares: 20
portfolioid 1, userid: 1, stockid: 2, buydate: 19.02.2020, shares: 41
So there is one portfolio, which contains two stocks. But overall that doesn't seem right. If used like in my example above I can't have the portfolioid as a primary key, how can I improve this?
Thanks for your time
What confused me is the name portfolio, which I would call position. Your initial code was correct, although I changed it a bit, removing AutoField which is probably not needed, using a OneToOneField to connect a Customer to a User, removing the s at the end of class names, which are templates, and therefore should be singular, nor plural, adding price to the Stock. And finally changing Portfolio, which should be the sum of all the Positions.
from django.conf import settings
class Customer(models.Model):
customer = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE,)
in_cash = models.DecimalField(max_digits=15, decimal_places=2)
def __str__(self):
return self.customer.username
class Position(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
stock = models.ForeignKey('Stock', on_delete=models.CASCADE)
number_of_shares = models.IntegerField()
buy_datetime = models.DateTimeField(default=datetime.now, blank=True)
def __str__(self):
return self.customer.customer.username + ": " + str(self.number_of_shares) + " shares of " + self.stock.stock_symbol
class Stock(models.Model):
stock_symbol = models.CharField(max_length=12)
price = models.DecimalField(max_digits=10, decimal_places=2)
def __str__(self):
return self.stock_symbol
In my head I would have an entry in the "Portfolios" table for each
stock of a portfolio. So "Portfolios" would look like
portfolioid 1, userid: 1, stockid: 1, buydate: 12.01.2019, shares: 20
portfolioid 1, userid: 1, stockid: 2, buydate: 19.02.2020, shares: 41
So there is one portfolio, which contains two stocks. But overall that
doesn't seem right. If used like in my example above I can't have the
portfolioid as a primary key, how can I improve this?
You are correct, except that should be applied to a Position, each of which is unique, not the Portfolio, which is all the Positions the Customer has.
As in usual many-to-many cases, you will need to create an intermediary table which is also called junction table/association table. Associative Entity
Your users are going to have several portfolios:
class UserPortfolio(models.Model):
user_id = models.ForeignKey("User")
portfolio_id = models.ForeignKey("Portfolio")
The portfolios will have multiple stocks in them:
class PortfolioStock(models.Model):
portfolio_id = models.ForeignKey("Portfolio")
stock_id = models.ForeignKey("Stock")
Now a user can have several portfolios, and those portfolios will include several stocks. In order to get access to the corresponding stocks for a user, you will need to join the tables.
I have here 2 django database table
class Inventory(models.Model):
product_name = models.CharField(max_length = 100)
qty = models.PositiveIntegerField()
class Order(models.Model):
product = models.ForeignKey(Inventory, on_delete = models.CASCADE )
qty = models.PositiveIntegerField()
I would like to have an inventory table page wherein I can see the total qty left in Inventory (for example: Inventory.qty - Order.qty) .
how to do this in Django ?
You can annotate the Inventory with the qty minus the sum of the related Orders:
from django.db.models import F, Sum
Inventory.objects.annotate(
qty_left=F('qty') - Sum('order__qty')
)
The Inventory objects that arise from this QuerySet will have an extra attribute .qty_left that contains the qty of the Inventory minus the sum of the qtys of the related Orders.
i want to remain the same data as i saved before , after changing , or deleted the model which provide the foreign key ,
i tried to
on_delete=models.SET_NULL
but still removes the instance which i've saved before
class Product(models.Model):
product_name = models.CharField(unique=True, max_length=50 ,
blank=False,null=False)
price = models.PositiveIntegerField()
active = models.BooleanField(default=True)
def __str__(self):
return self.product_name
class Order(models.Model):
id = models.AutoField(primary_key = True)
products = models.ManyToManyField(Product ,through='ProductOrder')
date_time = models.DateTimeField(default=datetime.now())
#property
def total(self):
return self.productorder_set.aggregate(
price_sum=Sum(F('quantity') * F('product__price'),
output_field=IntegerField()) )['price_sum']
class ProductOrder(models.Model):
product = models.ForeignKey(Product, on_delete=models.SET_NULL , null=True)
ordering = models.ForeignKey(Order, on_delete=models.SET_NULL,blank=True,null=True ,default='')
quantity = models.PositiveIntegerField(default=1)
def __str__(self):
return f"{self.product} : {self.quantity}"
and how save the total price in variable , if the the price in Product updated , it remains as the first time ?
and how to prevent losing data from Order model after removing a product from Product model thanks for advice
There are multiple ways to solve this, but it generally has little to do with Django itself, because these are business decisions:
Don't link to the Product in the Order (and ProductOrder) models, but save the product information directly in the ProductOrder model. You could for example use a JSONField (if you're on PostgreSQL) and keep all the product details there, including the price.
Don't change a Product once it's been ordered once. i.e. you can make it impossible to change/delete a Product (on_delete=models.PROTECT). Give a Product a unique SKU and version number, create new versions of your Product when the price changes. That way all orders will use a reference to the Product that was actually ordered. When fetching Products that can be purchased, always fetch the latest version of the Product. You could create a new ProductVersion table for this and link to that instead of the Product.
Don't allow deleting a Product (on_delete=PROTECT), but allow changing the price. Note that if other characteristics of the Product change (such as color), you should always create a new Product. Keep a copy of the paid price in the ProductOrder itself (the line item of the order). This is the most common approach. You just copy the price in the line items, so that you always have actual price paid by the customer.
The solution you choose depends a bit on the business requirements of your company, i.e. how products are managed, what needs to be kept, etc... It also depends on what you want your customers to be able to see when looking up their historical orders.
I need to do a software for a "restaurant" and it needs to be able to calculate prices for the dishes that need to be cooked taking the prices from a list of ingredients. I imagine that the Dishes model would need a field called ingredients or one field for each ingredient (?), but i dont know how it would fetch the Ingredients model for the prices for each ingredient and calculate the total based on the quantity that needs to be cooked. What would be the best method? Like to have a template that shows the price of each ingredient with its quantity and the total of all the ingredients.
Every Dish is composed of many Ingredient s and each Ingredient will be used in many Dishes so the following suggestion will be proper for your problem
class Dish(models.Model):
price = models.DecimalField(max_digits=5, decimal_places=2)
class Ingredient(models.Model):
price = models.DecimalField(max_digits=5, decimal_places=2)
class DishIngredient(models.Model):
dish = models.ForeignKey(Dish)
ingredient = models.ForeignKey(Ingredient)
quantity = models.IntegerField()
im doing some models and have a thought while designing them, here is an example: a bank buys stock shares, so one bank can have many stock shares and many stock shares can be bought from many banks, its a many to many relationship but when a bank buys a stock shares it has to keep a record of the price and the date/period/round of the purchase, works the same for a sale, o in order to keep record of all of that im doing a class something like this:
class Bank(models.Model):
name = models.Charfield()
money = models.IntegerField()
class StockShares(models.Model):
name = models.Charfield()
price = models.Charfield()
now to make a relationship i know i have to add
stock = models.ManyToManyField(StockShares)
but then how do i add the relationship attributes that only exist when a purchase or sale happens?
i was thinking maybe i can do something like this:
class Bank(models.Model):
name = models.Charfield()
money = models.IntegerField()
class StockShares(models.Model):
name = models.Charfield()
price = models.Charfield()
class Sale(models.Model):
bank = models.ForeignKey(Bank)
stockshares = models.ForeignKey(StockShares)
date = models.DateField()
quantity = models.ForeignKey()##this should be the quantity of stockshares sold in $ im just lazy to write it down
this is what i would to normaly without using django and inside a database manager
is there a way to aproach to this in django without doing an intermediate class to deal with the relationship? or im doing my thougth good and this is how things have to be done in django
pd: english is not my first language im doing my best here
thanks in advance for answering!
You are looking for an Extra fields on many-to-many relationships
Your code should look like this:
class Bank(models.Model):
name = models.Charfield()
money = models.IntegerField()
members = models.ManyToManyField(StockShares, through='Sale')
class StockShares(models.Model):
name = models.Charfield()
price = models.Charfield()
class Sale(models.Model):
bank = models.ForeignKey(Bank)
stockshares = models.ForeignKey(StockShares)
date = models.DateField()
Maybe quantity should be calculated field