Django relations nesting "related_name" - django

I'm trying to create single loop that will iterate through all sizes for each product from category. My models:
class Category(models.Model):
...
class Product(models.Model):
category = models.ForeignKey(Category, db_column="id", on_delete=models.CASCADE, related_name="products")
...
class Size(models.Model):
product = models.ForeignKey(Product, db_column="id", on_delete=models.CASCADE, related_name="sizes")
...
And my code in service
def adjust_sizes(self, category: Category) -> None:
for size in category.products.sizes.all():
# rest of my function
But when I was trying to run this function I got error:
*** AttributeError: 'RelatedManager' object has no attribute 'sizes'
I wanted this to run in single loop, can someone help me how to do that?

You can't access the manager on top of a manager. What you do in this case is query in reverse, so:
def adjust_sizes(self, category: Category) -> None:
for size in Size.objects.filter(product__category=category):
# rest of my function
pass
Very likely using db_column='id' is however not a good idea, since it can/will clash with the database column for the primary key.

lass Category(models.Model):
...
class Product(models.Model):
category = models.ForeignKey(Category, db_column="id", on_delete=models.CASCADE, related_name="products")
...
class Size(models.Model):
product = models.ForeignKey(Product, db_column="id", on_delete=models.CASCADE, related_name="sizes")
...

Related

How do I access instance of a many-to-many field in django __str__ method

