representing manytomanyfield with extra attributes in django - sql

I have a situation where i need to store a table of "Product"'s and a table of "Order"'s on these products.
One order consists of many ("Product", "Quantity") tuples where quantity is a float expressed in tonnes.
I considered the followng implementation, but i don't think having a table of arbitrary products and quantities would be a very good design decision.
class Product(models.Model):
name = models.CharField("Name", max_length=50)
description = models.TextField("Description", blank=True)
class ProductOrder(models.Model):
unit = "tonnes"
product = models.ManyToManyField('Product')
quantity = models.FloatField('Quantity')
class Order(models.Model):
products = models.ManyToManyField('ProductOrder')
date = models.DateField('Date')
Am I overlooking an obvious solution? How would you implement this relationship to lead to the most DRY code. (PS. I don't want to have separate lists of products and quantities and have to rely implicitly on their ordering.)

In django, you can use through to create such intermediate table and maintain order specific attributes in there.
You can implement it as
class Product(models.Model):
name = models.CharField("Name", max_length=50)
description = models.TextField("Description", blank=True)
class Order(models.Model):
products = models.ManyToManyField('Product', through="OrderDetail")
date = models.DateField('Date')
class OrderDetail(models.Model):
unit = "tonnes"
product = models.ForeignKey('Product')
order = models.ForeignKey('Order')
quantity = models.FloatField('Quantity')
The documentation explains how to use and work with such design.

Related

Django annotate multiple aggregators over grouped values

Due to the structure of my project, I need to have multiple aggregations over three interlocked tables. With structure looking somewhat like this:
class ItemMeta(models.Model):
item = models.ForeignKey(
Item, on_delete=models.SET_NULL, null=True
)
class = models.CharField(max_length=2048, null=True, blank=True)
department = models.CharField(max_length=2048, null=True, blank=True)
class Item(models.Model):
amount = models.DecimalField(max_digits=18, decimal_places=2)
status = models.CharField(max_length=2048, null=True, blank=True, choices=ItemStatus.choices)
class CartItem(models.Model):
author = models.ForeignKey(to=UserModel, on_delete=model.CASCADE)
item = models.ForeignKey(Item, on_delete=models.CASCADE)
class ItemStatus(models.TextChoices):
UNDER_CONSIDERATION = 'UNDER_CONSIDERATION', 'Under consideration'
IMPOSED = 'IMPOSED', 'Imposed'
PAID = 'PAID', 'Paid'
And I need to have item grouping by class, department and status both in cart and outside of it. I also need to have aggregations of combined amounts of items in different statuses, as well as counts of different items in cart and existing. So the structure of the response has to always contain 5 values: sum of paid, imposed and considered items, and count of items existing and in cart of the calling user. I inherited from last poor sod this piece of code to do these:
def _sum(self, status):
return Coalesce(Sum('amount', filter=Q(status=status)), 0.0, output_field=FloatField())
def annotate_kwargs(self):
return {
'under_consideration_amount': self._sum(ItemStatus.UNDER_CONSIDERATION),
'imposed_amount': self._sum(ItemStatus.IMPOSED),
'paid_amount': self._sum(ItemStatus.PAID),
'count': Count('pk', distinct=True),
'in_cart': Count('pk', distinct=True, filter=Q(cartitem__author=self.user)),
}
def get(self):
return self.queryset \
.values(*self.group_by) \
.annotate(**self.annotate_kwargs())
Which basically takes the Item queryset and groupes it according to request and then annotates it. Problem is, it returns lies, as is highlighted in the docs. Methinks having 3 different tables has something to do with it, but at this point i have no way to change the model structure, so it has to stay as it is or have as little change as possible. My question is how to have these aggregations? I tried using subquery, but i don't know how to make it work with .values clause

how to combine two tables in django

There are two tables
Hookahs and tobacco for example
and for the basket model, you need to combine these two models, help
For example:
class Hookah(model.Model):
name = models.Charfield()
description = .....
price = .......
class Tabacco(model.Model):
name = models.Charfield()
description = .....
price = .......
and OrderItem model:
class OrderItem(model.Model):
and here I need to pass the top two models, as a product, how to do it?
i.e. combine Hookah and Tabacoo into one
please help me
If I understand correctly, you want a Basket model that stores a link to other types? You can do that by creating a parent model that each shopping item inherits from, or you can do it by using a GenericForeignKey which allows pointing to any model object. The shared parent model is probably better as you don't have to duplicate code for shopping items such as name, price, etc.
class ShoppingItem(model.Model)
name = models.Charfield()
description = .....
price = .......
class Hookah(ShoppingItem):
height = ....
class Tabacco(ShoppingItem):
flavour = ....
Then you can do something like one of the following:
class OrderItem(model.Model): # info on a single ordered item
item = models.ForeignKey(ShoppingItem, on_delete=models.DO_NOTHING)
class Basket(model.Model): # basket of many `ShoppingItem`
items = models.ManyToManyField(ShoppingItem)
I think in this case, you should probably look at building a single product model and have a type attribute separate the product types. That way you can FK to a single product model with your order item model.
Something like this:
models.py
class Type(models.Model):
...
name = models.CharField(max_length=50)
...
class Product(models.Model)
name = models.CharField(max_length=150)
description = models.TextField()
type = models.ForeignKey(Type, on_delete=models.DO_NOTHING)
class Order(models.Model):
...
product = models.ForeignKey(Product, on_delete=models.DO_NOTHING)
....

How to model tournaments database into a SQL in django

I want to model a tournament database to store data of online games
My question is: How to create a model in relationship database to store all this types of tournaments? (such as, league of legends tournament, dota 2 tournament)
For example, a tournament can have 8 teams or 5 teams.
This is the sketch I created in my mind. What things do you suggest (especially I need help with relationships of tables).
Also how to keep team 1 and team 2 in the match table (such as, scores, winner, loser)
i thought;
Game database
game_id,name
Player database
player_id,name,surname,country,Game(FK).. ( and some other fields)
Team database
team_id,name,country,game,Player(ManyToMany).. ( and some other fields)
Match database
match_id,name,match_game,match_map,team1,team2,winner,loser,date,duration,score1,score2.. ( and some other fields)
Tournament database
tournament_id,tournament_name,tournament_game,Match(ManyToMany).. ( and some other fields)
You can create something like this in [app_name]/models.py
from django.db import models
class Tournament(models.Model):
name = models.CharField(max_length=255)
class Team(models.Model):
name = models.CharField(max_length=255)
class Player(models.Model):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
country = models.CharField(max_length=255)
team = models.ForeignKey(Team, on_delete=models.CASCADE)
class Match(models.Model):
name = models.CharField(max_length=255)
match_game = models.CharField(max_length=255)
match_map = models.CharField(max_length=255)
match_teams = models.ManyToManyField(Team)
winner = models.ForeignKey(Team, on_delete=models.CASCADE)
loser = models.ForeignKey(Team, on_delete=models.CASCADE)
duration = models.DurationField()
winning_score = models.PositiveIntegerField()
losing_score = models.PositiveIntegerField()
tournament = models.ForeignKey(Tournament, on_delete=models.CASCADE)
class Game(models.Model):
name = models.CharField(max_length=255)
match = models.ForeignKey(Match, on_delete=models.CASCADE)
Some things to note:
You do not need to create ID fields, Django does this for you automatically.
A Many-to-Many field can often be replaced with a One-to-One field on the other model, for instance instead of many matches having many games, each game is part of one match. This may or may not work in your particular use case.
I have changed some field names (such as score_1 being replaced with winning_score) because I feel they are more clear, assuming I have correctly understood their purpose.
There are some fields (Tournament.tournament_game, Player.country) for which I used CharField but would be better served with a ForeingKey field to a separate model.
This also assumes that you do not need different fields for different types of tournament (League of Legends, DOTA). If you do need this you could achieve it with different models that inherit from an abstract base class:
class Game(models.Model):
name = models.CharField(max_length=255)
match = models.ForeignKey(Match, on_delete=models.CASCADE)
class Meta:
abstract = True
class DOTA2Game(Game):
dota_field = models.CharField(max_length=255)
class LeagueOfLegendsGame(Game):
lol_field = models.CharField(max_length=255)
In this example DOTA2Game and LeagueOfLegendsGame both inherit from Game and therefore have both a name and a match field as well as their custom fields. Setting abstract = True in the meta class of Game prevents it existing as a separate table within the database.

Displaying columns from multiple tables in Django

im new with this django database querying.
how can i translate this into a django queryset
SELECT prod.item_code_id, prod.name, price.SRP
FROM inventory_product prod, inventory_pricing price
WHERE prod.item_code_id = price.item_code_id
class Product(models.Model):
item_code_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=255)
description = models.CharField(max_length=255)
category = models.ForeignKey(Category)
color = models.ForeignKey(Color)
brand = models.ForeignKey(Brand)
item_size = models.ForeignKey(ItemSize)
class Pricing(models.Model):
product_id = models.AutoField(primary_key=True)
item_code = models.ForeignKey(Product)
supplier = models.ForeignKey(Supplier)
SRP = models.DecimalField(max_digits=5, decimal_places=2)
Daniel Roseman is right. Don't use SQL query unless you really need them.
In your example, Django ORM should be enough. It would be better if you posted you models, but it will look smth like:
for prod in Product.objects.all():
price = Pricing.objects.get(item_code=prod)
print prod.pk, prod.name, price.SRP

Django annotate code

Just stumbled upon some guy code
He have models like this
class Country(models.Model):
name = models.CharField(max_length=100)
class TourDate(models.Model):
artist = models.ForeignKey("Artist")
date = models.DateField()
country = models.ForeignKey("Country")
And is querying like this
ireland = Country.objects.get(name="Ireland")
artists = Artist.objects.all().extra(select = {
"tourdate_count" : """
SELECT COUNT(*)
FROM sandbox_tourdate
JOIN sandbox_country on sandbox_tourdate.country_id = sandbox_country.id
WHERE sandbox_tourdate.artist_id = sandbox_artist.id
AND sandbox_tourdate.country_id = %d """ % ireland.pk,
}).order_by("-tourdate_count",)
My question is why He have underscores like sandbox_tourdate but it isn't in model field
Is that created automatically like some sort of pseudo-field?
sandbox_tourdate isn't the name of the field, it's the name of the table. Django's naming convention is to use appname_modelname as the table name, although this can be overridden. In this case, I guess the app is called 'sandbox'.
I don't really know why that person has used a raw query though, that is quite easily expressed in Django's ORM syntax.