Django - How to change dropdown form into table - django

I'm creating an application in Django and I'm having an issue with iterating through options in a dropdown from a form in Django. I was wondering if anyone could be of assistance.
detail.html
{% for subject in subject_list %}
<form action="" method="POST">
{% csrf_token %}
<table class='table table-borderless table-hover'>
<tbody>
<tr>
<td>{{ subject.subjectname }}
{% for field in form %}
{{ field.hidden }}
{% endfor %}
</td>
</tr>
</tbody>
</table>
<button type="submit" id="login-btn" class="btn">Create a new evaluation</button>
</form>
{% endfor %}
forms.py
class CreateEvalForm(forms.ModelForm):
subjectname = ModelChoiceField(queryset=Subject.objects, label='', empty_label="Choose subject..")
class Meta:
model = Evaluation
fields = ['subjectname', ]
models.py
class Subject(models.Model):
id = models.AutoField(primary_key=True)
subjectname = models.CharField(max_length=255, help_text="Type the name of the subject.")
slug = models.SlugField(max_length=200, unique=True)
Ideally we want it to look like on the picture below:
Note that the picture is in danish and Fag = Subject, Opret ny evaluering = Create new evaluation and Se evaluering = View evaluation
we want this
we don't want this

I solved this with the help from the comments by changing my for loop and table to this:
<form action="" method="POST">
{% csrf_token %}
<table class='table table-borderless table-hover'>
{% for option in form.fields.fagnavn.choices %}
{% if not forloop.first %}
<tbody>
<tr>
<td>{{ option.1 }}</td>
<td><button value="{{ option.0 }}" name="fagnavn">Opret ny evaluering</button></td>
</tr>
</tbody>
{% endif %}
{% endfor %}
</table>
</form>
I gained access to the choices in the dropdown with form.fields.fagnavn.choices and excluded the default value of "choose value" with an if statement of {% if not forloop.first %}
And that's pretty much it.

Related

Custom format an inline formset

