Django - Create model with fields derivable from other model - python

I have 2 Django models representing the coin domain.
The Coin has some properties and the trading Pair is based on those properties.
class Coin(models.Model):
code = models.CharField(max_length=8, primary_key=True)
name = models.CharField(max_length=32)
class Pair(models.Model):
code = models.CharField(max_length=16, primary_key=True)
name = models.CharField(max_length=64)
base_currency = models.ForeignKey(Coin, on_delete=models.CASCADE, null=False, related_name='base_currency')
quote_currency = models.ForeignKey(Coin, on_delete=models.CASCADE, null=False, related_name='quote_currency')
Let's add a couple of Coin instances:
first = Coin.objects.create(code="BTC", name="Bitcoin")
second = Coin.objects.create(code="USD", name="United States Dollar")
and one Pair:
Pair.objects.create(code="BTCUSD", name="Bitcoin / United States Dollar", base_currency=first, quote_currency=second)
As you can see, code and name in the Pair model can be derived from code and name in the Coin model.
To put it simple:
Pair Code = First Coin Code + Second Coin Code
Pair Name = First Coin Name + "/" + Second Coin Name
But, in this example I simply hardcoded those values and for sure this is not the best way to handle this situation.
For example: what if in the Coin model I need to change the name of an instance?
Then, I will have to manually update code and name in the Pair model, because this values are not properly binded from the Coin Model.
I believe Pair code/name must be binded/derived from the Coin model in some way.
Is there a way to do that in Django?

You might not need to store the name of your Pair since it can be infered from the references from Pair.base_currency and Pair.quote_currency.
A property on the Pair class should be enough:
class Pair(models.Model):
base_currency = models.ForeignKey(Coin, on_delete=models.CASCADE, null=False, related_name='base_currency')
quote_currency = models.ForeignKey(Coin, on_delete=models.CASCADE, null=False, related_name='quote_currency')
#property
def code(self) -> str:
return self.base_currency.code + self.quote_currency.code
#property
def name(self) -> str:
return f'{self.base_currency.name} / {self.quote_currency.name}'

Related

How to run a model's function with DTL?

I am fairly new to django and I am trying the following:
I am making an ordering web app for a nearby business. I am trying to add all the calories in a combo.
I have a model "Consumable", this represent the different food and drinks there are.
Here is the code for the "Consumable" Model:
class Consumable(models.Model):
name = models.CharField(max_length=80, unique=True)
category = models.ForeignKey(FoodCategory, null=True, on_delete=models.SET_NULL)
price= models.FloatField(default=0.00)
calories = models.IntegerField(blank=False)
image = models.ImageField(upload_to="images/Food/")
description = RichTextField(blank=True, max_length=500)
restaurant = models.ForeignKey(Place, on_delete=models.CASCADE)
added = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
Then, I have a model called "Meal" which has the following code:
class Meal(models.Model):
name = models.CharField(max_length=100)
image = models.ImageField(upload_to='images/photos/meals')
consumables = models.ManyToManyField(Consumable, related_name="consumable")
restaurant = models.ForeignKey(Place, on_delete=models.CASCADE)
price = models.FloatField()
def add_cals(meal_consumables):
total_calories = 0
for x in meal_consumables.values():
global total_calories += float(x.calories)
return total_calories
I am trying to call this model's function, add_cals from my HTML file using the DTL (Django Template Language).
For example, if you have a model stored with the variable x in your view, and it is in the view's context dictionary, you could simply call the model by using <p>{{x}}</p>, for example. And if the model has a variable x1, you could call it as <p>{{x.x1}}</p> and it works fine. However, if the x model from my example has a function
add_x(x):
return x
then it wouldn't work when you call it as <p>{{x.add_x(1)}}</p> for some reason. Could some wise individual out there in this world be so humble to share his or her knowledge with me in order to help me?
Thanks to everyone who tries.

How to create a subtraction in the inventory when a order is made? [Django] [Python] [E-commerce website]

