Make model field equal concatenation of two fields in Django - python

I have two models and want to create a field for the second class that is a concatenation of a foreign field and a field within the model.
The code I have so far is:
class Drug(models.Model):
drug_name = models.CharField("Drug Name", max_length=200)
reference_title = models.CharField("Publication Title",max_length=1024)
pub_date = models.DateField("Pubication Date",'date published')
pubmed_link = models.CharField("PubMed Link", max_length=300)
class Risk(models.Model):
drug_link = models.ForeignKey(Drug, on_delete=models.CASCADE)
dosage = models.IntegerField(default=0)
independent_risk = models.DecimalField("Individual Risk", max_digits=4, decimal_places=2)
I want to add a new field to the Risk model that is automatically populated by a concatenation of the selected value for drug_link and the entered value for dosage.

This can be accomplished by a python property on the class:
class Risk(models.Model):
drug_link = models.ForeignKey(Drug, on_delete=models.CASCADE)
dosage = models.IntegerField(default=0)
independent_risk = models.DecimalField("Individual Risk", max_digits=4, decimal_places=2)
#property
def name_dosage(self):
return "%s - %s" % ( self.drug_link.drug_name, self.dosage )

If you do not need to store this value in database but rather use it in templates, you would not need to create extra fields. You can use methods like this:
class Risk(models.Model):
drug_link = models.ForeignKey(Drug, on_delete=models.CASCADE)
dosage = models.IntegerField(default=0)
independent_risk = models.DecimalField("Individual Risk", max_digits=4, decimal_places=2)
def dosages(self):
return "{} - {}".format(self.drug_link.drug_name, self.dosage)
And in the templates, you can just do:
{% for risk in risks %}
{{ risk.dosage }}
{% endfor %}

Related

How to print data in template django of a diffrent table joined by foreign key?

