django: update database upon onsubmit dropdown - django

I am trying to create a ticketing system. What I want to do is when I change the Status dropdown list it should update the status of the ticket in the database. Also, I would like to update and view in the same page. Any insights if that would be possible?
forms.py
class ViewForm(forms.Form):
statuses = [
('In Progress', 'In Progress'),
('On Hold', 'On Hold'),
('Done', 'Done'),
('ForQA', 'ForQA'),
('QAPassed', 'QAPassed'),
('QARevs', 'QARevs'),
]
status = forms.ChoiceField(label='Status', required=True, choices=statuses, widget=forms.Select(attrs={'onchange': 'actionform.submit();'}))
views.py
def view_sheet(request, project_id):
project = Project.objects.get(pk=project_id)
tickets = Ticket.objects.filter(project=project_id)
form = ViewForm()
context = {
'project': project,
'tickets': tickets,
'form': form,
}
return render(request, 'project/sheet/view.html', context)
view.html
<div class="tracker-sheet">
<div class="project-name">
<h1>{{project.name}}</h1>
</div>
<div class="actions">
<a href="{% url 'add_ticket' project.id %}">
<button type="submit">New Ticket</button>
</a>
</div >
<div class="tracker-table">
<table>
<tr>
<th>Total Worked</th>
<th>Status</th>
<th>Status Date</th>
<th>Received</th>
<th>Due Date</th>
<th>Agent</th>
<th>Sub Type</th>
<th>CID</th>
<th>Link</th>
<th>Task Description</th>
<th>Server</th>
<th>Qty</th>
<th>Info</th>
</tr>
{% for ticket in tickets %}
<tr>
<td><span class="table-constant"></span></td>
{% for field in form %}
<td>{{field}}</td> <!-- Status dropdown list -->
{% endfor %}
<td><span class="table-constant">{{ticket.status_date}}</span></td>
</form>
<td><span class="table-constant">{{ticket.received}}</span></td>
<td><span class="table-constant">{{ticket.due_date}}</span></td>
<td><span class="table-constant"></span></td>
<td><span class="table-constant">{{ticket.sub_type}}</span></td>
<td><span class="table-vary"></span></td>
<td><span class="table-constant">{{ticket.link}}</span></td>
<td><input type="submit" value="{{ticket.task_description}}"</td>
<td><span class="table-constant"></span></td>
<td><span class="table-constant">{{ticket.qty}}</span></td>
<td></td>
</tr>
{% endfor %}
</table>
</div>

