Custom format an inline formset - django

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

Related

Pagination doesn`t work with extra context in Django ListView

I am trying to create a simple pagination through a query of filtered instances of Need model.
The problem is that pagination doesn`t work at all, and I guess this is because of extra content.
Here is my current view, which shows pagination on front-end as an empty div:
class CategoryNeeds(ListView):
model = Need
template_name = "volunteering/category_needs.html"
paginate_by = 1
context_object_name = "needs"
def get_queryset(self):
return Need.objects.filter(category__name=self.kwargs["name"].capitalize())
def get(self, request, *args, **kwargs):
self.object_list = self.get_queryset()
category = Category.objects.get(name=kwargs["name"].capitalize())
self.extra_context = {
"category": category,
"needs": self.object_list
}
return self.render_to_response(self.extra_context)
And here is the template:
{% extends "index/index.html" %}
{% block content %}
<section class="contact-section bg-black">
<div class="container px-4 px-lg-5">
<div class="row gx-4 gx-lg-5">
<div class="col-md-4 mb-3 mb-md-0">
<div class="card-body text-center">
<h1>{{ category.name }}</h1>
<hr style="size: A5">
</div>
</div>
</div>
</div>
</section>
<section class="about-section text-center" id="about">
<div class="container px-4 px-lg-5">
<h2>Needs:</h2>
<table class="table table-dark table-striped">
<thead>
<tr>
<th scope="col">Photo</th>
<th scope="col">Title</th>
<th scope="col">Description</th>
<th scope="col">Price</th>
<th scope="col">Donation</th>
<th scope="col">City</th>
{% if user.pk == user_page.pk %}
<th scope="col">Update</th>
<th scope="col">Delete</th>
{% endif %}
</tr>
</thead>
<tbody>
{% for need in needs %}
<tr data-href="{% url "volunteering:need" need.pk %}">
<td>{% if need.photo %}<img src="{{ need.photo.url }}">{% endif %}</td>
<td>{{ need.title }}</td>
<td>{{ need.description|truncatechars:10 }}</td>
<td>{{ need.price }}</td>
<td>{{ need.donation }}</td>
<td>{{ need.city }}</td>
{% if user.pk == user_page.pk %}
<td>Update</td>
<td>Delete</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div>
{% if page_obj.has_previous %}
« Previous page
{% if page_obj.number > 3 %}
1
{% if page_obj.number > 4 %}
<span>...</span>
{% endif %}
{% endif %}
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
{{ num }}
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
{{ num }}
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
{% if page_obj.number < page_obj.paginator.num_pages|add:'-3' %}
<span>...</span>
{{ page_obj.paginator.num_pages }}
{% elif page_obj.number < page_obj.paginator.num_pages|add:'-2' %}
{{ page_obj.paginator.num_pages }}
{% endif %}
Next Page »
{% endif %}
</div>
</section>
{% endblock %}
The reason why I think the problem lies in extra content is because this view works perfectly with pagination:
class AllNeeds(ListView):
model = Need
context_object_name = "needs"
paginate_by = 3
Could someone explain, why doesn`t my pagination work, please?
Would be very grateful for all your responce!
Yep, it seems that you are overiding normal django flow which adds context, try this:
class CategoryNeeds(ListView):
model = Need
template_name = "volunteering/category_needs.html"
paginate_by = 1
def get_queryset(self):
return Need.objects.filter(category__name=self.kwargs["name"].capitalize())
def get(self, request, *args, **kwargs):
self.object_list = self.get_queryset()
category = Category.objects.get(name=kwargs["name"].capitalize())
context = self.get_context_data()
context['category'] = category
return self.render_to_response(context)

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.

Why is my Class-based delete view not working?

My delete view is not working and the error message is:
Page not found (404) Request Method: GET.
I am trying to delete my uploaded file based on its primary key and so far, my url is able to link me correctly based on the pk.
This is my urls.py:
path('post/<int:post_id>/lesson_delete/<int:lesson_id>', LessonDeleteView.as_view(), name='lesson_delete'),
My views.py:
class LessonDeleteView(DeleteView):
model = Lesson
success_url = '../'
template_name = 'lesson_confirm_delete.html'
This is the html template that brings user to the delete view:
{% extends "store/base.html" %}
{% block content %}
<div id="main">
<table class="table mb-0">
<thead>
<tr>
<th>Title</th>
<th>Author</th>
<th>Download</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{% for l in Lesson %}
<tr>
<td>
{% if l.file %}
{{ l.title }}
{% else %}
<h6>Not available</h6>
{% endif %}
</td>
<td>{{ l.post.author }}</td>
<td>{% if l.file %}
Download
{% else %}
<h6>Not available</h6>
{% endif %}
</td>
<td> <a class="btn btn-danger btn-sm mt-1 mb-1" href="{% url 'lesson_delete' lesson_id=l.id %}">Delete</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
This is my html template for DeleteView:
{% extends "store/base.html" %}
{% block content %}
<div class="content-section" id="main">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Delete Lesson</legend>
<h2>Are you sure you want to delete the post "{{object.title}}"?
</h2>
</fieldset>
<span style="display:inline;">
<button class="btn btn-outline-danger" type="submit">Yes, Delete!
</button>
<a class="btn btn-outline-secondary" href ="">Cancel</a>
</span>
</form>
</div>
{% endblock content %}
This is my Lesson Model:
class Lesson(models.Model):
title = models.CharField(max_length=100)
file = models.FileField(upload_to="lesson/pdf")
date_posted = models.DateTimeField(default=timezone.now)
post = models.ForeignKey(Post, on_delete=models.CASCADE, null=False, blank=False)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('lesson_upload', kwargs={'pk': self.pk})
Is you template called 'lesson_confirm_delete.html'?
Also, for your success url, I have feeling you don't have a path '../'. It should the specific path you want it to go to.
(Sorry, I can't comment yet.)

Django Display a selection list

I am trying to implement a form where candidates can be selected for approval processing. I want to display a list of candidates, so their data can be viewed during selection.
models.py
class SubmissionApproval(models.Model):
candidate=models.ForeignKey(Candidate,on_delete=models.CASCADE)
clientProcess=models.ForeignKey(ClientProcessDetails,verbose_name="Client
Process",help_text="Process",on_delete=models.PROTECT)
dateSubmitted=models.DateTimeField(auto_now_add=True)
comments=models.CharField("Comments",max_length=200,blank=True,null=True)
class Meta:
verbose_name="First Stage Approval"
unique_together=(('candidate','clientProcess'),)
def __str__(self):
return self.candidate.name
views.py
def submissionApprovalList(request):
object_list=Candidate.objects.all()
if request.method=="POST":
fm=SubmissionApprovalFormList(request.POST)
print("Reached Post")
if fm.is_valid():
print("Printing Candidates Start")
for item in fm.cleaned_data['candidates']:
print(item)
print("Printing candidates End")
else:
fm=SubmissionApprovalFormList()
return render(request,'itrecruitment/firstStageSubmissionList.html',{'form':fm,'object_list':object_list })
forms.py
class SubmissionApprovalFormList(forms.Form):
candidates=forms.ModelMultipleChoiceField(
queryset=Candidate.objects.all(), widget=forms.CheckboxSelectMultiple
)
template
{% extends "seekgeek/base.html" %}
{% block content %}
<div class="row">
<div class="col-xs-12">
<div class="box">
<div class="box-header">
<h3 class="box-title">Select Candidates for First Stage Submission</h3>
<button type="button" class="btn btn-primary pull-right">Add Candidate </button>
</div>
<!-- /. box-header -->
<div class="box-body table-responsive">
<!-- form details -->
{% load bootstrap3 %}
{% bootstrap_css %}
{% bootstrap_javascript %}
{% bootstrap_messages %}
<form method="post" enctype="multipart/form-data" >
{% csrf_token %}
<table class="table table-bordered table-hover datatable2">
<thead>
<tr>
<td><b>Select</b></td>
<td><b>Candidate No</b></td>
<td><b>Candidate Name</b></td>
<td><b>Current CTC (LPA)</b></td>
<td><b>Expected CTC (LPA)</b></td>
<td><b>Experience in Yrs</b></td>
<td><b>Recruiter</b></td>
<td><b>Latest Status</b></td>
<td><b>Languages</b></td>
<td><b>Updated</b></td>
</tr>
</thead>
<!-- ./ table head -->
<tbody>
{% for obj in object_list %}
<tr>
<!--Select field for Form -->
<td> {{ form.candidates.0 }} </td>
<!--Select field for Form -->
<td>{{ obj.id }}</td>
<td>{{ obj.name }}</td>
<td>{{ obj.currentCTC }}</td>
<td>{{ obj.expectedCTC }}</td>
<td>{{ obj.experience }}</td>
<td>{{ obj.recruiter }}</td>
<td>{% if obj.latestRecStatus %}
<p><a class='text-green' href="{{ obj.latestRecStatus.get_absolute_url }}">{{ obj.latestRecStatus }}</a></p>
<p><a class='text-yellow' href="{% url 'clients:process-detail' obj.latestRecStatus.clientProcess.id %}"> {{ obj.latestRecStatus.clientProcess }} </a></p>
{% else %}
<p>No Status</p>
{% endif %}
</td>
<td>
{% for item in obj.programmingLanguages.all %}
<p>{{ item }}</p>
{% endfor %}
</td>
<td>{{ obj.updated }}</td>
</tr>
{% endfor %}
</tbody>
<!-- /. table body -->
</table>
<!-- /. table -->
{% buttons %}
<button type="submit" class="btn btn-primary">
Submit
</button>
{% endbuttons %}
</div>
<!-- /. box body -->
</div>
<!-- /. box -->
</div>
<!-- /.col -->
</div>
<!-- /.row -->
{% endblock %}
What is the correct way of doing this. intention is similar to change list form in django admin

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.