Hello Everyone i have Two model first one is as following:
class Item(models.Model):
title = models.CharField(max_length=100)
price = models.FloatField()
bargainprice = models.FloatField(default=0)
discount_price = models.FloatField(blank=True, null=True)
category = models.CharField(choices=CATEGORY_CHOICES, max_length=2)
label = models.CharField(choices=LABEL_CHOICES, max_length=1)
slug = models.SlugField()
description = models.TextField()
image = models.ImageField()
and i am getting this model data using the following view:
class ItemDetailView(DetailView):
model = Item
template_name = "product.html"
and in product.html i am accessing Item objects like this:
<span class="mr-1">
<del>₹ {{ object.price }}</del>
</span>
<span>₹ {{ object.discount_price }}</span>
{% else %}
<span> ₹ <span id="pp">{{ object.price }}</span></span>
and so on..
everything working fine up here. but problem arises when i created the following model:
class BargainModel(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
itemId = models.IntegerField()
bprice = models.FloatField()
i joined this with foreign key as mentioned.
**what i want to do is print the " bprice " in the product.html of the same user but i am not able to do it **
can anyone help me with this i am new to Django.
Thanks in advance
in this case you need to import User like
from django.contrib.auth.models import User
class BargainModel(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
itemId = models.ForeignKey(Item, on_delete=models.CASCADE)
bprice = models.FloatField()
in product.html you can call the model of BargainModel it also contains the Item with user
It is better to work with a ForeignKey since this will guarantee referential integrity. You thus shoudl define the BargainModel as:
from django.conf import settings
class Bargain(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE
)
item = models.ForeignKey(
Item,
on_delete=models.CASCADE
)
bprice = models.FloatField()
class Meta:
constraints = [
models.UniqueConstraint(fields=['item', 'user'], name='unique_user_item')
]
In the DetailView, we can then look if there is a Bargain record for the given item and user with:
class ItemDetailView(DetailView):
model = Item
template_name = "product.html"
def get_bargain(self):
if self.request.user.is_authenticated():
return Bargain.objects.filter(item=self.object, user=request.user).first()
Then you can render this with:
{{ view.get_bargain.bprice }}
if there is a related Bargain, then it will show the corresponding bprice.
Note: Models normally have no Model suffix. Therefore it might be better to rename BargainModel to Bargain.

How to handle a legacy database in the Django framework

I'm working on an Django app that needs to access a very large (MySQL) database, the db has no foreign keys whatsoever. I need to do queries on multiple tables. The way I'm doing it is VERY inefficient and involves doing multiple loops:
{% for flower in especies_id %}
<td>{{flower.especies}}</td>
{% for family in family_id %}
{% if family.family_id == flower.family_id %}
<td><a class="nav-item active" href="/home">
{{family.family_name}}</td></a>
{% endif %}
{% endfor %}
{% endfor %}
Is there a way to handle this db with the Django shell maybe JavaScript? Or refactor the db entirely?
(edit):
the db has ~3000 entries
relationship between two tables are made using an additional one:
flower2estate which contains estate_id, flower_id
Models.py:
class Listflower(models.Model):
especies_id = models.AutoField(primary_key=True)
family_id = models.IntegerField(blank=True, null=True)
especies = models.CharField(max_length=255, blank=True, null=True)
class Meta:
managed = False
db_table = 'listflower'
class Estate(models.Model):
estate_id = models.AutoField(primary_key=True)
estate_name = models.CharField(max_length=100, blank=True, null=True)
class Meta:
managed = False
db_table = 'estates'
class Flower2Estate(models.Model):
estate_id = models.IntegerField(primary_key=True)
especies_id = models.IntegerField()
class Meta:
managed = False
db_table = 'flower2estate'
unique_together = (('estado_id', 'especie_id'),)
Views.py:
def flowers(request):
list_flower = ListFlower.objects.all().order_by('especies_id')
paginator = Paginator(list_flower, 3)
page = request.GET.get("page")
try:
flowers = paginator.page(page)
except PageNotAnInteger:
flowers = paginator.page(1)
except EmptyPage:
flowers= paginator.page(paginator.num_pages)
return render(request, 'accounts/flowers.html', {'page':page,"flowers"
:flowers,"especies_id":flowers})
I need to get the "flower" and the corresponding "estate" without the need to loop between 3000 entries.
You can add some methods to legacy models to retrieve related items a bit more efficiently:
class Listflower(models.Model):
especies_id = models.AutoField(primary_key=True)
family_id = models.IntegerField(blank=True, null=True)
especies = models.CharField(max_length=255, blank=True, null=True)
class Meta:
managed = False
db_table = 'listflower'
def get_family(self):
return FamilyModel.objects.get(family_id=self.family_id)
class Estate(models.Model):
estate_id = models.AutoField(primary_key=True)
estate_name = models.CharField(max_length=100, blank=True, null=True)
class Meta:
managed = False
db_table = 'estates'
def get_flowers(self):
flower_ids = Flower2Estate.objects.filter(estate_id=self.estate_id).values_list('especies_id', flat=True)
return Listflower.objects.filter(especies_id__in=flower_ids)
But if it is not the last time you work with this data probably the better way is to define regular django models with fks and write once a script to convert legacy data to a new model structure. The challenge shouldn't take more than an hour.
UPDATE
class FlowerFamily(models.Model):
# assuming you old family model has
# "family_id" and "family_name" fields
family_id = models.IntegerField(blank=True, null=True)
family_name = models.CharField(max_length=255, blank=True, null=True)
class Flower(models.Model):
# you might want preserve old model fields in the new model
# at least id fields
especies_id = models.IntegerField(blank=True, null=True)
family_id = models.IntegerField(blank=True, null=True)
especies = models.CharField(max_length=255, blank=True, null=True)
family = models.ForegnKey(FlowerFamily, related_name='flowers')
class NewEstate(models.Model):
estate_id = models.IntegerField(blank=True, null=True)
estate_name = models.CharField(max_length=100, blank=True, null=True)
flowers = models.ManyToManyField(Flower, related_name='estates')
# this is a slightly primitive example
# in real life you might want to use get_or_create instead of direct creation
# in case script fails and you'll need to run it again
# also objects.get() might better be used with try-except ObjectDoesNotExist
def convert_legacy():
# create new instances
for ff in YourOldFamilyModel.objects.all():
new_ff = FlowerFamily(family_id=ff.family_id, family_name=ff.family_name)
new_ff.save()
for fl in Listflower.objects.all():
new_fl = Flower(...)
family = FlowerFamily.objects.get(family_id=fl.family_id)
new_fl.family = family
new_fl.save()
# same thing for Estate
for ...:
new_estate ...
new_estate.save()
# and restore relations
flower_ids = Flower2Estate.objects.filter(estate_id=new_estate.estate_id).values_list('especies_id', flat=True)
for new_lf in Flower.objects.filter(especies_id__in=flower_ids):
new_estate.flowers.add(new_fl)

values_list() in query_set is showing only numbers but not the names of countries

I selected my field with 'values_list' which contains name of countries. But what I get is country_id numbers.
I already used flat=True but it did not help any.
my models.py:
class Report(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
church_name = models.CharField(max_length=255)
area = models.ForeignKey(Area, on_delete=models.CASCADE, null=True, blank=True)
country = models.ForeignKey(Country, on_delete=models.CASCADE, null=True, blank=True)
water_baptism = models.IntegerField(default=0)
holy_ghost = models.IntegerField(default=0)
def __str__(self):
return '%s' % self.area
def get_absolute_url(self):
return reverse('users:report_view')
my views.py:
def report_cities(request, pk):
countries = Report.objects.values_list('country', flat=True)
context = {
'countries':countries
}
return render(request, 'users/report_countries.html', context)
my html
<h1>Report Countries</h1>
{% for country in countries %}
{{country}}
{% endfor %}
Use Report.objects.values_list('country__name', flat=True) (assuming that is the country name field on the country model). By default django will list the object id if no field is specified.
E.G if your country model was
class Country(models.Model):
name = Charfield()
another_field = ...
The above query would now return a list of the names.

Model defines __str__, how can I access the primary_key value?

I'm doing a web app using django and jinja2.In my models.py my class defines the __str__ function, to return a friendly text when referring to the objects of that class.
class MySystem (models.Model):
system_id = models.AutoField(primary_key=True),
system_name = models.CharField(max_length=100)
parent_system = models.ForeignKey('self', null=True, blank=True, on_delete=models.SET_NULL)
def __str__(self):
return "{} > {}".format(self.parent_system, self.system_name)
class Detail (models.Model):
detail_id = models.AutoField(primary_key=True)
system_id = models.ForeignKey(MySystem, on_delete=models.DO_NOTHING)
title = models.CharField(max_length=150)
def __str__(self):
return "{} > {}".format(self.system_id, self.title)
I have a Detail object, and I want the ID of its system. When I try to access the primary key, it returns the string instead of the ID.
<td> <a href="/base/system/{{detail.system_id}}" > {{ detail.system_id.system_name }} </a> </td>
I tried detail.system_id.system_id and it returns django.db.models.fields.AutoField. I want it to return the numeric ID for the link.
Ok, I found my solution. What I need to do is detail.system_id.id.

How to display a dropdown field __str__ in Django templates?

I've got a ModelForm where I can display either a foreignkey field which comes as a dropdown list ({{ form.auto_part }}) or the value or the ID of that foreignkey field which comes as a number ({{ form.auto_part.value }}). But I want to show the __str__ value of the foreignkey field. How can I do that?
forms.py
class AddCostPriceForm(forms.ModelForm):
class Meta:
model = Product
fields = ['auto_part', 'cost_price']
models.py
class Product(Timestamped):
product_list = models.ForeignKey(List)
auto_part = models.ForeignKey(AutoPart)
quantity = models.SmallIntegerField()
unit = models.CharField(max_length=20, default='pcs')
cost_price = models.IntegerField(blank=True, null=True)
class AutoPart(Timestamped):
brand = models.ForeignKey(Brand)
auto_type = models.ForeignKey(AutoType)
part_no = models.CharField(max_length=50)
description = models.CharField(max_length=255)
def __str__(self):
return "{brand} {auto_type} - {part_no}".format(brand=self.brand, auto_type=self.auto_type, part_no=self.part_no)
Using ModelChoiceField should allow you to do this, it is the default behavior. You can configure the labels.
See https://docs.djangoproject.com/en/1.10/ref/forms/fields/#modelchoicefield
Example:
class AddCostPriceForm(forms.ModelForm):
auto_part = forms.ModelChoiceField(queryset=AutoPart.objects.all())
class Meta:
model = Product
fields = ['auto_part', 'cost_price']

Categories