How to join tables with O2M and M2M relationship? - python

I have the following related data models
class Cart(models.Model):
products = models.ManyToManyField('assortment.Product', through='CartProduct')
order = models.OneToOneField('Order', on_delete=models.CASCADE, related_name='order_cart', null=True)
user = models.ForeignKey('account.Profile', on_delete=models.CASCADE, related_name='user_carts', blank=True, null=True)
class CartProduct(models.Model):
product = models.ForeignKey('assortment.Product', related_name='product_cartproducts', null=True, on_delete=models.SET_NULL)
cart = models.ForeignKey('Cart', related_name='cart_cartproducts', null=True, on_delete=models.SET_NULL)
count = models.IntegerField(blank=False, null=False, default=1)
class Order(models.Model):
pay_date = models.DateField(auto_now_add=True)
is_paid = models.BooleanField(default=False)
My code below gives an error: invalid argument "products" in prefetch_related:
Order.objects.all().select_related('order_cart').prefetch_related('products')
How can I join all three models in one request?

The query builder continues with the original table (Order), thus you have to specify the fields relative to that or relative to the previously mentioned field. Try one of the following:
'order_cart__products'
'order_cart__cart_cartproducts'
(Notice the double underscore.)

Related

Django DRF Model doesn't show foreign keys in admin panel

I have a model in my Django application for review. This model has two foreign keys to the product and user models. But when I go to the admin panel and try to add a new review I don't see the review models dropdown select for the foreign keys.
I'm expecting to see the foreign keys fields rendered in my admin panel as dropdown selects like in the blue box in the picture below.
Screenshot of my admin panel to add a new order object
But the admin panel doesn't show those fields. It only shows the name, rating, and comment fields.
Screenshot of my admin panel to add a new reivew object
Here is my review model.
class Reviews(models.Model):
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True),
product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True),
name = models.CharField(max_length=350, null=True, blank=True)
rating = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True, default=0)
comment = models.TextField(null=True, blank=True)
createdAt = models.DateTimeField
_id = models.AutoField(primary_key=True, editable=False)
def __str__(self):
return str(self.rating)
In your Reviews model, you have put a comma at the end of users and product fields. Remove the trailing comma at the end, as the fields are considered as tuple when a comma is present.
It should be:
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True)
Also, your createdAt field is not correct.
It should be:
createdAt = models.DateTimeField()
Try it like this, i removed comma from user and product field in the end, also i have added () in DateTimeField
class Reviews(models.Model):
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True)
name = models.CharField(max_length=350, null=True, blank=True)
rating = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True, default=0)
comment = models.TextField(null=True, blank=True)
createdAt = models.DateTimeField()

Django Model not defined

I've been working on some views and using a model for like a week now and there was no issues until now: I did not change anything but add a new field to the model, and now myModel.objects.create() gives me a name is not defined error. I have the model imported and as I said, I've been working on this for a week and I created several models using the exact same code.
models:
class Prescription(models.Model):
prescription_id = models.CharField(max_length=26, default=prescription_id, editable=False, unique=True) # THIS IS THE FIELD I ADDED BEFORE HAVING THIS ERROR
appointment = models.ForeignKey('booking.Appointment', on_delete=models.SET_NULL, null=True, blank=True)
doctor = models.ForeignKey('core.Doctor', on_delete=models.CASCADE)
patient = models.ForeignKey('core.Patient', on_delete=models.CASCADE)
overriden_date = models.DateField(null=True, blank=True)
control = models.BooleanField(default=False)
control_date = models.DateField(null=True, blank=True)
send_email = models.BooleanField(default=False)
posted = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = "Ordonnance"
verbose_name_plural = "Ordonnances"
def __str__(self):
return str(self.id)
class PrescriptionElement(models.Model):
prescription = models.ForeignKey('Prescription', on_delete=models.CASCADE)
drug = models.ForeignKey(Drug, on_delete=models.CASCADE, null=True)
custom = models.CharField("Elément", max_length=25, null=True, blank=True)
dosage = models.CharField(max_length=45, null=True, blank=True)
posologie = models.CharField(max_length=256, null=True, blank=True)
duration = models.CharField("Durée", max_length=15, null=True, blank=True)
views:
PrescriptionElement.objects.create(prescription=prescription, drug=listemedicament, custom=medicament, dosage=dosage, posologie=posologie, duration=duree)
error:
name 'PrescriptionElement' is not defined
I fixed the issue by removing any circular relation between multiple files. Circular Imports are the one problem causing this. The prescription_id default value was defined in a file called utils.py, and in utils.py there are some functions inheritting models from the models.py file. Removing this circular relationship fixes this issue.
Also, using this format to defined ForeignKeys ('booking.Appointment') is the better choice to avoir importing.

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)