I'm create a template in Django, adding a form and formset to the template, but I don't like how it's formatting the formset by default. I've tried .as_table and .as_ul, but it's not formatting it to my liking. I'd like to see the following from the formset:
Ingredient Percentage Delete
ingredient1 .55
ingredient2 .22
ingredient3 .33
I've tried the code in "https://stackoverflow.com/questions/17492374/how-to-render-formset-in-template-django-and-create-vertical-table" but when I implement it, I'm getting two extra column, "ID" and "Recipe Name". I don't know where those columns are coming from and I don't know how to get rid of them.
Example:
models.py
class Recipe(models.Model):
name = models.CharField(max_length=200, null=True)
description = models.CharField(max_length=200, null=True, blank=True)
def __str__(self):
return self.name
class Recipe_Ingredient(models.Model):
recipe_name = models.ForeignKey(Recipe, null=True, on_delete = models.SET_NULL)
ingredient = models.ForeignKey(Product, null=True, on_delete= models.SET_NULL)
recipe_percent = models.DecimalField(max_digits=8, decimal_places=5, blank=True)
views.py
def recipeUpdate(request, recipe_id):
RecipeIngredientFormSet2 = inlineformset_factory(Recipe, Recipe_Ingredient, extra=10, fields=('ingredient', 'recipe_percent'))
recipe = Recipe.objects.get(pk=recipe_id)
formset = RecipeIngredientFormSet2(instance=recipe)
context = {'formset' : formset}
return render(request, 'accounts/recipe_form.html', context)
recipe_form.html
{% extends 'accounts/main.html' %}
{% load static %}
{% block content %}
<div class="row">
<div class="col-md-6">
<div class="card card-body">
<form action="" method="POST">
{{ form }}
<p></p>
<!--{{ formset.as_table }}-->
<p></p>
{{ formset.management_form}}
<!--{% for form in formset %}
{{ form }}
{% endfor %}-->
<table>
<thead>
{% for form in formset %}
{% if forloop.first %}
{% for field in form %}
<th>{{ field.label_tag }}</th>
{% endfor %}
{% endif %}
</thead>
<tbody>
<tr>
{% for field in form %}
<td>{{ field }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
<input type="submit" name="Submit">
</form>
</div>
</div>
</div>
{% endblock %}
Found the answer. You've got to add the formset with a .management_form tag, then in table, loop through each form in form set. If it's the first loop, add the headers to the tables. In all other loops, add each field from the form that you want in the table.
The updated HTML that I'm using is below.
{% extends 'accounts/main.html' %}
{% load static %}
{% block content %}
<div class="row">
<div class="col-md-6">
<div class="card card-body">
<form action="" method="POST">
{% csrf_token %}
{{ form }}
{{ formset.management_form }}
<table>
{{ form.id }}
{% for p in formset %}
<tr>
{% if forloop.first %}
<td>{{ p.DELETE.label_tag }}</td>
<td>{{ p.ingredient.label_tag }}</td>
<td>{{ p.recipe_percent.label_tag }}</td>
<p></p>
{% endif %}
</tr>
<!--{{ p.id }}
{{ p.ORDER }}-->
<tr></tr>
<td>{{ p.DELETE }}</td>
<td>{{ p.ingredient }}</td>
<td>{{ p.recipe_percent }}</td>
</tr>
{% endfor %}
</table>
<input type="submit" name="Submit">
</form>
</div>
</div>
</div>
{% endblock %}

Outputting a table to a template

I recently began to study Django and cannot understand how to correctly implement the template (table)
I have a model:
She has ties to Company and bank.
class BankAccount(models.Model):
company = models.ForeignKey('Company.Company', null=True, on_delete=models.CASCADE, verbose_name='Фирма',
related_name='company')
bank = models.ForeignKey('Bank', null=True, on_delete=models.CASCADE, verbose_name='Банк', related_name='bank')
login_bank = models.CharField(max_length=255, verbose_name='Логин', null=False)
password_bank = models.CharField(max_length=255, verbose_name='Пароль', null=False)
date_created = models.DateTimeField(auto_now=True)
date_updated = models.DateTimeField(auto_now_add=True)
balance = models.DecimalField(max_digits=15, decimal_places=2, blank=True, null=True)
In the template I want to display a table where all firms / banks will be displayed at the intersection of these columns and rows, a value from this model will appear.
I've been looking for an answer for 5 days and
Company1
Company2
Company3
Company4
Bank1
Balance(Company1/Bank1)
Balance(Company2/Bank1)
Balance(Company/Bank1)
Balance(Company4/Bank1)
Bank2
Balance(Company1/Bank2)
....
....
....
Bank3
Balance(Company1/Bank3)
....
....
....
I tried the example template below, thanks
#Linh Nguyen
<table class="table table-bordered">
<tr>
<th> </th>
{% for company in companies %}
<th>{{ company.name }}</th>
{% endfor %}
</tr>
{% for bank in banks %}
<tr>
<td>{{bank.name}} </td>
{% for company in companies %}
{% for account in bank_accounts %}
{% if account.company_id == company.id and bank.id == account.bank_id %}
<td>{{account}}</td>
{% endif %}
{% endfor %}
{% endfor %}
</tr>
{% endfor %}
</table>
context = {
'companies': Company.objects.all().order_by('id'),
'banks': Bank.objects.all().order_by('id'),
'bank_accounts': BankAccount.objects.all()
}
But the result is still not desired. One firm can have 2 and 4 accounts in the table of accounts (bank_account).
and if the company does not have all 4 accounts, the data no longer match.If you add {% else%}, then the table breaks completely.
screen
<div class="col-md-12">
<div class="row">
<table class="table table-bordered">
<tr>
<th> </th>
{% for company in companies %}
<th>{{ company.name }}</th>
{% endfor %}
</tr>
{% for bank in banks %}
<tr>
<td>{{bank.name}} </td>
{% for company in companies %}
<td>
{% for account in bank_accounts %}
{% if account.company_id == company.id and bank.id == account.bank_id%}
{{account}}
{% endif %}
{% endfor %}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
</div>
</div>
Finally it worked out!
I think it only come down to how you handle the logic in the looping:
in your view you have the querysets for all the banks, companies and bank accounts
view.py:
context = {
'companies': Company.objects.all(),
'banks': Bank.objects.all(),
'bank_accounts': BankAccount.objects.all()
}
template.html:
<table style="width:100%">
<tr>
{% for company in companies %}
<th>{{ company.name }}</th>
{% endfor %}
</tr>
{% for bank in banks %}
<tr>
{% for company in companies %}
{% for bank_account in bank_accounts %}
<td>
{% if bank_account.company == company %}
Balance({{ company.name }}/{{ bank.name }})
{% endif %}
</td>
{% endfor %}
{% endfor %}
</tr>
{% endfor %}
</table>
First, you should implement your view function like this:
from django.shortcuts import render
from models import BackAccount
def get_bank_accounts(request):
accounts = BankAccount.objects.all()
context = {
'accounts': accounts,
}
return render(request, 'accounts.html', context)
So, that way you send all accounts to the template. And the way you use them in accounts.html like this:
{% for account in accounts %}
{{ account.bank }}
{{ account.company }}
{% endfor %}

Django how to display list users with some data in template

I want to display the list of users with some objects in 2 modelapps created.
these are the models.
first model:
class UserProfile(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE)
indirizzo = models.CharField(max_length=50)
citta = models.CharField(max_length=50)
paese = models.CharField(max_length=50)
ecap = models.CharField(max_length=4)
descrizione = models.CharField(max_length=100, default='')
image = models.ImageField(upload_to='profile_image', blank=True,null=True)
second model:
class Ore(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="ore",null=True,)
data = models.DateField(default=timezone.now)
oret = models.CharField(max_length=3,)
contrattiok = models.PositiveSmallIntegerField()
contrattiko = models.PositiveSmallIntegerField(default=0,)
nomecognome = models.CharField(max_length=100,blank=True)
my view:
def inizio(request):
users = User.objects.all()
return render (request, "base.html", {"users":users})
my template:
{% for users in users %}
<tbody>
<tr>
<td>
<img src="{{ users.userprofile.image.url }}"class="thumbnail">
<h4 class="small font-weight-bold">{{users}}</h4>
</td>
<td><h4 class="small font-weight-bold">{{users.last_name}}</h4></td>
<td class="text-center">
<h4 class="small font-weight-bold" class="btn btn-primary btn-circle">{{ users.ore.contrattiok }}</h4> <<<<<(does not work)
</td>
</tr>
{% endfor %}
I saw several problems in your templates.
1. It would be better to make different variable of users loop to increase readability code.
don't do this: {% for users in users %}
but instead: {% for user in users %}
so then you can use it with user instead of users inside loop like:
{{ user.last_name }}
2. your <tbody> inside forloop users, but theres no </tbody> right before the {% endfor %}.
But I suggest you to do not include <tbody> inside forloop.
Do this instead:
<tbody>
{% for user in users %}
<tr><td></td></tr>
{% endfor %}
</tbody>
since your foreign key is inside Ore model instead
(one to many relationship which means 1 user has many ores),
so you need to loop every ore on each user.
{% for user in users %}
{% for ore in user.ore.all %}
{{ ore.contrattiok }}
{% endfor %}
{% endfor %}
so the final result will be like this:
<tbody>
{% for user in users %}
<tr>
<td>
<img src="{{ user.userprofile.image.url }}" class="thumbnail">
<h4 class="small font-weight-bold">{{ user }}</h4>
</td>
<td><h4 class="small font-weight-bold">{{user.last_name}}</h4></td>
<td class="text-center">
{% for ore in user.ore.all %}
<h4 class="small font-weight-bold" class="btn btn-primary btn-circle">
{{ ore.contrattiok }}
</h4>
{% endfor %}
</td>
</tr>
{% endfor %}
</tbody>
EDITED
based on your comment, so you want to sum the total of contrattiok field?
if that so, you need to change your view using annotate
from django.db.models import Sum
users = User.objects.annotate(total_contrattiok=Sum('ore__contrattiok'))
then in your template:
{% for user in users %}
<td class="text-center">
<h4 class="small font-weight-bold" class="btn btn-primary btn-circle">
{{ user.total_contrattiok }}
</h4>
</td>
{% endfor %}

Django dynamically filter list in template

I have a page which lists all of the athletes that a certain coach has. Coaches, however, can have multiple teams and I am trying to allow them to select a team from a dropdown at the top of the page and dynamically filter the list of athletes to only show those on the selected team.
My template:
<table class='table'>
<tr>
<td><h3>Team</h3></td>
<td><h3>First Name</h3></td>
<td><h3>Last Name</h3></td>
<td><h3>Email</h3></td>
</tr>
{% for athlete in athletes %}
{% if not athlete.coach_ind %}
<tr><td>
{% for team in athlete.team.all %}
{{ team.school }} {{ team.mascot }} {{ team.sport }}
{% endfor %}
</td>
<td>{{ athlete.user.first_name }}</td>
<td>{{ athlete.user.last_name }}</td>
<td>{{ athlete.user.email }}</td>
</tr>
{% endif %}
{% endfor %}
</table>
My view:
teams_list = request.user.profile.team.all()
athletes = UserProfile.objects.filter(team__in=teams_list).order_by('team','user__last_name')
I am able to successfully get the correct list of all athletes and their information, I'm just not sure how to create a dynamic filter to show only by team.
You can use django-filter for it https://github.com/alex/django-filter.
Example from documentation:
Model
class Product(models.Model):
name = models.CharField(max_length=255)
manufacturer = models.ForeignKey(Manufacturer)
Filter
class ProductFilter(django_filters.FilterSet):
class Meta:
model = Product
fields = ['manufacturer']
View
def product_list(request):
f = ProductFilter(request.GET, queryset=Product.objects.all())
return render_to_response('my_app/template.html', {'filter': f})
Template
{% block content %}
<form action="" method="get">
{{ filter.form.as_p }}
<input type="submit" />
</form>
{% for obj in filter %}
{{ obj.name }}<br />
{% endfor %}
{% endblock %}
Another app to those for this type of "chained" selection is selectable (http://django-selectable.readthedocs.io/en/latest/advanced.html#chained-selection). You have to put some additional javascript to the template, though.

Display many to many relation relations in the template

First of all I will post all the possibly necessary code. My models:
class topic(models.Model):
learningObjectivesTopic = models.ManyToManyField(learningObjective, verbose_name = "Lernziel")
topic = models.TextField(verbose_name = 'Thema')
class learningObjective(models.Model):
learningObjectives = models.TextField(verbose_name = 'Lernziel')
My views:
#login_required(login_url='login')
def lernziel(request):
return render(request, 'lernziel.html', {'topic': topic.objects.all(), 'todo': todoList.objects.all()})
#login_required(login_url='login')
def create_lernziel(request):
neuesLernziel=learningObjective(learningObjectives=request.POST['Lernziel'])
neuesLernziel.save()
neuesLernziel_Topic=topic.objects.get(topic=request.POST['Thema'])
neuesLernziel_Topic.learningObjectivesTopic.add(neuesLernziel)
return render(request, 'lernziel.html', {'topic': topic.objects.all(), 'todo': todoList.objects.all()})
And the template I am using:
<html lang="{{ LANGUAGE_CODE|default:"de-de" }}" >
<head>
<h1 align = "center">Lernziele</h1>
</head>
<body>
<form action="{% url 'create_lernziel' %}" method="post">
{% csrf_token %}
<br>Hallo Benutzer: {{ user.username }}</br>
Lernziel: <textarea name="Lernziel" rows="3" cols="45" ></textarea>
<p>
<select name="Thema" size="5">
{% for topic_ in topic %}
<option>{{ topic_.topic }}</option>
{% endfor %}
</select>
</p>
<input type="submit" value="Absenden" />
</form>
{% comment %}
Here should be the table which displays learning objectives and the related topics
{% endcomment %}
</body>
</html>
Ok I know my question is a bit weird because I don't have directly wrong code that I am posting. But I tried it so many times to display what I want properly but I just don't get how to do it right. My aim is to have 2 columns/headers: [learning objective] and [topics]. For every learning objective I want to have a new row. And in every row, it is possible to display more topics in relation. If you need more information or want me to be more specific about my problem please post it in the comments :)
Edit my first thought of that structure was that one: I iterate through the learning objectives, create a row for each one and and list the learning objectives and topics in that row then. Apparently it's not working. The Table probably has to be dynamic so that my idea is working or I just had a wrong thought.
<table border="1">
<th>Lernziel</th>
<th>Thema</th>
{% for topic_ in topic %}
{% for lObj in topic_.learningObjectivesTopic.all %}
<tr><td>{{ lObj }}</td>
{% endfor %}
<td>{{ topic_.topic }}</td></tr>
{% endfor %}
</table>
There isn't anything complicated here. You already know that you can get from an objective to its related topics by doing my_objective.topic_set.all(). So you just need to do that while you iterate through each topic in the template (and since it's a template, you drop the parentheses):
<table>
{% for objective in objectives %}
<tr>
<td>{{ objective.learningObjectives }}</td>
<td>{% for topic in objective.topic_set.all %}
{{ topic.topic }}{% if forloop.last %},{% endif %}
{% endfor %}</td>
</tr>
{% endfor %}
</table>
models.py
class learningObjective(models.Model):
learningObjectives = models.TextField(verbose_name = 'Lernziel')
class topic(models.Model):
learningObjectivesTopic = models.ManyToManyField(learningObjective, verbose_name = "Lernziel")
topic = models.TextField(verbose_name = 'Thema')
if you want to put topic ahead,use " or ',that is "learningObjective"
class topic(models.Model):
learningObjectivesTopic = models.ManyToManyField("learningObjective", verbose_name = "Lernziel")
topic = models.TextField(verbose_name = 'Thema')
class learningObjective(models.Model):
learningObjectives = models.TextField(verbose_name = 'Lernziel')
<p>
<select name="Thema" size="5">
{% for topic_ in topic %}
<option>{{ topic_.topic }}</option>
{% for lo in topic_.learningObjectivesTopic.all %}
<option>{{ lo.learningObjectives }}</option>
{% endfor %}
{% endfor %}
</select>
</p>
If you want to get topic from learningObjective
lo = learningObjective.objects.all()[0]
lo.topic_set()
in templates,remove "()", I believe that you know how to use it in templates.