Name attribute of input field identical modelform - python

I am trying to loop through a Model PendingRequest and check the every request instance of a user and approve or decline the users request for each instance.I am using a ModelForm to render my form however, the part that gives issue is that the radio button to click on whether to approve or decline do not share the same input name attribue
here is my template
<form method="post">
{% csrf_token %}
<table>
<thead>
<tr>
<th>Book Title</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{% for book in books %}
<tr>
<td>{{ book.book.title }}</td>
<td>
<input type="radio" name="{{ book.id }}" value="approved"> Approve
<input type="radio" name="{{ book.id }}" value="not_approved"> Decline
</td>
</tr>
{% endfor %}
</tbody>
</table>
<button type="submit">Update</button>
</form>
so what i want to achieve is to replace
<input type="radio" name="{{ book.id }}" value="approved"> and <input type="radio" name="{{ book.id }}" value="not_approved"> with this below such that when it is rendered, every loop will have same the name attribute but different values
<form method="post">
{% csrf_token %}
<table>
<thead>
<tr>
<th>Book Title</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{% for book in books %}
<tr>
<td>{{ book.book.title }}</td>
<td>
{% for choice in form.approved %}
{{choice.tag}}
{% endfor %}
{% for choice in form.not_approved %}
{{choice.tag}}
{% endfor %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<button type="submit">Update</button>
</form>
here is my forms.py
class Approve(forms.ModelForm):
approved = forms.BooleanField(widget=forms.RadioSelect(choices=[(True, 'Approve')]))
not_approved = forms.BooleanField(widget=forms.RadioSelect(choices=[(True, 'Decline')]))
class Meta:
model = PendingRequest
exclude = ["member", "book_request", "book"]
models.py
class PendingRequest(models.Model):
book_request = models.OneToOneField(BorrowBook, on_delete=models.CASCADE, null=True)
member = models.ForeignKey(User, on_delete=models.CASCADE, default="", null=True)
book = models.ForeignKey(Books, on_delete=models.CASCADE, default="", null=True)
approved = models.BooleanField(default=False)
not_approved = models.BooleanField(default=False)
approval_date = models.DateTimeField(auto_now=True, null=True)
views.py
def approve(request, pk):
books = PendingRequest.objects.filter(member__id=pk)
if request.method == "POST":
for book in books:
form = Approve(request.POST, instance=book)
if form.is_valid():
book.approve = form.cleaned_data.get(f'approve_{book.id}')
book.save()
return redirect(index)
else:
form = Approve()
return render(request, "books/approve.html", {"form": form, "books": books})

You are making this a little complicated for yourself...
You have two booleans in that PendingRequest model. One for approved and one for not_approved. You only want one, because if approved is False, then it's already not_approved by definition.
You also are making life difficult by having two radio button fields with one radio button each for field. Radio buttons are for multiple choice, one value allowed. You could use two radio buttons for one field (a checkbox is often better) but having two radio buttons for two separate fields is not only bad HTML, you'll likely be able to select both at once. If you give them the same name to prevent that, they won't be linked to the correct field without a lot of weird post-POST fiddling about. It's very messy. I'd really advise using a single field.
Regardless if you take that advice, for multiple forms of the same model, Django can handle this situation with a modelformset, something like...
views.py
PendingRequestFormSet = modelformset_factory(PendingRequest , form = Approve)
#we have to also bring in the book title along with the forms , even though we are not using it in the form,
# so we'll zip up the queryset with the formset.
# We use select_related in the queryset to prevent additional database calls in the template when the title gets evaluated
pending_requests = PendingRequest.objects.filter(member__id=pk).select_related('book')
formset = PendingRequestFormSet(queryset=pending_requests))
pending_requests_and_formset = zip(queryset, formset)
...
return render(request, "books/approve.html", {"form": form, "books": books, 'pending_requests_and_formset', pending_requests_and_formset })
template.html
...
<form method="post">
{{ formset.management_form }}
{% for request, form in pending_requests_and_formset %}
<td>{{request.book.title}}</td>
<td>{{ form }}</td>
{% endfor %}
</form>

Related

How I can get the value of check radio button in update page

