Django, m2m with same model - python

I have following models in my django app:
Product model:
class Product(BaseModel):
company = models.ForeignKey(Company, null=True, blank=True)
title = models.CharField(max_length=128,verbose_name="Product title")
Order model:
class Order(BaseModel):
company = models.ForeignKey(Company)
products = models.ManyToManyField(Product)
I am not able to add multiple same products to an order.
For example, I have product called "Car", how can I add multiple Car objects to single Order?
Every Order may contain multiple Products (same or not).

You need to use third table for that task, for example:
class OrderProduct(BaseModel):
order = models.ForeignKey(Order)
product = models.ForeignKey(Product)
quantity = models.IntegerField()
and then you can use intermediary table https://docs.djangoproject.com/en/dev/topics/db/models/#intermediary-manytomany
class Order(BaseModel):
company = models.ForeignKey(Company)
products = models.ManyToManyField(Product, through='OrderProduct')
Unlike normal many-to-many fields, you can’t use add, create, or assignment (i.e., order.products.add(prod)) to create relationships. You should manually create record in through table:
prod = Product.objects.get(uuid=product)
#order.products.add(prod)
q = product_quantity
order = order # order record must be created before
OrderProduct.objects.create(order=order, product=prod, quantity=q)
check this questions:
How can I add the same object to a ManyToMany field?
adding the same object twice to a ManyToManyField

The many to many relationship with foreign keys works backwards. You don't need a foreign key in your Order model. What you need is a foreign key in the Product model linking to Orders (Every product will have an order) :
class Product(BaseModel):
company = models.ForeignKey(Company, null=True, blank=True)
order = models.ForeignKey(Order)
title = models.CharField(max_length=128,verbose_name="Product title")

Related

what is the right way to use prefetch_related or select_related to achieve this in django

hey guys i have these models
class Theme(models.Model):
name = models.charfield()
class Category(models.Model):
name = models.charfield()
class Product(models.Model):
category = models.ForeginKey(Category)
theme = models.ForeignKet(Theme)
......
class Order(models.Model):
product = models.ForeigKey(Product)
i want to fetch the product and the category of the product from an order instance in one query, i know that for forward foreignkey you should use select related but i don't think there's a way to fetch the product category when you use this:
Order.objects.all().select_related('product')
so is it right to use this one then:
Order.objects.all().prefetch_related('product__category')
my last question let's say i have instead these models:
class Category(models.Model):
name = models.charfield()
class Product(models.Model):
category = models.ForeginKey(Category)
theme = models.ForeignKet(Theme)
class Course(models.Model):
category = models.ForeginKey(Category)
......
class Order(models.Model):
product = models.ForeigKey(Product)
if i have products and i want to fetch also the category and the courses related to this category too
product = LvaProducts.objects.all().select_related('category')[0]
courses = product.category.course_set
is this is the most efficient way to do this?
Since the relation from Order to Product is a many-to-one relation, and that of Product to Category is a many-to-one relation, you fetch these both through .select_related(…) [Django-doc]:
Order.objects.select_related('product__category')
You can chain relationships in a select_related call with double underscores
Order.objects.all().select_related('product__category')
EDIT: You can run a prefetch on a related model by using the same technique
Product.objects.select_related(
'category'
).prefetch_related(
'category__course_set'
)

Django Designing Model : Item/Inventory/User

