Display many to many relation relations in the template - django

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.

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 %}

djang-bootstrap avoid label tag being added when calling `field|bootstrap`

How to avoid label tag being added when calling field|bootstrap. I have the below code
filter.py
import django_filters
from .models import Issue
class IssuesFilter(django_filters.FilterSet):
summary = django_filters.CharFilter(label="Summary", lookup_expr="icontains")
class Meta:
model = Issue
Views.py
def index(request):
issues = IssuesFilter(request.GET, queryset=Issue.objects.all())
context = {
'user': request.user,
'message': 'LogedIn',
'filter': issues
}
return render(request, 'testApp/index.html', context)
index.html
{% extends "firstPage/base.html" %}
{% load bootstrap %}
{% load render_table from django_tables2 %}
{% load crispy_forms_tags %}
{% block body %}
<form method="GET">
<table>
{% for field in filter.form %}
<tr class="table table-borderless">
<td>{{ field.label_tag }}</td>
<td>{{ field|bootstrap }}</td>
</tr>
{% endfor %}
</table>
<button type="submit" class="btn btn-primary">Search</button>
</form>
{% endblock %}
When I add field|bootstrap I could see the label tag of the field is displayed. Is it possible to remove additional label tag from being added?
I know this comes very late but if anyone is dealing with the same problem you can find the answer in the documentation
https://django-bootstrap4.readthedocs.io/en/latest/templatetags.html#bootstrap4.templatetags.bootstrap4.bootstrap_field
{% bootstrap_field field show_label=False %}

Django - How to change dropdown form into table

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.

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.

How to split form to two columns?

I have model:
class Post(models.Model):
path = 'images' + str(datetime.now().year) + '/' + str(datetime.now().month)
image = models.ImageField(upload_to=path, null=True)
recommended = models.BooleanField(default = False)
promoted = models.BooleanField(default = False)
title = models.TextField(blank = True)
intro = RichTextField(config_name='full_ck', blank = True)
text = RichTextField(config_name='full_ck', blank = True)
, form:
class Form(forms.ModelForm):
id = forms.ModelChoiceField(queryset=Post.objects.all(), widget=forms.HiddenInput())
class Meta:
model = Post
and template:
<table cellpadding="0" cellspacing="0">
<formset>
{% for field in form %}
{% if field.is_hidden %}
{{ field }}
{% else %}
<div class="fieldWrapper">
{% if field.errors %}<div class="errorbox">{% endif %}
<p>{{ field.label_tag }}</p>
<p>{{ field }}{% block formextrafields %}{% endblock %}</p>
<p></p>
{% if field.errors %}<p>{{ field.errors }}</p></div>{% endif %}
</div>
{% endif %}
{% endfor %}
</formset>
</table>
But I want to divide form to two columns. In first may be intro, text and title fields and in second others. How to do it?
I use this in view:
form = list(form)
, in model I set order with:
class Meta:
model = Post
fields = (my fields in order)
and in template:
<!-- first -->
<table cellpadding="0" cellspacing="0">
<formset>
{% for field in form|slice:":3" %}
[...]
{% endfor %}
</formset>
</table>
<!-- second -->
<table cellpadding="0" cellspacing="0">
<formset>
{% for field in form|slice:"3:" %}
[...]
{% endfor %}
</formset>
</table>
And it works.
You could use crispy forms for the layout and to add css classes: https://github.com/maraujop/django-crispy-forms