I’m a python/django begginer. I decided to build a e-commerce website using django for an academic project. I’ve been able to develop enough of the project and build understanding of the subject, but right now I’m having issues finding a way to subtracts the number of items listed in the inventory whenever a order is made.
That’s the code for the models, evey product has it's own stock quantity call inventory:
class Product(models.Model):
name = models.CharField(max_length=200, null=True)
price = models.FloatField()
description = models.TextField(default='', null=True, blank=True)
digital = models.BooleanField(default=False,null=True, blank=True)
image = models.ImageField(null=True, blank=True)
inventory = models.IntegerField(default=0)
def __str__(self):
return self.name
def has_inventory(self):
return self.inventory > 0
This is the code I made to subtract base on quantity of the item ordered, but I can’t make it work, it won’t subtract the number of items from the inventory on the product stock.
class OrderItem(models.Model):
product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True)
order = models.ForeignKey(Order, on_delete=models.SET_NULL, null=True)
quantity = models.IntegerField(default=0, null=True, blank=True)
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.product) + " x " + str(self.quantity)
def inventory(self):
product.inventory = self.inventory
product.inventory -= int(self.quantity)
return inventory
What could I do to make it work?
All logic/action should be written under views.py file. You could create a function where it takes in a request, and when it does, it takes in all the value inputted through a form, and you could use filter to filter out the products you want to subtract its inventory and update query by Django to update the inventory.
It should look something like this inside your views function:
Product.objects.filter(name = name, description = description, digital = digital).update(Inventory = F('Inventory')-inventory)
Here is Django's documentation on queries: Django's Making Queries
I think there are a few problems with the snippet above.
First, the OrderItem.inventory is not referring the right value, it should be like the snippet below.
def inventory(self):
// remember the current stock is stored on Product.inventory
return self.product.inventory - self.quantity
Second, The method name should be remaining_stock not inventory to prevent misunderstanding.
def remaining_stock(self):
return self.product.inventory - self.quantity
Also, don't forget if you want to store inventory of the product please call the save method after successfully inserting the OrderItem.

Set the ForeignKey to value in field of self in Django 2.0 and Python

I'm perhaps a little confused as to how ForiegnKey and database relationships work. I have two classes, Coin contains a list of items coin names. CoinData rows of data, containing daily price data for each coin. I want each CoinData to be ForiegnKey tied to their matching item in Coin, and to do this I gave CoinData a 'coin' ForeignKey attribute to my Coin model but all this does is produce a field of 'Coin' options on each CoinData item.
I want to programmatically assign the value in coin_name, to the Coin object it matches with on each row of data. Am I going about this the right way, or am I doing things wrong?
class Coin(models.Model):
"""
A class defining all the coins we'll have on the website
"""
# Fields
name = models.CharField(max_length=30, unique=True, help_text="Enter coin name")
class CoinData(models.Model):
"""
A class defining the daily coin data
"""
# Fields
coin_name = models.CharField(max_length=30, null=True, default='empty')
coin = models.ForeignKey(Coin, on_delete=models.SET_NULL, null=True)
date = models.DateField(null=True, blank=True)
open_price = models.DecimalField(max_digits=30, decimal_places=10, null=True, help_text="Opening Price")
high_price = models.DecimalField(max_digits=30, decimal_places=10, null=True, help_text="High Price")
low_price = models.DecimalField(max_digits=30, decimal_places=10, null=True, help_text="Low Price")
close_price = models.DecimalField(max_digits=30, decimal_places=10, null=True, help_text="Low Price")
volume = models.DecimalField(max_digits=30, decimal_places=10, null=True, help_text="Volume")
market_cap = models.DecimalField(max_digits=30, decimal_places=10, null=True, help_text="Market Cap")
So based on your comment, I understand that you have CoinData and Coin that are related through their name field, and you would like to link them with a foreign key instead. Let say you started wrong and want to correct this for future use.
What you already done to fix this:
You added the foreign key field named coin in CoinData model to reference a Coin model instance.
What I would suggest to finish fixing this is:
Write a script (or run a few commands in a Python shell) to automatically update all CoinData instances to reference their related Coin instances, given their respective name field:
for coin_data in CoinData.objects.all():
try:
related_coin = Coin.objects.get(name=coin_data.name)
coin_data.coin = related_coin
coin_data.save()
except Coin.DoesNotExist:
print('no related Coin instance for %s' % coin_data)
Add instructions for when a CoinData instance is created to reference it's related Coin instance (so you don't have to do it later, and you can make sure every CoinData is linked to a Coin): coin_data = CoinData.objects.create(coin=related_coin, ...)
Remove the name field from CoinData as it is redundant with the name in Coin model.
If you simply want to say "this specific Coin Data refers to this specific Coin", you would reference the Coin data to the Coin using a foreign key. If you want to get, for example, the associated Coin Name for a Coin Data, you could use
coin_data = CoinData.objects.get(pk=1) #example
coin_name = coin_data.coin.name
You would need a name field on your CoinData model if a CoinData instance must have a specific name.