Something like this should do it:
views.py
def update_status(request, ticket_id):
ticket = get_object_or_404(Ticket, pk=ticket_id)
status = request.GET.get(status)
if status:
ticket.status = status
ticket.save()
else:
raise Http404
return HttpResponse({'ticket_id': ticket.id, 'status': ticket.status, content_type='application/json')
And in the template (or remote js file):
<script>
$(document).ready(function(){
$(".statuses").change(function(){
$.ajax({url: "update_status/" + $(this).data("ticket_id) + "/?status=" $(this).val(), success: function(result){
console.log(result);
}});
});
});
</script>
urls.py:
....
url(r'^update_status/(?P<ticket_id>[\d]+)$', update_status),
....
NOTE: You'l need a different ticket id for each of these trs, so I'd add a data-ticket_id = {{ ticket.id }} to each select. That means your {{ field }} is going to have to get more declarative.
Something like:
<select id="status_{{ticket.id}}" class="statuses" data-ticket_id="{{ ticket.id }}" />
{% for k, v in statuses %}
<option value="{{ k }}">{{ v }}</option>
{% endfor %}

What you are asking is totally possible.
The idea:
One way would be to use a javascript function call to update this field (AJAX GET or POST). This script will request a URL managed by the same view, or a new one.
The view would then process the request, return some data for you to parse and optionally confirm that the change what successful, or display an error.
In practice:
You can use for example a jQuery Post, with the URL parameter the one to your view_sheet (or like I said, a new view just for this purpose).
In your view you could play with request.is_ajax(), a test on the request that will be true when it comes from your jQuery post.

What I want to do is when I change the Status dropdown list it should
update the status of the ticket in the database
Instead of this :
status = forms.ChoiceField(label='Status', required=True, choices=statuses, widget=forms.Select(attrs={'onchange': 'actionform.submit();'}))
Try this :
status = forms.ChoiceField(label='Status', required=True, choices=statuses, widget=forms.Select(attrs={'onChange':'this.form.submit()'}))

Related

How to hide entire row if one or two fields are empty Django

How can I hide an entire row if one or more specific fields are empty? For example, I have a django query set up so that I can get a total profit from items in the inventory manager. The way that I have that written is like:
html
{% extends 'portal/base.html' %}
{% block title %}Inventory{% endblock %}
{% block content %}
<br>
<div class="row">
<div class="col">
<form class="d-flex" role="search" action="/search" method="get">
<input class="form-control me-2" type="text" name="q" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success">Search</button>
</form>
</div>
<div class="col">
<a class="btn btn-primary me-md-2" href="/newitem" type="button">Input New Purchase</a>
</div>
</div>
</div>
<table class="table table-striped">
<thead>
<tr>
<th>Breakdown</th>
<th>Product ID</th>
<th>Product</th>
<th>Total Profit</th>
</tr>
</thead>
{% for inventory in inventory %}
<tr>
<td><a class='btn btn-success btn-sm' href=''>View Breakdown</a>
<td>{{inventory.id}}</td>
<td>{{inventory.product}}</td>
<td>{{ inventory.Calculate_profit }}</td>
</tr>
{% endfor %}
</table>
{% endblock %}
views.py
#login_required(login_url="/login")
def profitsperitem(request):
inventory = Inventory.objects.all().order_by('id')
return render(request, 'portal/profitsperitem.html', {"inventory": inventory})
models.py
#property
def Calculate_profit(self):
soldfor = Inventory.objects.filter(soldprice=self.soldprice).aggregate(Sum('soldprice'))['soldprice__sum'] or 0.00
paidfor = Inventory.objects.filter(paid=self.paid).aggregate(Sum('paid'))['paid__sum'] or 0.00
shipfor = Inventory.objects.filter(shipcost=self.shipcost).aggregate(Sum('shipcost'))['shipcost__sum'] or 0.00
totalprofit = soldfor - paidfor - shipfor
return totalprofit
As long as the model fields soldprice , paid , and shipcost are all filled out on every row in the database, I can get the results no problem. I get an error if soldprice or shipcost are null or none, so when there is nothing added to database. If one row does not have soldprice or shipcost set, none of the results can be viewed as this error pops up: "TypeError at /profitsperitem
unsupported operand type(s) for -: 'float' and 'decimal.Decimal'"
My question is how can I hide the entire row if either or both soldprice and/or shipcost are empty?
Tho filter all rows with any of the two fields beeing null/None use a query like this
from django.db.models import Q
#login_required(login_url="/login")
def profitsperitem(request):
inventory = Inventory.objects.filter(
Q(soldprice__isnull = False) | Q(shipcost__isnull = False)
).order_by('id')
return render(request, 'portal/profitsperitem.html', {"inventory": inventory})
I was able to update the view like this
#login_required(login_url="/login")
def profitsperitem(request):
inventory = Inventory.objects.filter(soldprice__isnull = False, shipcost__isnull = False).order_by('id')
return render(request, 'portal/profitsperitem.html', {"inventory": inventory})
{% for inventory in inventory %}
{% if inventory.Calculate_profit %}
<tr>
<td><a class='btn btn-success btn-sm' href=''>View Breakdown</a>
<td>{{inventory.id}}</td>
<td>{{inventory.product}}</td>
<td>{{ inventory.Calculate_profit }}</td>
</tr>
{% endif %}
{% endfor %}
you can print row only if you have calculate price.
if(soldfor is not None and paidfor is not None and shipfor is not None )
totalprofit = soldfor - paidfor - shipfor
else totalprofit =None
Also You can check if Calculate profit has some value

All my rows are still visible eventhough i am filtering

THis my first time using the django filter and i am trying to filter my all my records are still show even do my url says it is filtering the my records- any help will be appreciated
This my filter File
class Clientsearch(django_filters.FilterSet):
class Meta:
model = client
fields ='__all__'
exclude = ['Companyemail','Telephone','address','Postcode','RegNom','UTRno','PAYE','VAT','pensionusername','pensionpassword','companyfilling','authenticationcode','gatewayonlineuserid','gatewayonlinepassword',
'finacialdate',
'confirmationdate',
'agreedfees','updated_at','created_at','datejoined']
This my view.py
def manage_client(request):
clients=client.objects.all()
myFilter = Clientsearch(request.GET,queryset = clients)
context = {'myFilter':myFilter,'clients':clients}
clients = myFilter.qs
return render(request,"admintemplate/manage_client_template.html",context)
This the Html Code for my Table - All the rows are still show but i can see in the url it is filtering
<br>
<div class="row">
<div class="col">
<div class="card card-body">
<form method ="get">
{{myFilter.form}}
<button class="btn btn-primary" type ="submit">Search</button>
</form>
</div>
</div>
</div>
<br>
<div class="row">
<div class="col-md">
<div class="card card-body">
<table class="table table-sm">
<tr>
<th>ID</th>
<th>Company Name</th>
<th>Company Email</th>
<th>Sector</th>
<th>Employee Assigned</th>
<th>Edit</th>
<th>Delete</th>
</tr>
{% for client in clients %}
<tr>
<td>{{client.id}}</td>
<td>{{client.Companyname}}</td>
<td>{{client.Companyemail}}</td>
<td>{{client.sector}}</td>
<td>{{client.username}}</td>
<td>Edit</td>
<td>delete</td>
{% endfor %}
</table>
</div>
</div>
</div>
You are using the queryset you passed clients = client.objects.all(), use the filters queryset which you can access using myFilter.qs, i.e in your template the loop will be:
{% for client in myFilter.qs %}
You need to assign clients = myFilter.qs before you create your context. Doing so after you create the context doesn't change the value that you originally passed to the context (a client.objects.all() queryset)
def manage_client(request):
clients = client.objects.all()
myFilter = Clientsearch(request.GET,queryset = clients)
clients = myFilter.qs # These lines
context = {'myFilter': myFilter, 'clients': clients} # These lines
return render(request, "admintemplate/manage_client_template.html", context)

How to add data to database in loop from multiple textfields in template?

I have to enter marks obtained by all the students in a class. So I created a template with a text field to store the marks corresponding to each roll number. The id of each text field is the roll number of the corresponding student.
How do I pass these marks from each field to views.py so that they can be stored in the database?
I tried using Javascript but I so not know how to access a table in database(class in models) so as to extract the roll number of each student and access the text field.
models.py
class MarksForm(forms.Form):
exam_type = forms.CharField(label='Exam Name', widget=forms.Select(choices=EXAM_TYPES))
entered_marks = forms.FloatField(label='Marks', required=True)
def clean(self):
examtype = self.cleaned_data.get("exam_type")
enteredmarks = self.cleaned_data.get("entered_marks")
return self.cleaned_data
views.py
#csrf_protect
#login_required
def edit_marks(request, course_code):
print ('Inside Views')
user = request.user
extrainfo = ExtraInfo.objects.get(user=user)
if extrainfo.user_type == 'faculty':
instructor = Curriculum_Instructor.objects.filter(instructor_id=extrainfo)
for ins in instructor:
if ins.curriculum_id.course_code == course_code:
registered_students = Register.objects.filter(curr_id = ins.curriculum_id.curriculum_id)
for reg in registered_students:
identity = Register.objects.get(student_id=reg.student_id, curr_id=curriculum[0])
m_id = identity.r_id
student_marks = 'enteredmarks'+identity.student_id
score = request.POST.get(studentmarks)
exam = request.POST.get('examtype')
Marks.objects.create(
mid=m_id,
exam_type=exam,
marks=score
)
context= {'registered_students': registered_students }
return render(request, 'coursemanagement/viewperformance.html', context)
urls.py
urlpatterns = [
url(r'^$', views.viewcourses, name='viewcourses'),
url(r'^(?P<course_code>[A-z]+[0-9]+[A-z]?)/$', views.course, name='course'),
url(r'^(?P<course_code>[A-z]+[0-9]+[A-z]?)/edit_marks$', views.edit_marks, name='edit_marks'),
viewperformance.html
{% load static %}
{% block viewperformance %}
<div>
<form class="ui large form" id="entermarks" method="POST"> {% csrf_token %}
<select name="examtype" id = "examtype" style="width: 100px">
<option value = "1">Quiz 1</option>
<option value = "2">Quiz 2</option>
<option value = "3">Mid Sem</option>
<option value = "4">End sem</option>
</select>
<table class="ui very basic collapsing celled table">
<thead>
<tr>
<th>Students</th>
</tr>
</thead>
<tbody>
{% for x in registered_students %}
<tr>
<td>
<div class="content">
<p style="text-align:center">{{x.student_id}}</p>
var student = x.student_id;
</div>
</td>
<td>
<input type="number" id="enteredmarks{{x.student_id}}" required="true" />
</td>
</tr>
{% endfor %}
</tbody>
</table>
<input type="submit" class="ui primary button" id="submit_marks" value="Upload" href="/ocms/{{course.course_id}}/edit_marks"/>
</form>
</div>
{% endblock %}```
When I try to print something inside view.py, it does not appear. Why is html not getting linked to its corresponding view(edit_marks)?
Best way to do this in django is by using Django Formset
A formset is a layer of abstraction to work with multiple forms on the same page. Which is your requirement.

Django - How to delete a object directly from a button in a table

(sorry for my bad english)
I need to delete an object, but directly from a list of the objects that y have in my template.
I have a work orders, that have spare parts but i don't know how to create the deleteview for the spare parts using only a buton in the detailview of the work order. The idea is that the user make click in the Delete button.
This is the model of the Spare Parts
class OrderSparePart(models.Model):
# Relations
workorder = models.ForeignKey(
WorkOrder,
verbose_name=_('order'),
)
# Attributes - Mandatory
spare_part = models.CharField(
max_length=80,
verbose_name=_('spare part'),
)
# Attributes - Optional
price = models.DecimalField(
max_digits=6,
decimal_places=2,
null=True,
blank=True,
verbose_name=_('price'),
)
# Object Manager
# Custom Properties
# Methods
def get_absolute_url(self):
return reverse('work_orders:detail', kwargs={'order_id': self.workorder.id})
# Meta and String
class Meta:
verbose_name = _("order spare part")
verbose_name_plural = _("order spare parts")
This is where is showed in the template
{% if spare_parts %}
<table class="table">
<thead>
<tr>
<th>{% trans "Spare Part" %}</th>
<th>{% trans "Price" %}</th>
<th>{% trans "Delete" %}</th>
</tr>
</thead>
<tbody>
{% for part in spare_parts %}
<tr>
<td><i class="fa fa-gear"></i> {{ part.spare_part }}</td>
{% if part.price %}
<td>$ {{ part.price }}</td>
{% else %}
<td></td>
{% endif %}
<td><i class="fa fa-trash"></i></td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>NO HAY REPUESTOS ASENTADOS AÚN</p>
{% endif %}
The the idea is use the to delete the spare part.
how i have to make the deleteview and the link to this???
Thanks!
here in fa fa-thrash pass the id and the URL as I did it:-
{% if spare_parts %}
<table class="table">
<thead>
<tr>
<th>{% trans "Spare Part" %}</th>
<th>{% trans "Price" %}</th>
<th>{% trans "Delete" %}</th>
</tr>
</thead>
<tbody>
{% for part in spare_parts %}
<tr>
<td><i class="fa fa-gear"></i> {{ part.spare_part }}</td>
{% if part.price %}
<td>$ {{ part.price }}</td>
{% else %}
<td></td>
{% endif %}
<td></i></td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>NO HAY REPUESTOS ASENTADOS AÚN</p>
{% endif %}
ur url would be sonething like that:
url(r'^delete/(?P<part_id>[0-9]+)/$', view.function, name='delete_view'),
in ur view:
def function(request,part_id =None):
object = YourModel.objects.get(id=part_id)
object.delete()
return render(request,'ur template where you want to redirect')
In your html template inside for loop use the form tag inside <td> to create delete button as below (css class will work if you are using bootstrap3):
<form action="{% url 'delete_view' pk=part.pk %}" method="POST">
{% csrf_token %}
<input class="btn btn-default btn-danger" type="submit" value="Delete"/>
</form>
add urlpattern in urls.py
url(r'^delete-entry/(?P<pk>\d+)/$', views.DeleteView.as_view(), name='delete_view'),
delete view will be like below in views.py
class DeleteView(SuccessMessageMixin, DeleteView):
model = OrderSparePart
success_url = '/'
success_message = "deleted..."
def delete(self, request, *args, **kwargs):
self.object = self.get_object()
name = self.object.name
request.session['name'] = name # name will be change according to your need
message = request.session['name'] + ' deleted successfully'
messages.success(self.request, message)
return super(DeleteView, self).delete(request, *args, **kwargs)
Note: import necessary imports shown in links or you need not to worry if you are using IDE such as pyCharm it will prompt you which import to make.
My solutions works best for django 4.0.3 and is the combination of gahan and Abi waqas answers. Use this one if you are using django 3 or above
Add the following to views.py
def delete_object_function(request, id):
# OrderSparePart is the Model of which the object is present
ob = OrderSparePart.objects.get(id=id)
ob.delete()
return redirect('page-delete.html') # for best results, redirect to the same page from where delete function is called
Add the following to urls.py
path('page-delete/<int:id>', views.delete_object_function, name='delete_object'),
Add the following code to the django template from where the delete function is to be called.
Let's say page-delete.html
<form action="{% url 'delete_object' id=part.id %}" method="post">
{% csrf_token %}
<button class="btn btn-danger" type="submit" ><i class="fa fa-trash"></i></button>
</form>
This works as I've used this solution in my own code.

How do I set value to hidden integerfield in WTForms

I have a form which needs to take in 1 integer value. This integer value will be an id associated with a row in a html table.
template.html
{% block content %}
<div id="formContainer" class="center top">
<p class="lead">Select simulation session </p>
{% if simulationSessions %}
<table class="table table-striped">
<thead>
<tr>
<th></th>
<th>#</th>
<th>Label</th>
<th>Date</th>
</tr>
</thead>
<tbody>
{% for simulationSession in simulationSessions %}
<tr>
<td><input id="id-{{ simulationSession.id }}" name="idRadio" type="radio" value="{{ simulationSession.id }}"> </td>
<td>{{ simulationSession.id }}</td>
<td>{{ simulationSession.label }}</td>
<td>{{ simulationSession.date.strftime('%d-%m-%y %H:%M') }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<button type="button" class="btn btn-sm btn-success">Analyse</button>
{% else %}
<div class="alert alert-danger" role="alert">
<strong>Oopsadazy!</strong> No simulations are registered in the database for this user. You need to run a simulation session before analyzing it!
</div>
{% endif %}
</div>
{% endblock %}
Each table row has a radio button, and the value from the selected button will be the only thing my form requires. I have decided to go with one hidden IntegerField instead of a RadioField. It is possible to do the latter but then I have to solve the problem of dynamically creating the choices (I decided to go against that when I couldn't pass the list as a parameter when referencing the form from my view.py).
form.py
class SimulationSessionSelectionForm(Form):
simulationSessoinId = IntegerField('simulationSessoinId', validators=[DataRequired()], widget=HiddenInput())
My questions is how can I take the value from the selected radio button and use that as the data for the hidden integer field once the form is submitted?
This could maybe be done with something similar to this inside a script within the html? (this does not compile)
{% set form.id.data %}
this.value
{% endset %}
The view would look something like this:
view.py
#app.route('/dashboard', methods=['GET', 'POST'])
#login_required
def dashboard():
form = SimulationSessionSelectionForm()
if form.validate_on_submit():
redirect('/somewhere')
userkey = models.User.query.filter_by(id = current_user.get_id()).first().userKey
userSimulationSessions = models.SimulationSession.query.filter_by(userKey = userkey).all()
simulationSessions = []
simulationSessionIds = []
for simulation in userSimulationSessions:
simulationSessions.append({'id' : simulation.sessionID, 'label' : simulation.label, 'date' : simulation.date})
simulationSessionIds.append(simulation.sessionID)
return render_template("dashboard.html", simulationSessions = simulationSessions, form = form)
This line in the template adds the hidden field (and the csfr token) to the
{{ form.hidden_tag() }}
I figured I could just set the value of the hidden IntegerField by some jquery script whenever the radio button change event fired. To do this I used the following code:
<script>
$( document ).ready(function() {
$('input[type=radio][name=idRadio]').change(function() {
$('#simulationSessoinId').val(this.value)
});
});
</script>