How to write a self referencing Django Model?

I have a Django model "Inspection" which has:
InspectionID (PK)
PartID
SiteID
Date
Comment
Report
Signiture
I want to be able to have a one to many relationship between the inspection ID and date. So one ID can have inspections at many dates. How would I do this? I currently have the following:
class Inspection(models.Model):
InspectionID = models.IntegerField(primary_key=True, unique=True)
PartID = models.ForeignKey('Part', on_delete=models.CASCADE)
SiteID = models.ForeignKey('Site', on_delete=models.CASCADE)
Date = models.DateField(auto_now=False, auto_now_add=False)
Comment = models.CharField(max_length=255, blank=True)
Report = models.FileField(upload_to='docs', null=True, blank=True)
Signiture = models.CharField(max_length=255, blank=True)
I thought about using models.ForeignKey but I really don't know how to implement that properly in this situation.
I want to be able to have a one to many relationship between the inspection ID and date.
You create an extra model, like:
class InspectionDate(models.Model):
inspection = models.ForeignKey(
Inspection,
on_delete=models.CASCADE,
related_name='inspectiondates'
)
date = models.DateField()
You thus can create InspectionDates for a given Inspection.
Or if you want to add extra data, it might be better to define an InspectionGroup model:
class InspectionGroup(models.Model):
pass
class Inspection(models.Model):
id = models.AutoField(primary_key=True, unique=True, db_column='InspectionId')
inspectiongroup = models.ForeignKey(InspectionGroup, on_delete=models.CASCADE, db_column='InspectionGroupId')
part = models.ForeignKey('Part', on_delete=models.CASCADE, db_column='PartId')
site = models.ForeignKey('Site', on_delete=models.CASCADE, db_column='SiteId')
date = models.DateField(db_column='Date')
comment = models.CharField(max_length=255, blank=True, db_column='CommentId')
report = models.FileField(upload_to='docs', null=True, blank=True, db_column='ReportId')
signiture = models.CharField(max_length=255, blank=True, db_column='Signature')
Note: the name of attributes are normally written in snake_case [wiki], not in PerlCase or camelCase.
you may store 'self Foriegnkey' as
class Inspection(models.Model):
InspectionID = models.IntegerField(primary_key=True, unique=True)
PartID = models.ForeignKey('Part', on_delete=models.CASCADE)
SiteID = models.ForeignKey('Site', on_delete=models.CASCADE)
Date = models.DateField(auto_now=False, auto_now_add=False)
Comment = models.CharField(max_length=255, blank=True)
Report = models.FileField(upload_to='docs', null=True, blank=True)
Signiture = models.CharField(max_length=255, blank=True)
inspection_id = models.ForeignKey('self', null=True, blank=True)

filter manytoone relationship, exclude childs on condition

I have a one to many relationship with category and products, category and product have active fields, if any of them are not active I want to exclude them from list.
categories = Category.objects.filter(is_active=True)
But now category can have many products, and some of them are inactive, how could I filter and exclude inactive products from all of categories?
Models:
class Category(MPTTModel):
name = models.CharField(max_length=50, blank=False, unique=True)
is_active = models.BooleanField(default=True)
parent = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children', db_index=True)
class Product(models.Model):
name = models.CharField(max_length=50, blank=False, unique=True)
is_active = models.BooleanField(default=True)
category = TreeForeignKey('Category', on_delete=models.CASCADE, null=True, blank=True, db_index=True)
If you need to filter related pruducts you can use prefetc_related with Prefetch object:
from django.db.models import Prefetch
categories = Category.objects.filter(is_active=True).prefetch_related(Prefetch('product_set', queryset=Produc.objects.filter(is_active=True)))
in this case for each category from categories this code
category.product_set.all()
will return only active product. Moreover this queryset will not hit DB, since related product will be cached by first query.

Categories