How I can get the value of check radio button in update page, it save it DB but in update page it did not show the selected radio button.
in models
class UserListGroup(models.Model):
user_role = models.CharField(max_length=25, default="USER")
def __int__(self):
return self.ulg_id
class Meta:
db_table = 'userlist_group'
in add html
<tr>
<td class="mtrr"><b>User Role*</b></td>
<td class="mtrr"><label class="radio-inline"><input type="radio" name="user_role" value="admin" checked>Admin</label></td>
<td class="mtrr"><label class="radio-inline"><input type="radio" name="user_role" value="super">Super User</label></td>
<td class="mtt"><label class="radio-inline"><input type="radio" name="user_role" value="user">User</label></td>
</tr>
in update add html
<tr>
<td class="mtrr"><b>User Role*</b></td>
<td class="mtrr"><label class="radio-inline"><input {% if data.ul_role == True %} checked {% endif %} type="radio" name="user_role">Admin</label></td>
<td class="mtrr"><label class="radio-inline"><input {% if data.ul_role == True %} checked {% endif %} type="radio" name="user_role">Super User</label></td>
<td class="mtt"><label class="radio-inline"><input {% if data.ul_role == True %} checked {% endif %} type="radio" name="user_role">User</label></td>
</tr>
in view
def add_user(request):
if request.method == 'POST':
form = request.POST
user_role = form.get('user_role')
employee_master = UserListGroup.objects.create(user_role=user_role,
)//other code
Your information is a bit incomplete as you left out the update view
You can solve your problem as follows
Add CHOICE attribute to your user_role field
In model:
class UserListGroup(models.Model):
ROLE = (('user', 'USER'), ('admin', 'ADMIN'), ('super', 'SUPER USER'))
user_role = models.Charfield(max_length=25, choices=ROLES, default=user)
using choices will cause a html widget to be used, to use a radio button, create a Django form and update it as below
from Django forms import ModelForm, RadioSelect
from .models import UserListGroup
class UserListGroupForm(ModelForm):
class Meta:
model = UserListGroup
field = '__all__'
widgets = {
'user_role': RadioSelect()
}
Your add.html and update.html would look similar to
<form method="POST" action="">
{% csrf_token %}
{{ form }}
</form>
For such simple crude operation, you are better off using the Django generic view
On a final note, the approach you use in your update.html in checking for the current user role is wrong, as the condition is same in all three cases. It should be compared with their possible database values as follows
<tr>
<td class="mtrr"><b>User Role*</b></td>
<td class="mtrr"><label class="radio-inline"><input {% if data.ul_role == 'admin' %} checked {% endif %} type="radio" name="user_role">Admin</label></td>
<td class="mtrr"><label class="radio-inline"><input {% if data.ul_role == 'super' %} checked {% endif %} type="radio" name="user_role">Super User</label></td>
<td class="mtt"><label class="radio-inline"><input {% if data.ul_role == 'user' %} checked {% endif %} type="radio" name="user_role">User</label></td>
</tr>

When displaying foreign key base Queryset on template