Reference multiple foreign keys in Django Model

I'm making a program that helps log missions in a game. In each of these missions I would like to be able to select a number of astronauts that will go along with it out of the astronauts table. This is fine when I only need one, but how could I approach multiple foreign keys in a field?
I currently use a 'binary' string that specifies which astronauts are to be associated with the mission (1 refers to Jeb, but not Bill, Bob, or Val and 0001 means only Val), with the first digit specifying the astronaut with id 1 and so forth. This works, but it feels quite clunky.
Here's the model.py for the two tables in question.
class astronauts(models.Model):
name = models.CharField(max_length=200)
adddate = models.IntegerField(default=0)
experience = models.IntegerField(default=0)
career = models.CharField(max_length=9, blank=True, null=True)
alive = models.BooleanField(default=True)
def __str__(self):
return self.name
class Meta:
verbose_name_plural = "Kerbals"
class missions(models.Model):
# mission details
programid = models.ForeignKey(programs, on_delete=models.SET("Unknown"))
missionid = models.IntegerField(default=0)
status = models.ForeignKey(
missionstatuses, on_delete=models.SET("Unknown"))
plan = models.CharField(max_length=1000)
# launch
launchdate = models.IntegerField(default=0)
crewmembers = models.IntegerField(default=0)
# recovery
summary = models.CharField(max_length=1000, blank=True)
recdate = models.IntegerField(default=0)
def __str__(self):
return str(self.programid) + '-' + str(self.missionid)
class Meta:
verbose_name_plural = "Missions"
I saw a post about an 'intermediate linking table' to store the crew list but that also isn't ideal.
Thanks!
This is the use case for Django's ManyToManyField. Change the appropriate field on the missions:
class missions(models.Model):
crewmembers = models.ManyToManyField('astronauts')
You can access this from the Astronaut model side like so:
jeb = astronaut.objects.get(name='Jebediah Kerman')
crewed_missions = jeb.missions_set.all()
Or from the mission side like so:
mission = missions.objects.order_by('?')[0]
crew = mission.crewmembers.all()
This creates another table in the database, in case that is somehow a problem for you.

django querying from 3 models

My models are :
model 1:
class source_of_enquiry(models.Model):
source_of_enquiry = models.CharField(max_length=200, null=True, blank=True)
def __unicode__(self):
return '%s' % self.source_of_enquiry
model 2:
class customers(models.Model):
cutomer_name = models.CharField(max_lentgth=200)
customer_src_n_type = models.Foreign_key(source_of_enquiry)
customer_contact = models.CharField(max_lentgth=200)
def __unicode__(self):
return '%s' % self.customer_name
model 3:
class sales_cycle(models.Model):
item_name = models.CharField(max_length=200)
customer_name = models.Foreignkey(customers)
def __unicode__(self):
return '%s' % self.item_name
how should i know how many sales had peen completed based on source of enquiry??
tried many from `select_related' and 'prefetch_selected' , but all were kaput.
First of all - python naming convention state that classes should not have underscores and prefer upper-case letters instead. So your models should be SourceEnquiry, Customer (not plural) and SaleCycle.
That being said, let's say I have a SourceEnquiry item (I'm going to pick one arbitrarily), and you want all related SaleCycle items, you do it like so:
>>> sinq = SourceEnquiry.objects.get(pk=1)
>>> SaleCycle.objects.all().filter(customer_name__customer_src_n_type=sinq)
p.s.
also, going back to the naming convention thing, it's redundant to use customer as part of a field name inside the class Customer. You alread know it's a customer object, so it's better to name it like so:
class Customer(models.Model):
name = models.CharField(max_lentgth=200)
src_n_type = models.Foreign_key(source_of_enquiry)
contact = models.CharField(max_lentgth=200)
You other fields can also be cleaner:
class SourceEnquiry(models.Model):
value = models.CharField(max_length=200, null=True, blank=True)
class SaleCycle(models.Model):
item = models.CharField(max_length=200)
customer = models.Foreignkey(Customer)

Categories