I am having two models;
class Cart(models.Model):
book = models.ForeignKey(Book, on_delete=models.CASCADE, related_name="book")
quantity = models.PositiveIntegerField(default=1, null=True, blank=True)
def __str__(self):
return f"{self.quantity} of {self.book.title}"
class Order(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
cart = models.ManyToManyField(Cart)
def __str__(self):
return f"{self.cart.quantity}"
I get:
'ManyRelatedManager' object has no attribute 'quantity'
This usually works for a ForeignKey field; but it seems not to for a ManyToManyField.
Note: I am trying to access quantity that belongs to the cart model from the Order model using ManyToManyField.
Is there any way of doing something like this?
self.cart returns 'ManyRelatedManager'.
you have to write something like this:
self.cart.last().quantity
# OR
self.cart.first().quantity
or get sum of all, with self.cart.all()
sum([_.quantity for _ in self.cart.all()])

Getting a column instead of an object when relating with PrimaryKeyRelatedField in Django-Rest-Framework

I have a model for applications, which among many attributes have a category. This category is in fact a key to another model that has the category ID, its name, and so on.
class Application(models.Model):
title = models.CharField(max_length=50)
vendor = models.CharField(max_length=50, default="Unknown", null=False)
.
.
.
category = models.ForeignKey('ApplicationCategory', related_name='applications', null=False, default=1, on_delete=models.SET_DEFAULT)
class ApplicationCategory(models.Model):
name = models.CharField(max_length=20, null=False)
description = models.CharField(max_length=200, null=False)
Then, on the Django REST serializers side I have the serializer for the applications:
class SoftwareSerializer(serializers.ModelSerializer):
category = serializers.PrimaryKeyRelatedField(queryset=ApplicationCategory.objects.all())
class Meta:
model = Application
fields = ['id', 'title', ... 'category']
Which is generating the expected API view, with a dropdown for the categories, but showing them as the ApplicationCategory objects and not giving me their name.
API showing Category dropdown with objects instead of names
Is there a way to access attributes of those objects to show the name in the dropdown, for usability sake?
I have also tried creating a CategorySerializer object (class CategorySerializer(serializers.ModelSerializer)) and then using it as category = CategorySerializer(many=False) but instead of dropdowns, I get open text fields for the attributes of the category.
Am I trying to do something that is not expected to work?
try to define the desired text in str method for your ApplicationCategory class:
class ApplicationCategory(models.Model):
name = models.CharField(max_length=20, null=False)
description = models.CharField(max_length=200, null=False)
#example
def __str__(self):
return '%s: %s' % (self.name , self.description)

How do I create this queryset?

I have the following three models:
class Category(models.Model):
name = models.CharField(max_length=120)
class Experiment(models.Model):
name = models.CharField(max_length=50, unique=True)
categories = models.ManyToManyField(Category)
class Ad(models.Model):
experiment = models.ForeignKey(Experiment, related_name='ads', on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.PROTECT, blank=True, null=True)
I want to create a queryset which returns all ads where ad.category is in ad.experiment.categories.
Some example data to talk through:
Category: ['Cat1', 'Cat2', 'Cat3', Cat4', 'Cat5']
Experiment: [['Exp1',['Cat2','Cat3]],['Exp2',['Cat5','Cat1']]]
Ad: [['Exp1','Cat4'],['Exp1','Cat2']]
The queryset I'm hoping to create would only return the second ad because the ad's category is in the ad's experiment's category.
Any help would be appreciated!
You need to traverse the reverse relationship for experiment and then use an F object to access the ad's category field in the query. The distinct is used because the experiment will have many categories so one ad may have multiple matches on the comparison.
from django.db.models import F
Ad.objects.filter(experiment__category=F('category')).distinct()

Django - How to filter using a ManyToManyField field?

Models:
class Product(models.Model):
...
options = models.ManyToManyField(Option, blank=True)
class Option(models.Model):
...
class ProductVariant(models.Model):
...
product = models.ForeignKey(Product, on_delete=models.CASCADE) # parent product
option = models.ForeignKey(Option, on_delete=models.DO_NOTHING, null=True)
I need to find all the ProductVariants where the option doesn't belong to any options on the parent product Product.
I tried doing the following filtering:
ProductVariant.objects.exclude(option_id__in=[o.pk for o in F('product__options')])
But I got the following exception:
'F' object is not iterable
Try filtering by Count instead:
ProductVariant.objects.annotate(product_count=Count('option__product')).filter(product_count=0)

ForeignKey to a model that is defined after/below the current model

Having the error msg
order = models.ForeignKey(Order, on_delete=models.CASCADE)
NameError: name 'Order' is not defined
So how ever I do one class will be missing cuz of the class is below the currently reading class so that the class is missing. How do I solve this? i've read about many-to-many function, might that solve the problem?
class Items(models.Model):
name = models.CharField(max_length=10)
def __str__(self):
return self.name
class OrderedItem(models.Model):
items = models.ForeignKey(Items, on_delete=models.CASCADE)
order = models.ForeignKey(Order, on_delete=models.CASCADE)
amount = models.IntegerField()
def __str__(self):
return self.items
class Order(models.Model):
#clientID
orderedItem = models.ForeignKey(OrderedItem, on_delete=models.CASCADE)
#truckId Foreign key till truck
created = models.DateTimeField(auto_now=False, auto_now_add=True)
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
emergency = models.BooleanField(default=False)
status = models.IntegerField()
#building
#floor
def __str__(self):
return self.id
Use the fully-qualified model string
When this happens, I usually resort to what's called the fully-qualified model string, fancy term for what's essential a string representing the model and the containing app in the format of 'app_label.ModelName'
E.g. if your model is Order, then the model string name would be the string 'Order'
So you can already do:
order = models.ForeignKey('Order', on_delete=models.CASCADE)
With the above, Django will look for the model 'Order' in the same app. It's okay if you have not defined it yet, as long as it is defined.
If that model happens to come from a different app, it would be:
order = models.ForeignKey('appname.Order', on_delete=models.CASCADE)
Reverse query clashes
Because Order points to OrderItems and OrderItems point to Order you get a clash with related queries that Django generate for you. You can disable those with related_name='+':
order = models.ForeignKey('Order', on_delete=models.CASCADE, related_name='+')
Better modeling
Since a OrderedItem already "belongs" to an Order, there's no point in having a ForeignKey from Order to OrderedItem, you can just remove it instead of dealing with the above clash.
So what you'd have would look like this
Item
Order
OrderedItem
+ FK(Item)
+ FK(Order)
A design which wouldn't involve referencing a model that hasn't been defined yet :)
The reason it can't find the class order is because it hasn't been defined yet, you either need to specify it as a string as shown by Shang Wang, or change the order of them in your models.py
class Order(models.Model):
#clientID
orderedItem = models.ForeignKey(OrderedItem, on_delete=models.CASCADE)
#truckId Foreign key till truck
created = models.DateTimeField(auto_now=False, auto_now_add=True)
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
emergency = models.BooleanField(default=False)
status = models.IntegerField()
#building
#floor
def __str__(self):
return self.id
class OrderedItem(models.Model):
items = models.ForeignKey(Items, on_delete=models.CASCADE)
order = models.ForeignKey(Order, on_delete=models.CASCADE)
amount = models.IntegerField()
def __str__(self):
return self.items
Changing the order has its advantages over specifying as a string since it will allow IDE's to find usages of the class should it ever need refactoring.
Since you have foreign keys to both classes, the above won't work and only applies to one-to-one or one-to-many relationships. Instead, it would be better to define a ManyToManyField instead of the two foreign keys
You have defined class Items before use it and you have not any error.
you must define class Order before class OrderedItem.