I would like to ask some advice on Modeling a specific model behavior.
Basically I have a model Item. It describes the name and description of an item.
I have a inventory, which should hold a "List" of items, considering the quantity of each item should be specified in the inventory.
Each User should have one unique inventory.
Here's what I'm trying to do:
class User(models.Model):
name = models.CharField(max_length=100)
invetory =models.ForeignKey(inventory,on_delete=models.CASCADE)
class item(models.Model):
name =models.CharField(max_length=40)
description = models.TextField(max_length=200)
value = models.FloatField()
class inventory(models.Model):
?
I'm not sure if this is the right approach.
You should use many-to-many relations. First of all you should delete the FK from the User model. Then create a separate model for items and finally link many users to many items (one user can handle multiple items and one item can belong to multiple users). Something like that:
class User(models.Model):
name = models.CharField(max_length=100)
class item(models.Model):
name =models.CharField(max_length=40)
class inventory(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
item = models.ForeignKey(item, on_delete=models.DO_NOTHING)
quantity = models.FloatField()
PS Class names should use PascalCase convention https://www.python.org/dev/peps/pep-0008/?#class-names
class User(models.Model):
name = models.CharField(max_length=100)
class Inventory(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE)
class Item(models.Model):
name =models.CharField(max_length=40)
description = models.TextField(max_length=200)
value = models.FloatField()
invetory =models.ForeignKey(Inventory,on_delete=models.CASCADE)
This should work as per your specification. We have tied up inventory to a user and each item will have a foreign key to Inventory table.
Now you can do
1. To access inventory you can do `user.inventory`
2. To get a list of items `user.inventory.item_set`
3. You should use the `post_save` signal to create the inventory object.
class inventory(models.Model):
user = models.ForeignKey(User, default=User.objects.first())
item = models.ForeignKey(Item, default=Item.objects.first())
count = models.IntegerField(default=0)
I think this would make a better design.

Aggregation and track back relations to multiple models in a single view Django

I am doing first steps in Django and currently can't resolve further difficulties. Imagine we have next data scheme:
class Categories(models.Model):
name = models.CharField()
class Inventories(models.Model):
name = models.CharField(unique = True)
unit = models.CharField()
category = models.ForeignKey(Categories)
class Suppliers(models.Model):
name = models.CharField()
class InventoryReceiving (models.Model):
name = models.ForeignKey(Inventories, related_name='item_received')
quantity = models.DecimalField(max_digits=6, decimal_places=2)
supplier = models.ForeignKey(Suppliers, related_name = 'item_supplier')
I would like to group_by names in InventoryReceiving to get distinct values and aggregated quantity fields. Then track back relations and get a single grouped_by name table with human readable name, unit, category, supplier and quantity labels.
I came up with an expression which return name_id (I need names from the related table) and sum:
inventory_list = InventoryReceiving.objects\
.values('name')\
.annotate(agg_sum=Sum('quantity'))
I think you can just add the rest of the related data you need.
InventoryReceiving.objects.values(
'name__name', #Inventories.name
'name__unit', #Inventories.unit
'name__category__name', #Inventories.category.name
'supplier__name' #Suppliers.name
).annotate(agg_sum=Sum('quantity'))

Django how to filter queryset based on nested many to many relations in one query

Let's say I have a product that can have various child products, and the models are defined like this
class Country(models.Model):
name = models.CharField()
class Product(models.Model):
parent = models.ForeignKey(
'self', null=True, blank=True, related_name='children')
name = models.CharField()
countries = models.ManyToManyField(Country)
my goal is to retrieve all products that have one or more child products that are linked to a specific country.
In my use case I need this information as a Queryset. What I have tried is this and it works:
valid_products = []
desired_country = Country.objects.get(name='mycountry')
for product in Product.objects.all():
for child in product.children.all():
countries = child.countries.all()
for country in countries:
if country == desired_country:
valid_products.append(product.id)
desired_queryset = Product.objects.filter(pk__in=valid_products)
This method requires and additional query to convert my result into a queryset and I would like to avoid that.
Is it possible to filter a queryset like this directly with the Django ORM?
You can simply follow the relations using the double-underscore syntax. So:
desired_queryset = Product.objects.filter(children__countries= desired_country)

one-to-many field in Django

I've got this class:
class PurchaseOrder(models.Model):
product = models.CharField(max_length=256)
dollar_amount = models.FloatField()
item_number = models.AutoField(primary_key=True)
I'm trying to make it so that 'product' has a one to many field. In other words, whenever I am adding a new item in django's default admin page. I want to be able to have the option of putting multiple 'product' for the same dollar amount and item number.
In response to Hedde van der Heide's comment. Would this be how you implement this?
class PurchaseOrder(models.Model):
product = models.ManyToManyField(Order)
dollar_amount = models.FloatField()
item_number = models.AutoField(primary_key=True)
class Order(models.Model):
order_product = models.CharField(max_length =256)
def __unicode__(self):
return self.order_product
No, your edit is incorrect. That would imply a purchase order could belong to many orders and vice versa, which makes no sense. You want a simple ForeignKey from PurchaseOrder to Order.

Categories

Resources