Django) How to inquire field of another model in ManyToMany relationship - django

I want to inquire data field from model which contains another model in ManyToMany relationship.
For instance, I want to calculate total cost from Dinner model, which has ManyToMany relationship with Menu model. Here goes simplified code.
class Menu(models.Model):
cost = models.IntegerField()
class Dinner(models.Model):
menus = models.ManyToManyField(Menu)
objects = DinnerManager()
class DinnerManager(models.Manager):
def get_total_cost(self):
total_cost = 0
for each_menu in self.menus.all():
total_cost += each_menu.cost
return total_cost
So my question is this: how should I set
for each_menu in self.menus.all():
total_cost += each_menu.cost
these two lines to get my class method work?
(or if other parts is wrong, please let me know. I'm fairly new to django..)

This code would work fine, except that it belongs on the Dinner model, not the Manager. It's relating to a specific dinner, not dinners generally, and needs to calculate the value of the menu items related to that individual dinner.

Related

Is it possible to link multiple models to one fiel in django?

Let's say I have these models:
class Material(models.Model):
name = models.CharField([...])
class Consumable(models.Model):
name = models.CharField([...])
restores = models.IntegerField([...])
class Weapon(models.Model):
name = models.CharField([...])
damage = models.IntegerField([...])
# And then I have an 'inventory', like this one:
class Inventory(models.Model):
user = models.ForeignKey([...]) # to which user you want to link the item
item = models.ForeignKey([...]]) # which item
quantity = models.IntegerField([...]) # how many of it
I want to be able to have all Material, Consumable, and Weapon models listed in the 'item' field, so when you want to add an item as an inline, you would see all 3 models' objects.
Something like
# instead of this
item = models.ForeignKey(Consumable) # which item
# want something like this
item = models.ForeignKey(Consumable and Material and Weapon) # which item
# this wouldn't work ofc...
Is there a way to collect all 3 of them and pass them to the 'item' field, without the need of restarting the server? (when making a "choices" list that queries from a model you must restart the server to see the newly added objects, I don't want that.)
I also want to stick to the built-in admin of Django since it provided everything I need for the past couple of months, but I am open to any ideas.
I could be wrong but I think you are making this more complex than it needs to be. Instead of doing separate classes for materials (type of material) and consumable (type of product), you can have that built in the last class as model field as category or bolean fields.
class Products(models.Model):
material_type =
consumable = boolean for yes no or you can do multiple choice field
Then for items you can query the number of items based on material_type or consumable model fields (see query filters for for more).
all_items = Products.model.all()
consumable_items = Products.model.filter(your filter logic goes here)
Hope this helps!

Populating django model with objects from other model

I'm new to django, but working on an app for a volunteer sailing organization in my local area. Not sure how to ask this question since it's fairly general but I want the following to happen based on two models;
Yacht class (boat name, skipper, color, etc.)
Race_Event class (event date, time results for each boat)
Step 1: The user will need to create a Race_Event each week. I want the boats from the Yacht model to be loaded into the Race_Event.
Step 2: The user will enter race times for each boat.
Is there a way to pre-load objects from one model into another? With a ForeignKey the user has to add the boats each time. Any direction for me to research would be helpful.
Here is the simplified code so far;
class Yacht (models.Model):
yacht_classes = [('A', 'A'),('A1', 'A1'),]
yacht_type = [('J-29','J-29'),('J-24','J-24'),]
yacht_name = models.CharField(max_length=75)
yacht_type = models.CharField(max_length=25, choices=yacht_type,
default='J-29')
yacht_class = models.CharField(max_length=25, choices=yacht_classes)
skipper = models.ForeignKey(Skipper, on_delete=models.CASCADE)
def __str__(self):
return self.yacht_name
class Event (models.Model):
race_date = models.DateTimeField(default=timezone.now)
#yachts = #how to Include Yacht.objects.all() to the field?
class Results (models.Model):
pass
Thanks
Yes, u can use signals...
after objects is saved u can call post_save and add all yachts to race
more => https://docs.djangoproject.com/en/3.1/ref/signals/#post-save
but i dont think this is good way...
(not every time all the data must be present or must be saved => this save rows in database)
i recomment you to use m2M between race and ship with throught table where time is saved in table between.
then its on you how you present this problem to end-user.
with this solution you save only data which are needed.
this can be done with
https://docs.djangoproject.com/en/3.1/topics/db/models/#extra-fields-on-many-to-many-relationships

Django - model that has a count per CHOICES Field

django 2.1, python 3.6
Let's say I have a set of things ['house_1','house_2',...] and I want to have a model that keeps a count of each item. I'd imagine that it'd look like the following.
class Card(models.Model):
house_1_count = models.IntegerField(...
house_2_count = models.IntegerField(...
house_3_count = models.IntegerField(...
Is there a way to convert this model so that the items are not hard coded. Like by using a CHOICES field. The items in my list may change (slowly), but I don't want to have to create a field in the model every time it happens.
In your situation, I don't think it would be wise to store the count of houses in a model. If you want to get count, then simply do it like this using count():
House.objects.filter(house_type=1).count()
You can create a choice field in your model rather than storing each count.
Update you card model:
class Card(models.Model):
house = models.IntegerField(choices=list(zip(range(1, 4), range(1, 4))), max_length=1)
To count Card with particular type house use count():
Card.objects.filter(house=1).count()

Django: Getting last value by date from related model in admin. Best way?

Say I have a model like
class Product(models.Model):
name = models.CharField(max_length=64)
[...]
and another like
class Price(models.Model):
product = models.ForeignKey('Product')
date = models.DateField()
value = models.FloatField()
[...]
and I want to display products in a modelAdmin, with the last price registered in a column.
So far, the only way I have found is to add the following method to the product object:
#property
def last_price(self):
price = Price.objects.filter(product=self.pk).order_by("-date")
return price[0].value if price else None
and then adding last_price to the list_display in Product's ModelAdmin. I don't like this approach because it ends up doing a query for each row displayed.
Is there a better way to do this in code?. Or do I have to create a column in the Product table and cache the last price there?.
Thanks!
to reduce the the queries for each entry use the following:
Price.objects.filter(product=self.pk).order_by("-date").select_related('product')
this will decrease the product query at each object, hope it is helpful, vote up please
A cleaner version of what you have would be:
def last_price(self):
latest_price = self.price_set.latest('date')
return latest_price.value if latest_price else None
But this still involves queries for each item.
You if you want to avoid this I would suggest adding a latest_price column to Product. Then you could set up a post_save signal for Price that then updates the related Product latest_price (This could be a ForiegnKey or the value itself.)
Update
Here is a receiver that would update the products latest price value when you save a Price. Obviously this assumes that you are saving Price models in chronological order so the lastest one saved is the latest_value
#receiver(post_save, sender=Price)
def update_product_latest_value(sender, instance, created, **kwargs):
if created:
instance.product.latest_value = instance.value
instance.product.save()

Embed product-variance logic into Django models

I wonder how I would model my Products model to auto-create (and that the admin-App would also understand it) variants of a Product based on it's variant-parts.
My Products have;
Colors
Sizes
and can probably get more features in the future.
How would I model my Product class to generate all variants of the Product?
Say I would create a new Product in Colors Red Blue Green and in Sizes XS S M L XL.
class Product(models.Model):
name = models.CharField(max_length=200)
class Color(models.Model):
product = models.ForeignKey(Product)
name = models.CharField(max_length=200)
class Size(models.Model):
product = models.ForeignKey(Product)
name = models.CharField(max_length=200)
class FutureVariant(models.Model):
product = models.ForeignKey(Product)
name = models.CharField(max_length=200)
# etc.
Now when I would need a smart method that when I would auto-create all color-size-[FUTURE VARIANT] for that product.
So I would tell Django;
Create new Product
In the colors Red Blue Green
In the sizes XS S M L XL
And the Product class would go and produce Products with all possible combinations in the products_product table.
I'm almost sure that this has design flaws. But I'm just curious how to put this logic in the ORM, and not to write weird procedural code, which would probably go against the DRY principal.
In Database logic I would think of something like this;
PRODUCTS
- id
- name
PRODUCTS_VARIANTS_COLORS
- id
- name
- html_code
PRODUCTS_VARIANTS_SIZES
- id
- name
PRODUCTS_VARIANTS_TABLES
- table_name
- table_id
PRODUCTS_VARIANTS
- product_id
- variant_table
- variant_id
This way I could make endless variant tables, as long as I would register them in my PRODUCTS_VARIANTS_TABLES and store their name as relevant. PRODUCTS_VARIANTS would hold all the the variants of the product, including combinations of them all. I am also aiming to have a selection-phase where the user can chose (in a HTML checkbox-list) which variants it does and doesn't want.
The problem (I think) is that this would not really comply with a logic in the ORM.
I don't know if you are asking about alternatives or just looking to make your way work, but what about splitting a product from it's attributes?
So instead of having separate models for attributes, you just have an Attribute model. This way you are future-proofing your database so you can easily add more attributes (like if you have products with a height and width instead of just color or size).
class AttributeBase(models.Model):
label = models.CharField(max_length=255) # e.g. color, size, shape, etc.
...
class Attribute(models.Model):
base = models.ForeignKey('AttributeBase', related_name='attributes')
value = models.CharField(max_length=255) # e.g. red, L, round, etc.
internal_value = models.CharField(max_length=255, null=True, blank=True) # other values you may need e.g. #ff0000, etc.
...
class ProductAttribute(Attribute):
product = models.ForeignKey('Product', related_name='attributes')
It now becomes very easy to create all attributes for a product...
class Product(models.Model):
...
def add_all_attributes(self):
for attribute in Attribute.objects.all():
self.attributes.add(attribute)
now when you use product.add_all_attributes() that product will contain every attribute. AND you can even make it add attributes of a certain AttributeBase
def add_all_attributes_for_base(self, label):
base = AttributeBase.objects.get(label=label)
for attribute in base.attributes.all():
self.attributes.add(attribute)
You could write something as:
class Product(models.Model):
#classmethod
def create_variants(cls):
# compute all possible combinations
combinations = ...
for combination in combinations:
Product.objects.create(**combination)
Creating all the combinations would indeed happen through registering the possible variants and their possible values.
Note that ORM is there to help you map Django objects to database records, it doesn't help you with producing the database records (read: Django models) that you wish to save.