I am a novice programmer, I am learning python and Django on my own. I got stuck in a part of my application:
I have many models with many attributes, and I have a window and a template for each of them.
The idea is to show in each one, a table with all its content with an sql query in the file view.py
objects.all ()
My code:
MODELS.PY
from django.db import models
class MFuel(models.Model):
marca = models.TextField(db_column='Marca', blank=True, null=True) # Field name made lowercase.
modelo = models.TextField(db_column='Modelo', blank=True, null=True) # Field name made lowercase.
potencia_electrica_kw = models.BigIntegerField(db_column='Potencia_electrica_kW', blank=True, null=True) # Field name made lowercase.
fecha_oferta = models.DateTimeField(db_column='Fecha_oferta', blank=True, null=True) # Field name made lowercase.
pais_proyecto = models.TextField(db_column='Pais_Proyecto', blank=True, null=True) # Field name made lowercase.
proyecto = models.TextField(db_column='Proyecto', blank=True, null=True) # Field name made lowercase.
uds = models.FloatField(db_column='Uds', blank=True, null=True) # Field name made lowercase.
precio_eur = models.FloatField(db_column='Precio_EUR', blank=True, null=True) # Field name made lowercase.
precio_usd = models.FloatField(db_column='Precio_USD', blank=True, null=True) # Field name made lowercase.
precio_unitario_eur = models.FloatField(db_column='Precio_Unitario_EUR', blank=True, null=True) # Field name made lowercase.
ratio_eur_kw = models.FloatField(db_column='Ratio_eur_KW', blank=True, null=True) # Field name made lowercase.
largo_mm = models.FloatField(db_column='Largo_mm', blank=True, null=True) # Field name made lowercase.
ancho_mm = models.FloatField(db_column='Ancho_mm', blank=True, null=True) # Field name made lowercase.
alto_mm = models.FloatField(db_column='Alto_mm', blank=True, null=True) # Field name made lowercase.
peso_kg = models.FloatField(db_column='Peso_kg', blank=True, null=True) # Field name made lowercase.
presupuesto = models.TextField(db_column='Presupuesto', blank=True, null=True) # Field name made lowercase.
esp_tecnicas = models.TextField(db_column='Esp_Tecnicas', blank=True, null=True) # Field name made lowercase.
observaciones = models.FloatField(db_column='OBSERVACIONES', blank=True, null=True) # Field name made lowercase.
class Meta:
managed = False
db_table = 'm_fuel'
VIEWS.PY
def m_fuel(request):
fuel = MFuel.objects.all()
# QuerySet
myFilter = Filter(request.GET, queryset=fuel)
fuel = myFilter.qs
total = fuel.count()
attr = MFuel.__doc__
inici = attr.index("(") + 1
fi = attr.index(")")
nom_columnes = attr[inici:fi]
nom_columnes = str(nom_columnes)
nom_columnes = nom_columnes.split(",")
dict = {
"fuel": fuel,
"filter": myFilter,
"motores": motores_list,
"total": total,
"nom_columnes": nom_columnes,
}
return render(request, "motores/fuel.html", dict)
TEMPLATE.HTML
<table class="table_info">
<tr>
{% for nom in nom_columnes %}
<th>{{nom}}</th>
{% endfor %}
</tr>
{% for i in fuel %}
<tr>
<td>{{i.id}}</td>
<td>{{i.marca}}</td>
<td>{{i.modelo}}</td>
<td>{{i.potencia_electrica_kw}}</td>
<td>{{i.fecha_oferta}}</td>
<td>{{i.pais_proyecto}}</td>
<td>{{i.proyecto}}</td>
<td>{{i.uds}}</td>
<td>{{i.precio_eur}}</td>
<td>{{i.largo_mm}}</td>
<td>{{i.ancho_mm}}</td>
<td>{{i.alto_mm}}</td>
<td>{{i.peso_kg}}</td>
<td>{{i.presupuesto}}</td>
</tr>
{% endfor %}
</table>
My idea is to automate the table columns by accessing all the attributes of the class.
I tried pulling out a list of the attribute names
attr = MFuel .__ doc__
and print them as follows:
<table class="table_info">
<tr>
{% for nom in nom_columnes %}
<th>{{nom}}</th>
{% endfor %}
</tr>
{% for i in fuel %}
<tr>
{% for nom in nom_columnes %}
<td>{{i.nom}}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
but this shows nothing:
capture that this code shows
It seems that it does not recognize the name as an attribute of the class, it must be because it is a string?
I saw this question, but I don't understand it
Django - print all objects attribute values
Any help to automate this? Thanks a lot
I have been able to solve my problem, I share it in case someone needs it
This returns a list of all the values available:
fuel = fuel.values()
and print them:
<table class="table_info">
<tr>
{% for nom in nom_columnes %}
<th>{{nom}}</th>
{% endfor %}
</tr>
{% for i in fuel %}
<tr>
{% for key, value in i.items %}
<td>{{value}}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
And all ok
Related
I'm trying to render a template with a list of participants (adult and minor) and their latest checkin and checkout times.
There are two types of participants and they are represented in two tables/models: AdultParticipant and MinorParticipant. MinorParticipants have a foreign key relationship to the ParentParticipant.
Checkin information (checkin and checkout) is stored in a single table irregardless of whether the checkin data refers to AdultParticipant or the MinorParticipant. One record in this table captures the participant reference and the checkin and checkout times.
Any participant can have many checkins. A checkin record can only have one participant.
The code as it exists now does everything I want except it displays every checkin record for the participant. I only want to display the last (most recent) record for the participant.
How can I construct the queryset to include the participant information and include only the last checkin record for the participant?
Thank you in advance. You are appreciated.
Models
class AdultParticipant(models.Model):
first_name = models.CharField(max_length=50)
middle_initial = models.CharField(max_length=50, blank=True)
class MinorParticipant(models.Model):
first_name = models.CharField(max_length=50)
middle_initial = models.CharField(max_length=50, blank=True)
parent = models.ForeignKey(
WaiverAdult, on_delete=models.CASCADE, related_name='minor_of_adult')
class CheckIn(models.Model):
adult = models.ForeignKey(
AdultParticipant, on_delete=models.CASCADE, blank=True, null=True, related_name='adult_checkin')
minor = models.ForeignKey(
MinorParticipant, on_delete=models.CASCADE, blank=True, null=True, related_name='minor_checkin')
checkin = models.DateTimeField(blank=True, null=True)
checkout = models.DateTimeField(blank=True, null=True)
View
class WaiverListView(ListView):
participants_and_checkins = AdultParticipant.objects.all().order_by('created')
queryset = participants_and_checkins
context_object_name = "the_list"
template_name = 'list.html'
Template
{% for adult in the_list %}
<tr>
<td class="fs-6">
{% for c in adult.adult_checkin.all|dictsortreversed:"checkin" %}
In: {{ c.checkin }}</br>
Out: {{c.checkout}}</br>
{% endfor %}
</td>
<td>{{adult.last_name}}</td>
<td>{{adult.first_name}}</td>
</tr>
{% for child in adult.minor_of_adult.all %}
<tr>
<td class="fs-6">
{% for c in child.minor_checkin.all|dictsortreversed:"checkin" %}
In: {{ c.checkin }}</br>
Out: {{c.checkout}}
{% endfor %}
</td>
<td>{{child.last_name}}</td>
<td>{{child.first_name}}</td>
</tr>
{% endfor %}
{% endfor %}
in your template change checkin.all to checkin.last.
Also you can get rid of the for loop as well,like
In: {{ child.minor_checkin.last.checkin }}</br>
Out: {{child.minor_checkin.last.checkout}}
I have a working solution but I would like to know if this is the best way to do it.
I have three models: Meal, Indgredient and IngredientWithQuantity (IwQ). Meal can have multiple IwQ and Ingredient can have multiple IwQ.
I created a simple view where you can create Meal (one form), add IwQ (another form) and if needed go to another view to create new Ingredient (yet another form) and then come back to this view where you still will edit the previous Meal.
The only problem is keeping the information about the meal that is being created.
I am doing this through html hidden input field where I store an information about meal_id.
I am simply not sure if this is the best way to exchange this information, because at times it seems a little off.
Could some take a look and tell me if maybe this could be achieved in a more effective manner?
Thanks,
models.py
class Ingredient(models.Model):
name = models.CharField(max_length=200, null=True)
#brand
#WW
def __str__(self):
return self.name
class Meal(models.Model):
EVALUATION = (
('Perfect', 'Perfect'),
('Average', 'Average'),
('Bad', 'Bad')
)
name = models.CharField(max_length=200, null=True)
time_eaten = models.DateTimeField(auto_now=False, auto_now_add=False, default=timezone.now, null=True)
# time_of_day = jaki posiłek?
bolus_n = models.DecimalField(max_digits=2, decimal_places=1, default=0, null=True)
bolus_s = models.DecimalField(max_digits=2, decimal_places=1, default=0, null=True, blank=True)
bolus_s_duration = models.DecimalField(max_digits=3, decimal_places=2, default=0, null=True, blank=True)
interval = models.IntegerField(null=True, default=0)
prev_bolus_n = models.DecimalField(max_digits=2, decimal_places=1, default=0, null=True, blank=True)
prev_bolus_s = models.DecimalField(max_digits=2, decimal_places=1, default=0, null=True, blank=True)
prev_bolus_s_duration = models.DecimalField(max_digits=3, decimal_places=2, default=0, null=True, blank=True)
prev_bolus_time = models.DateTimeField(auto_now=False, auto_now_add=False, default=timezone.now, null=True)
evalution = models.CharField(max_length=200, null=True, choices=EVALUATION)
notes = models.CharField(max_length=1500, null=True)
#recipe = models.ForeignKey(Recipe, null=True, on_delete=models.SET_NULL)
class IngredientWithQuantity(models.Model):
UNITS = (
('g', 'g'),
('spoon', 'spoon'),
('cup', 'cup'),
)
ingredient = models.ForeignKey(Ingredient, null=True, on_delete=models.SET_NULL)
quantity = models.IntegerField(null=True)
unit = models.CharField(max_length=10, choices=UNITS, null=True, blank=True)
meal = models.ForeignKey(Meal, null=True, on_delete=models.CASCADE)
#recipe = models.ForeignKey(Recipe, null=True, on_delete=models.CASCADE)
def __str__(self):
caption = str(self.quantity) + ' ' + str(self.unit) + ' ' + self.ingredient.name
return caption
views.py:
def createMeal2(request):
print(request.POST)
if 'meal_id' not in request.POST or request.POST['meal_id'] == '':
meal = Meal()
meal.save()
meal_id = meal.id
else:
meal_id = request.POST['meal_id']
meal = Meal.objects.get(id=meal_id)
if 'meal_form' in request.POST:
meal_form = MealForm(request.POST, instance=meal)
if meal_form.is_valid():
meal_form.save()
return redirect('/boot/')
iwq = IngredientWithQuantity(meal = meal)
meal_form = MealForm(instance=meal)
if 'ingredient_form' in request.POST:
ing_form = IngredientForm(request.POST)
if ing_form.is_valid():
ing_form.save()
iwq.ingredient = Ingredient.objects.get(name=request.POST['name'])
if request.method == 'POST' and 'iwq_form' in request.POST:
iwq_form = IwQForm(request.POST, instance=iwq)
if iwq_form.is_valid():
iwq_form.save()
else:
iwq_form = IwQForm(instance=iwq)
context = {'iwq_form':iwq_form, 'meal':meal, 'meal_id':meal_id, 'meal_form':meal_form}
return render(request, 'meals/create_meal2.html', context)
template:
{% extends 'meals/main.html' %}
{% load static %}
{% block content %}
<hr>
<h2>Meal: {{meal.name}}
<hr>
<h2>Ingredients2</h2>
<form action="/create_ingredient/" method="POST">
{% csrf_token %}
<input type = "hidden" name="meal_id" value={{meal_id}}>
<input type ="submit" class="btn btn-primary" name="add_ingredient" value="Dodaj składnik">
</form>
<br>
<form method="POST">
{% csrf_token %}
<table border="1">
{% for field in iwq_form.visible_fields %}
<tr>
<th>{{ field.label_tag }}</th>
<td>
{{ field.errors }}
{{ field }}
{{ field.help_text }}
</td>
<td>
</td>
</tr>
</tr>
{% endfor %}
</table>
<input type="submit" value = "Dodaj składnik" name="iwq_form">
<input type="hidden" name="meal_id" value={{meal.id}}>
</form>
<h2>Ingredients</h2>
{% for i in meal.ingredientwithquantity_set.all %}
{{i}} <br>
{% endfor %}
<hr>
<form action="." method="POST">
{% csrf_token %}
{{meal_form.as_p}}
<input type="hidden" name="meal_id" value={{meal.id}}>
<input type ="submit" class="btn btn-primary" name="meal_form" value="Zapisz posiłek">
{% endblock %}
For this task I think you can use formtools. It divides the forms into multiple pages and user get to fill them with step by step method. You can skip certain forms depending on answers the user gave beforehand etc. It is very useful and at the end you get the entire data for all the forms. You can also get data for a specific step at a certain point. Here is the link to an article: https://swapps.com/blog/how-to-do-a-wizard-form/
Also here is the documentation link: https://django-formtools.readthedocs.io/en/latest/wizard.html
Im making a django app, and its basically an admin site, i have an app called calculator, inisde it i have 3 models Transaction, FamilyGroup and FamilyMember, each model has some property methods for calculation purposes. here are the models for more clearness :
class Transaction(models.Model):
chp_reference = models.CharField(max_length=50, unique=True)
rent_effective_date = models.DateField(null=True, blank=True)
income_period = models.CharField(max_length=11)
property_market_rent = models.DecimalField(max_digits=7)
#property
def ftb_combined(self):
ftb_combined = 0
for family_group in self.familygroup_set.all():
ftb_combined += family_group.ftb_combined
return ftb_combined
class FamilyGroup(models.Model):
name = models.CharField(max_length=10)
transaction = models.ForeignKey(Transaction, on_delete=models.CASCADE)
last_rent = models.DecimalField(max_digits=7)
#property
def additional_child_combined(self):
return (self.number_of_additional_children
or 0) * self.maintenance_rate_additional_child
class FamilyMember(models.Model):
transaction = models.ForeignKey(Transaction, on_delete=models.CASCADE)
family_group = models.ForeignKey(FamilyGroup, on_delete=models.CASCADE, null=True, blank=True)
name = models.CharField(max_length=100, null=True, blank=True)
date_of_birth = models.DateField(null=True, blank=True)
income = models.DecimalField(max_digits=6)
#property
def weekly_income(self):
if self.transaction.income_period == 'Weekly':
return self.income
return (self.income or 0) / 2
this is how my models are connected, now i made a method in views.py as below:
def transaction_print(request, transaction_id):
transaction = Transaction.objects.get(id=transaction_id)
return render(request, 'report.html', {'transaction':transaction})
I want to make a report in report.html, 1 report for each transaction, and the transaction can have many FamilyGroups and FamilyMember, and will include almost all the data from the models and the property methods inside it.
here what i thought in the report.html
<table class="table">
<thead class="thead-dark">
<tr>
<th>CHP Reference </th>
<th>Rent Effective From (dd/mm/yyyy)</th>
<th>CRA Fortnightly Rates valid for 6 months from</th>
<th>Market Rent of the Property </th>
<th>Number of Family Groups </th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ transaction.chp_reference }} </td>
<td>{{ transaction.rent_effective_date }} </td>
<td>0</td>
<td>{{ transaction.property_market_rent }}</td>
<td>{{ transaction.number_of_family_group }}</td>
</tr>
</tbody>
{% for family_group in transaction.family_group_set.all %} ??
{% for m in family_group.transaction.family_group_set.all %} ??
</table>
Im really not sure how to perform the nested loop to iterate through the FamilyGroup and FamilyMember inside the transaction report.html would appreciate a hint how this be done.
According to the documentation Django sets the name to MODELNAME_set. However you can still use the related_name property to set a name for your backward reference (you will still be able to use MODELNAME_set as well).
Here's how to achieve it using related_name:
models.py
class FamilyGroup(models.Model):
name = models.CharField(max_length=10)
transaction = models.ForeignKey(Transaction, on_delete=models.CASCADE, related_name="family_groups") # Notice the related_name here as it will be used later on
last_rent = models.DecimalField(max_digits=7)
# ...
class FamilyMember(models.Model):
transaction = models.ForeignKey(Transaction, on_delete=models.CASCADE, related_name="family_members") # Notice the related_name
family_group = models.ForeignKey(FamilyGroup, on_delete=models.CASCADE, null=True, blank=True)
name = models.CharField(max_length=100, null=True, blank=True)
date_of_birth = models.DateField(null=True, blank=True)
income = models.DecimalField(max_digits=6)
# ...
Now you can loop through them like so:
report.html
{% for family_group in transaction.family_groups.all %}
{{ family_group.name }}
{% endfor %}
{% for family_member in transaction.family_members.all %}
{{ family_member.name }}
{% endfor %}
I want my template to render object with specific attribute (products with specific category).
I am trying following code but it doesn't work.
May you please suggest how to write it correctly?
Template that I am trying make to work:
{% for instance in object_list %}
{% if instance.category == 'Statues' %}
{% endif %}
{% endfor %}
my models.py
class Category(models.Model):
categoryname = models.CharField(max_length=20)
description = models.CharField(max_length=200, blank=True, null=True)
#To make in name, not objXXX
def __str__(self):
return self.categoryname
class Product(models.Model):
name = models.CharField(max_length=20)
image = models.ImageField(upload_to='static/photos', default='http://placehold.it/700x400')
description = models.TextField(max_length=200, blank=True, null=True)
price = models.DecimalField(decimal_places=2, max_digits=10)
category = models.ForeignKey(Category, on_delete=models.PROTECT, blank=True, null=True)
#To make in name, not objXXX
def __str__(self):
return self.name
You need to use the field on the object;
{% for instance in object_list %}
{% if instance.category.categoryname == 'Statues' %}
{{ instance }}
{% endif %}
{% endfor %}
It won't work as a comparison against the string representation of the object.
I have three main models, Picture, Place and PlaceRating:
class Picture(models.Model):
file = ImageField(max_length=500, upload_to="images")
user = models.ForeignKey(User, null=True, related_name="userpictures")
place = models.ForeignKey(Place, null=True, related_name='pictures')
class PlaceRating(models.Model):
place = models.ForeignKey(Place, null=True, related_name="placeratings")
user = models.ForeignKey(User, null=True, related_name="userratings")
rating = models.DecimalField(null=True, max_digits=4, decimal_places=1)
class Place(models.Model):
name = CharField(max_length=50)
I would like to display the place's rating given by the user, together with the place's image, but I cannot manage to do that as I would need to filter the ForeignKey and Django does not seem to allow that.
Example of what I would like to do:
View:
pictures = Picture.objects.filter(user=request.user)
Template:
{% for picture in pictures %}
<img src="{{ picture.file.url }}" class="bigpicture">
{{ picture.place.placeratings.0.rating|user:picture.user }}
{% endfor %}
For information, I managed to do it with templatetags, but this generates a lot of different queries to the database which I can't prefetch..:
{% for picture in pictures %}
<img src="{{ picture.file.url }}">
{% getplaceratingrelatedtopic picture.place.id picture.user.id %}
{% endfor %}
And:
#register.simple_tag
def getplaceratingrelatedtopic(placeid, userid):
print(placeid)
theplace = Place.objects.get(id=placeid)
user = User.objects.get(id=userid)
placerating = PlaceRating.objects.filter(author=user, place=place).last()
if rating:
return placerating.rating
else:
return ""
I work with Python 2.7/Django 1.9.
Any clue ? Thanks a lot!
You should move the logic to the model and use it in the template.
class Picture(models.Model):
file = ImageField(max_length=500, upload_to="images")
user = models.ForeignKey(User, null=True, related_name="userpictures")
place = models.ForeignKey(Place, null=True, related_name='pictures')
class PlaceRating(models.Model):
place = models.ForeignKey(Place, null=True, related_name="placeratings")
user = models.ForeignKey(User, null=True, related_name="userratings")
rating = models.DecimalField(null=True, max_digits=4, decimal_places=1)
class Place(models.Model):
name = CharField(max_length=50)
#property
def rating(self):
return self.placeratings.get().rating
{% for picture in picture_list %}
<img src="{{ picture.file.url }}" class="bigpicture">
{{ picture.place.rating }}: {{ picture.user.username }}
{% endfor %}