I have two models shown below
class Services(models.Model):
name = models.CharField(max_length=200, null=True)
price = models.FloatField(null=True)
service_sku = models.CharField(max_length=200, null=True)
class Order(models.Model):
customer = models.ForeignKey(Customer, null=True, on_delete = models.SET_NULL)
service = models.ForeignKey(Service, null=True, on_delete = models.SET_NULL)
I have created a function-based view based on the service model where I want to render a template displaying a list of field information from each instance from the service model.
See below for my views and template
views.py
def service_list(request):
service_list = Service.objects.all().order_by('service_sku')
context = {'service_list':service_list}
return render(request, 'accounts/service_list.html',context)
template
<div class="card card-body">
<table class="table">
<tr>
<th>SKU</th>
<th>Service Name</th>
<th>Number of Ordered</th>
</tr>
{% for i in service_list %}
<tr>
<td>{{i.service_sku}}</td>
<td>{{i.name}} </td>
<td></td>
</tr>
{% endfor %}
I want to display the number of orders of each instance, considering that the order model has a foreign key from the service model.
The query set would have to be like the below shown.
Order.objects.all().filter(service__id =3).count()
Problem is that I must specify which id of that model would be for that queryset to work.
I’ve tried to put the queryset format below within the template
{{Order.objects.all().filter(service__id=i.id).count()}
In the template it would look like how it does below
template
<div class="card card-body">
<table class="table">
<tr>
<th>SKU</th>
<th>Service Name</th>
<th>Number of Ordered</th>
</tr>
{% for i in service_list %}
<tr>
<td>{{i.service_sku}}</td>
<td>{{i.name}} </td>
<td>{{Order.objects.all().filter(service__id=i.id).count()}}</td>
</tr>
{% endfor %}
The above implementation does not work.
Which method is ideal for this situation?
You can not call methods (with parameters) in a Django template. The templates are deliberately restricted to prevent people from writing business logic in the templates.
You can .annotate(…) [Django-doc] the queryset to fetch the number of related Orders:
from django.db.models import Count
def service_list(request):
service_list = Service.objects.annotate(
norders=Count('order')
).order_by('service_sku')
context = {'service_list':service_list}
return render(request, 'accounts/service_list.html',context)
In the template you can then render this with:
{% for i in service_list %}
<tr>
<td>{{ i.service_sku }}</td>
<td>{{ i.name }} </td>
<td>{{ i.norders }}</td>
</tr>
{% endfor %}

Getting the id of a model from a button in Django

I currently have a template set up so that it loops through all of my menu items with a button that correspond to a post request in my views.py
<td>
{% for menu_items in menu %}
{{ menu_items.Menu_name }}
{% endfor %}
</td>
<td>
{% for menu_desc in menu %}
{{ menu_desc.Menu_Desc }}
{% endfor %}
</td>
<form method="post">
{% csrf_token %}
<th><input class="btn btn-success" type="submit" value="Add To Cart" name="add">.
</th>
</form>
In my views file I have a if statement that tries to get the id of the model that was clicked.
However, i'm only able to get the Query Set and not the specific ID of the model.
def ordering(request):
latest_order = Order.objects.all()
menu = Menu.objects.all()
if 'add' in request.POST:
user_order = Order.objects.get(name='')
print(menu.id)
return render(request, 'users/ordering.html', {'title':'Ordering', 'latest_order': latest_order, 'menu':menu})
When working with queryset, whatever is returned has a primary key and not id as you would occasionally think, therefore use
item.pk instead of item.id
You cannot get the id of QuerySet, in the situation, you can treat the QuerySet like an iterable, try to print this way:
menu = Menu.objects.all()
print([item.id for item in menu])

Python Django tables with checkbox delete option

I am new to Django and currently trying to display a table with a checkbox which displays the list of records from the database and would have a delete button to delete multiple records using checkbox.
How to display a table with checkbox and delete button?
Appreciate your help!
Here is my code related to it:
models.py
class Customer(TimeStamp):
name = models.CharField(max_length=30, unique=True)
description = models.CharField(max_length=100,blank=True,help_text="Long-form name (optional)")
comments = models.TextField(blank=True)
class Meta:
ordering = ['-id']
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('App_CUS:customer_list')
views.py
class CustomerListView(ListView):
queryset = Customer.objects.order_by('id')
model = Customer
paginate_by = 10
context_object_name = 'customers'
template_name = 'App_CUS/customer_list.html'
customer_list.html
customer_list.html:
{% extends 'index.html' %}
{% load buttons %}
{% block content %}
<div class="pull-right">
{% if perms.App_CUS.customer_add %}
{% add_button 'App_CUS:customer_add' %}
{% delete_button 'App_CUS:customer_delete' %}
{% endif %}
</div>
<h1>{% block title %}Customers{% endblock %}</h1>
<div class="col-md-9">
<div class="table-responsive">
<table class="table table-hover table-headings table-bordered">
<thead>
<tr>
<th class="pk">
<input class="toggle" title="Toggle all" type="checkbox">
</th>
<th>ID</th>
<th>Customer Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
{% for customer in customers %}
<tr>
<th class="pk">
<input class="toggle" title="Toggle all" type="checkbox">
</th>
<td>{{ customer.pk }}</td>
<td>{{ customer.name }}</td>
<td>{{ customer.description }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
I would add to your existing
{% for customer in customers %}
a new td tag including something like:
<td>
<div class="checkbox">
<input type="checkbox" name="name_check_{{customer.name}}" id="id_check{{customer.name}}" value="1"
{%if customer.data == 0 %}unchecked {%else%} checked {%endif%}>
</div>
<td>
I've used customer.data to represent a value stored in your db.
You could then write some js to do something on click of each new checkbox.
<script>
$(document).ready(function() {
$("#id_check_{{customer.id}}").on("click", function(){
#do something / ajax call etc..
OR
pass these values back to the view on form post (we've named each checkbox unique to the customer), then process the deletions from there.

Django-Filter: Dynamically Create Queryset on Search or Hide Queryset until Search

I am using django-filter to search a model. Here is the code:
filters.py:
class PersonFilter(django_filters.FilterSet):
lastName = django_filters.CharFilter(lookup_expr='icontains')
firstName = django_filters.CharFilter(lookup_expr='icontains')
class Meta:
model = Person
fields = ['lastName', 'firstName']
views.py:
def search(request):
people = Person.objects.all()
people = PersonFilter(request.GET, queryset=people)
context = {'filter': people}
return render(request, 'myapp/template.html', context)
template.html:
<form method="get">
{{ filter.form.as_p }}
<button type="submit">Search</button>
</form>
<table>
{% for field in filter.qs %}
<tr>
<td>
{{ field.idno }}
</td>
<td>
{{ field.lastName }}
</td>
<td>
{{ field.firstName }}
</td>
<td>
{{ field.status }}
</td>
</tr>
{% endfor %}
</table>
{% endblock %}
</body>
</html>
Right now, this results in a table that mirrors my model with search boxes for first name and last name. The search works perfectly.
How do I prevent the table of data from showing up initially? Logically, this could be done superficially (hide) or, better yet, substantially (dynamically create queryset). Is this possible?
You can leverage the FilterSet's is_bound property, although you would need to change the view code to only provide the request query params when the form has been submitted.
def search(request):
submitted = 'submitted' in request.GET
data = request.GET if submitted else None
people = PersonFilter(data, queryset=Person.objects.all())
return render(request, 'myapp/template.html', {'filter': people})
<form method="get">
{{ filter.form.as_p }}
<button type="submit" name="submitted">Search</button>
<!-- ^^^^ added 'name' parameter -->
</form>
{% if filter.is_bound %}
<table>
{% for person in filter.qs %}
...

Categories