Gel all the values of Many2Many intermediate table with their respective name - django

I have the following database structure:
Products
--------
id name
1 prodA
2 prodB
Products_Invoices
-----------------
product_id Invoice_id
1 1
2 1
Invoices
--------
id name
1 InvA
2 InvB
Which is most correct way to retrieve all the values of the Products_Invoices table but bring the names of their respective row in parent tables.

Since you stated that you have
products = models.ManyToManyField('Product', blank=True)
You can do the following:
invoices = Invoice.objects.all()
for invoice in invoices:
for product in invoice.products.all():
print(product.name)
For efficiency, you can also prefetch all the products for the invoice using prefetch_related
invoices = Invoice.objects.all().prefetch_related('products')

Related

Django LEFT JOIN or INNER JOIN the same query set together multiple times

It's been a minute since I've used SQL so I'm not 100% sure LEFT or INNER join is the correct term, as I googled this and in most cases, people just wanted to concatenate the results, which is not SQL JOIN's. I have 3 models. Dumbed down they are as follows:
class Stakeholders(models.Model):
firstname = models.CharField(max_length=50)
lastname = models.CharField(max_length=50)
email = models.EmailField(max_length=254)
class Policy(models.Model):
name = models.CharField(max_length=50)
description = models.CharField(max_length=150)
class StakeholderPolicyResp(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
stakeholder = models.ForeignKey(Stakeholders, on_delete=models.CASCADE)
policy = models.ForeignKey(Policy, on_delete=models.CASCADE)
response = models.IntegerField(default=0)
I want to create a table that has a unique stakeholder with the response for up to 4 policies.
In simple example:
Stakeholder
-------------------
1 John Doe jd#email.com
Policy
-------------------
1 Policy 1
2 Policy 2
3 Policy 3
StakeholderPolicyResp
-------------------
UID1 1 1 0
UID2 1 2 4
UID3 1 3 3
What I want out is a table that can have varying amount of columns, but something like this:
MyTable
------------------
Stakeholder data - Policy x Resp - Policy y Resp - Policy z Resp
==================
John | Doe | 0 | 4 | 3
Here we have the stakeholder with the responses for policy 1, policy 2 and policy 3. From here I'm going the render the data and doing that is fairly easy. It need not be in qs format. A possible format might be using pandas data frame, but is there an easier django'y way of doing it?

How to count quantity with distinct?

I have 2 templates, one representing a product sheet and the other one an actual product in stock.
The stock can have several products that have the same product sheet.
Example:
I can have a product record "Water bottle", and several "water bottle" in the stock.
My models:
class Stock(models.Model):
machine = models.ForeignKey(
"machine.Machine",
verbose_name=_("machine"),
related_name="machine_stock",
on_delete=models.CASCADE
)
product = models.ForeignKey(
"client.Product",
verbose_name=_("product"),
related_name="product_stock",
on_delete=models.CASCADE
)
epc = models.CharField(_("EPC"), max_length=80)
dlc = models.DateField(_("DLC"))
class Product(models.Model):
name = models.CharField(_('Name'), max_length=255)
[...]
I want to retrieve the products in stock sorted by both DLC and name.
On my frontend I want to display a table with for each row:
the name of the product
the dlc
the number of products with this name and this dlc
Example:
If I have 2 product sheets (Product Model) :
water bottle
bottle of coca cola
and I have 5 products in stock (Stock Model) :
2 bottles of water whose dlc is 02/04/2022
2 bottles of cola whose dlc is the 02/04/2022
1 bottle of cola whose dlc is 03/04/2022
I want to display 3 lines in my table:
Quantity | Name | DLC
2 | water | 02/04/2022
2 | cola | 02/04/2022
1 | cola | 03/04/2022
I tried with
queryset = (
Stock.objects.all()
.select_related('product')
.select_related('machine')
.annotate(quantity=Count("product__name", distinct=True))
.distinct("dlc", "product__name",)
.order_by("-dlc")
)
But django ORM don't accept annotate and distinct in the same query.
It's works with:
queryset = (
Stock.objects.all()
.select_related('product')
.select_related('machine')
#.annotate(quantity=Count("product__name", distinct=True))
.distinct("dlc", "product__name",)
.order_by("-dlc")
)
for result in queryset:
result.quantity = Stock.objects.filter(dlc=result.dlc, product__name=result.product.name).count()
But I'm not sure that is the best method to use.

Django how to filter a foreign key object only with specific value

I have two tables.
Table Product
id | name |
Table Discount
id | product_id | is_deleted
Two models are:
class Product(models.Model):
name = models.CharField(max_length=10)
class Discount(models.Modle):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
is_deleted = models.BooleanField(default=True)
product_id is the foreign key of product table's id, and is_deleted is a boolean field.
How can I filter all products only with is_deleted discount? Notice those two tables may be large, so .exclude() is not fit for this case.
product_ids_subquery = Discount.objects.values('product').annotate(
deleted=(Count('product') - Count('product', filter=Q(is_deleted=True)))
).filter(deleted=0).values('product')
products_qs = Product.objects.filter(id__in=product_ids_subquery)
we can identify that products only with is_deleted discount with the help of count after group by product. For each product,
calculate how many records are present in discount table. let say total_count = Count('product')
calculate how many records are present which is deleted. let say deleted_count = Count('product', filter=Q(is_deleted=True))
deleted = (total_count - deleted_count) gives you a no. which is not deleted
if deleted == 0 then you can say all mapped records are deleted
products = Product.objects.filter(discount__is_deleted=True)

How does postgreSQL structure Django Array Fields in database

How does PostgreSQL structure an ArrayField like:
class House(models.Model):
people_ids = ArrayField(models.IntegerField(), default=list, blank=True)
in database? Does it generate an auxiliary table with the numbers as Ids and then another table with the Id pairs? Like:
House
Id
Name
1
MyHouse
People
Id
1
2
House_People
House_Id
Person_Id
1
1
1
2
So as to have, for example, people 1 and 2 in house "MyHouse"?

django accessing raw many to many created table fields

Model:
class Subjects (models.Model):
name = models.CharField(max_length=100)
places = models.CharField(max_length=100)
class Student (models.Model):
name = models.CharField(max_length=40)
lastname = models.CharField(max_length=80)
subjects = models.ManyToManyField(Subjects, blank=True)
Django creates appname_student_subjects when I use model above.
appname_student_subjects table looks for example, like this:
id | student_id | subjects_id
-----------------------------------------
1 | 1 | 10
2 | 4 | 11
3 | 4 | 19
4 | 5 | 10
...
~1000
How can I access subjects_id field and count how many times subjects_id exists in the table above (and then do something with it). For example: If subject with id 10 exists two times the template displays 2. I know that I should use "len" with result but i don't know how to access subject_id field.
With foreign keys I'm doing it like this in a for loop:
results_all = Students.objects.filter(subject_id='10')
result = len(results_all)
and I pass result to the template and display it within a for loop but it's not a foreign key so it's not working.
You can access the through table directly.
num = (Students.subjects # M2M Manager
.through # subjects_students through table
.objects # through table manager
.filter(student_id=10) # your query against through table
.count())