reload page automatically without needing to RE-enter URL again Django - python

My webpage consists of 2 parts, upper part is a section that let user to enter data while bottom part displays all the data in database in a table form. When user selects "Add" button in the upper part, the data will be saved into database and being outputted in a table in bottom part of the webpage. Is there anyway to show the table once i select the "Add" button ? Right now what the code is doing is when "Add" button is being selected, it will load a new form but then the whole table will disappear. I have to manually type this address again "http://127.0.0.1:8000/hrfinance/lscholarship/" then only the table will appear. Even with refreshing the page will not work. Below is my code in
views.py:
def scholarship(request, id=None):
query_results = []
if request.method == "POST":
form = ScholarshipForm(request.POST)
if form.is_valid():
scholarship = form.save(commit=False)
scholarship.save()
else:
form = ScholarshipForm()
id = request.GET.get('scholarship')
query_results = Scholarship.objects.all()
data = {
'query_results':query_results,
'form': form
}
return render(request, 'hrfinance/add_remove_scholarship.html', data)
models.py
class Application(models.Model):
studentID = models.CharField("Student ID", max_length=8, validators=[MinLengthValidator(8)], primary_key=True, default="")
studentName = models.CharField("Student Name", max_length=500, default="")
scholarship = models.TextField("Scholarship")
add_remove_scholarship.html
<div align="center" >
<form method="POST" onsubmit="return validation()" action="">
{% csrf_token %}
{{ form.errors }}
<p>Upload File: {{ form.doc }}</p>
<p>Faculty: {{ form.faculty }} </p>
<p>Opening date: <input id="odate" type="date" name="openDate"> </p>
<p>Closing date: {{ form.closeDate }} </p>
<input type="submit" name="AddScholarship" value="Add Scholarship" >
</form>
</div>
<br></br>
<button id="button" type="button">Delete Selected Scholarship</button>
<br></br>
{{query_results}}
<form method="POST" action="">
{% csrf_token %}
<table id="example" class="display" cellspacing="0" width="100%" border="1.5px">
<tr align="center">
<th> Scholarship </th>
<th> Faculty </th>
<th> Open Date </th>
<th> Close Date </th>
</tr>
{% for item in query_results %}
<tr align="center">
<td>{{item.doc}}</td>
<td>{{item.faculty}}</td>
<td>{{item.openDate}}</td>
<td>{{item.closeDate}}</td>
</tr>
{% endfor %}
</table>
</form>

Best practice is to use the Post/Redirect/Get pattern. This will solve your problems as well: the GET request will clear the form and show the new query results.
If the form is successfully saved, you simply return a redirect to the current page. The browser will then do a GET request. This prevents accidental duplicate form submissions when e.g. the user reloads the current page when it is still a POST request:
from django.shortcuts import redirect
def scholarship(request, id=None):
query_results = []
if request.method == "POST":
form = ScholarshipForm(request.POST)
if form.is_valid():
scholarship = form.save(commit=False)
scholarship.save()
# Return a redirect to the same page
return redirect('/path/to/current/page/')
...

def scholarship(request, id=None):
query_results = []
if request.method == "POST":
form = ScholarshipForm(request.POST)
if form.is_valid():
scholarship = form.save(commit=False)
scholarship.save()
else:
id = request.GET.get('scholarship')
query_results = Scholarship.objects.all()
form = ScholarshipForm()
data = {
'query_results':query_results,
'form': form
}
return render(request, 'hrfinance/add_remove_scholarship.html', data)
you need to move the query out side the else condition.
Although, this method would take a lot of time as the number of rows in the database increases. A better method to do this would be to use jquery Ajax method to update the data in the database and show it dynamically using javascript/Jquery once the database is updated.

Related

Can’t loop value in html table

I’m building a function which can let admin to delete account in that page.
I have several accounts in admin page but all the delete buttons are holding a value from first account in that page instead of other account.
<form action="/admin" method="post">
<table class="table">
<thead class="table-dark">
<tr>
<th>Users</th>
</tr>
</thead>
{% for user in users %}
<tr style="background-color:burlywood">
<td><input type="hidden" name="user" value="{{user.username}}">{{user.username}}</td>
<td><input type="submit" for="user" value="Delete"></td>
{% endfor %}
</tr>
</table>
#app.route("/admin", methods=["GET", "POST"])
#login_required
def admin():
"""Manage account"""
if request.method == "GET":
user_id = session["user_id"]
admin = db.execute("SELECT id FROM users WHERE id = (?)",
user_id)
for row in admin:
if int(row["id"]) == 17:
users = db.execute("SELECT username FROM users")
return render_template("admin.html", users = users)
else:
return apology("Only Admin can access this page!")
return apology("valid return")
else:
username = request.form.get("user")
flash(f"{username} has been deleted!")
return redirect("/")
I expected each delete button is holding each value in column.
After the issue is fixed, when delete button is clicked flash function will show the different username based on the value not admin at all.
here is html page
From the tags I believe you're using Jinja to load and render the html page, however, you should be more clear about what you want to ask.
This may sound like a bad idea and definitely something you shouldn't do in production but how about creating different forms for each user?
Something like this :
<table class="table">
<thead class="table-dark">
<tr>
<th>Users</th>
</tr>
</thead>
{% for user in users %}
<form action="/admin" method="post">
<tr style="background-color:burlywood">
<td><input type="hidden" name="user" value="{{user.username}}">{{user.username}}</td>
<td><input type="submit" for="user" value="Delete"></td>
</tr>
</form>
{% endfor %}
</table>
I think your line only returns usernames in your users variable:
users = db.execute("SELECT username FROM users")
So users in your template is an array that only contains a list of names, or only contains one name.
1 / Whats contains users?
2 / what if you put {{ user }} instead of {{ user.username }} in your template?

How to compare user input to corresponding model field django

I'm trying to make learning app for myself and part of my plan is to make a quiz module.
My problem is, that I don't know how to compare user answer with the correct answer that's stored in the model.
Now, the only thing I've tried (except reading docs and stack overflow) was to inject the related model question inside of my HTML to later use in views.py, but from the beginning I felt like that's not the way it should work, so I guess I have to reorganize my models/forms or inside of views.py there is some way to query database for that specific model instance that I don't know.
Here is my code
Models:
class Question(models.Model):
question = models.CharField(max_length=100, unique=True)
answer = models.CharField(max_length=100, unique=False)
def __str__(self):
return self.question
Forms:
class Answer(forms.Form):
answer = forms.CharField()
Views:
def quiz(request):
questions = Question.objects.order_by('question')
form = Answer()
context_dict = {'form':form,'questions':questions}
if request.method == 'POST':
form = Answer(request.POST)
if form.is_valid():
#Here I want to make the comparison
pass
return render(request,"quiz_app/quiz.html",context_dict)
HTML:
<table>
{% for q in questions %}
<tr>
<td>{{ q.question }}</td>
<form method="POST">
<td>{{ form.answer }}</td>
{% csrf_token %}
<td>
<input type="submit" value="submit">
</td>
</form>
</tr>
{% endfor %}
</table>
You can pass the question_id with the post request and then get the question instance and compare the results.
HTML:
<form method="POST">
<td>{{ form.answer }}</td>
{% csrf_token %}
<input type="hidden" name="q_id" value="{{ q.id }}" />
<td>
<input type="submit" value="submit">
</td>
</form>
views:
def quiz(request):
questions = Question.objects.order_by('question')
form = Answer()
context_dict = {'form':form,'questions':questions}
if request.method == 'POST':
instance = Question.objects.get(id=request.POST['q_id'])
form = Answer(request.POST, instance=instance)
if form.is_valid():
#Here I want to make the comparison
if request.POST.get("answer").strip() == instance.answer:
# used strip() to remove whitespace before and after the text.
# other logic.
return render(request,"quiz_app/quiz.html",context_dict)

Django create instance from views.py not working

I have a Django app that is basically a list app for tracking jobs that the user is applying for. Users have applications and applications have questions that the user wants to ask to the interviewers should they get an interview. So I have created a many to many relationship between the models 'Application' and 'Question' called 'Ask'. Models.py:
class Application(models.Model):
status_choices = (
('NS','Not Started'),
('IP','In Progress'),
('OH','On Hold'),
('CO','Complete'),
)
app_status = models.CharField(max_length=2,choices=status_choices)
position = models.CharField(max_length=255)
company = models.ForeignKey(Company)
applied_date = models.DateField(null=True)
isDeleted = models.BooleanField(default=False, blank=True)
user = models.ForeignKey(User)
def __str__(self):
return self.position
class Questions(models.Model):
question = models.CharField(max_length=255)
category = models.CharField(max_length=25)
isDeleted = models.BooleanField(default=False, blank=True)
class Ask(models.Model): #joining table
question = models.ForeignKey(Questions)
app = models.ForeignKey(Application)
isDeleted = models.BooleanField(default=False, blank=True)
So the idea is that the user creates a list of questions and then when they get an interview, they prepare for it by looking at their list of questions and assigning them to the application through a template. Questions.html:
{% extends 'base.html' %}
{% block body %}
<h1> Questions </h1>
<div class="table-responsive" align="center">
<table class="table-hover" width="75%">
<tr>
<th> Category </th>
<th> Question </th>
<th> Create Question</th>
<form method="POST">
{% csrf_token %}
<input type="text" name="app" value="{{ request.META.HTTP_REFERER }}">
<th><input type='submit' value='Add Selected'></th>
</tr>
{% for item in query %}
<tr>
<td> {{ item.category }} </td>
<td> {{ item.question }} </td>
<td> <input type="checkbox" name="selected_q" value="{{ item.id }}"></td>
<td> Delete </td>
<td> Edit </td>
</tr>
</form>
{% endfor %}
</table>
</div>
{% endblock %}
Which is called from views.py:
class QuestionView(TemplateView):
template_name = 'question.html'
def get(self, request):
query = Questions.objects.all().order_by('category')
args = {'query': query}
return render(request, self.template_name, args)
def post(self, request):
id_list = request.POST.getlist('selected_q')
return_url = request.POST.get('app')
app = int(return_url.rsplit('/')[-1])
myApp = Application.objects.get(pk=app)
if id_list != None:
for item in id_list:
myQuestion = Questions.objects.get(pk=int(item))
Ask.objects.create(app=myApp,question=myQuestion)
return HttpResponseRedirect(return_url)
else:
query = Questions.objects.all().order_by('category')
args = {'query': query}
return render(request, self.template_name, args)
The user can only get to the questions page by going through the Application view and when that happens Questions.html captures the link that the user came from. Users then select one or more questions through a checkbox on questions.html which is captured in the post as id_list - So this should give me the two keys I need to create an instance of Ask.
However, when trying to do this it looks like everything works properly, but no instance of Ask is created and I don't get any error messages. I have tried creating a record from the python shell and it works just fine. I have also tried other methods such as using a form and instantiating Ask to call .save() afterwards, but it does not insert a record. For testing, I took out the query in views.py to check to make sure valid values are getting passed to myApp and myQuestion, so I believe that the data is all there and accurate, but it isn't creating a record for some reason.
I appreciate any help you might offer, or maybe just different ideas on how to debug this problem so I can get some error messages.
Blurb was right - wrapping the table in the form tag resolved the issue. Thanks!

Why the django form data cannot display after submitting

After submitting the form (input), it will redirect to another page(result) and show the form information in this result page.
The problem now is that the submitted information doesn't show in the result page.
I doubt the reason is because in result' views.py, I want to show the submitted form from Input,but the form's data is not saved or I shouldn't fetch the data from the model,I should fetch the data from view,so it cannot display the table:
context['input'] = Input.objects.all()
Please correct me if my guess is right or not. Thanks in advance for your suggestion.
input- models.py
class Input(models.Model):
company=models.CharField(max_length=100,default='Empty')
region=models.CharField(max_length=100,default='Empty')
start_date=models.DateField(auto_now=False, auto_now_add=False,default='Empty')
end_date=models.DateField(auto_now=False, auto_now_add=False,default='Empty')
input -- form
class Inputform(forms.ModelForm):
company=forms.CharField()
regionlist = forms.ModelChoiceField(queryset=Result.objects.values('region').distinct())
start_date=forms.DateField(widget=DateInput(),required=True)
end_date = forms.DateField(widget=DateInput(),required=True)
class Meta:
model = Input
fields = ('company', 'region','start_date','end_date')
widgets = {
'start_date': forms.DateInput(attrs={'class':'datepicker'}),
'end_date': forms.DateInput(attrs={'class':'datepicker'}),
}
input -- part of the html code
<form action="result_list/" method="post">{% csrf_token %}
<!--enter company-->
<div class="field">
<p>Company:<input type="text" name="Company" value="{{company}}"/>
</div>
<!--select region-->
<div class="field" >
<label> Select the Region:
{{ form.regionlist }}
{% for region in form.regionlist.choices %}
<option value="{{ val }}" {% ifequal data.val val %}selected {% endifequal %}></option>
{% endfor %}
</label>
</div>
....
<div class="fieldWrapper">
<p><input type="submit" value="Submit" /></p></div>
</form>
input --views
from django.http import HttpResponseRedirect
from django.shortcuts import render,render_to_response,get_object_or_404
from inputform.forms import Inputform
from inputform.models import Input
from result.models import Result
from django.views.decorators.csrf import csrf_exempt
from django.views.generic.list import ListView
#csrf_exempt
def input(request):
if request.method == 'POST':
form = Inputform(request.POST)
if form.is_valid():
cd = form.cleaned_data
print (cd['company'])
form.save()
return redirect('result')
urls
from inputform import views
from django.views.generic.list import ListView
from inputform.views import input
from django.views.generic import RedirectView
urlpatterns = patterns('',
url(r'^result_list/$',ResultView.as_view(),name='result'),
(r'^input/$', RedirectView.as_view(url='/result_list/')),
}
Result --views.py
class ResultView(ListView):
context_object_name = 'result_list'
template_name = 'result_list.html'
queryset = Result.objects.all()
def get_context_data(self, **kwargs):
context = super(ResultView, self).get_context_data(**kwargs)
context['input'] = Input.objects.all()
return context
Result -- html
{% for input_object in input %}
<table border="1" cellpadding="1">
<tr>
<td align="left">Company</td>
<td>{{input_object.company}}</td>
</tr>
<tr>
<td align="left">Region</td>
<td>{{input_object.region}}</td>
</tr>
...
</table>
{% endfor %}
Your code looks rather messy. Its not clear, how you initially pass the empty form to input template.
However, the problem may arise cause you do not pass the whole form to your template, but only {{ form.regionlist }}. So your inputs cannot write any data to db.
Render either the whole {{ form }} or each field one by one as you've done for regionlist field.
Moreover, you do not need to dublicate model field in forms.py if it does not actually override somehow the original field in models.py.
The root cause is actually in url.py:
Should delete "(r'^input/$', RedirectView.as_view(url='/result_list/')),",only to put redirect in views.py is enough.

Flask - Submit Button Actioning Database Update

I think I may have been at it too long today and I can't wrap my head around this very well. I am fairly new to python and have been playing with flask for about a week, this is my first 'real' app that I have built so please be gentle.
The app allows an internal customer (datatechs) to enter their ticket number and login into a form. That form is submitted and kept in a sqlite DB for now, with an ID, ticket#, login, create_time and an active flag.
On another page I have what could be called a management list, this renders all the tickets that are currently in the database and marked as active. I have populated this with a jinja2 for loop and have a button that resides inline.
For example:
[ 1 ] [ ticket number ] [ login ] [ button ]
[ 2 ] [ ticket number ] [ login ] [ button ]
The button is my issue. I am very unsure about how I can have the specific button clicked cause an action against that entry in the database. I am looking to flip the status field from an int of 1 to 0 (true and false works too), so these can be essentially marked as complete but still available for analytics.
Thanks for reading, here are some snippets.
views.py
#app.route('/', methods=['GET', 'POST'])
def index():
form = TicketForm()
ticket = Ticket.query.filter_by(status=1)
if request.method == 'GET':
return render_template('index.html', form=form, ticket=ticket)
elif request.method == 'POST':
if form.validate() == False:
flash('All fields are required, please update and try again.')
return render_template('index.html', form=form, ticket=ticket)
else:
remedy = Ticket(request.form['tt'], request.form['login'], create=datetime.datetime.utcnow(), status=1)
db.session.add(remedy)
db.session.commit()
flash('Your ticket has been added to the queue')
return redirect(url_for('index'))
#app.route('/manage', methods=['GET'])
def manage():
if request.method == 'GET':
ticket = Ticket.query.all()
return render_template('manage.html', ticket=ticket)
models.py
class Ticket(db.Model):
id = db.Column(db.Integer, primary_key=True)
tt = db.Column(db.String(10))
user = db.Column(db.String(20))
create = db.Column(DateTime, default=datetime.datetime.utcnow)
status = db.Column(db.Integer)
def __init__(self, tt, user, create, status):
self.tt = tt
self.user = user
self.create = create
self.status = status
manage.html
{% extends "base.html" %}
{% block content %}
<table class="table" width=50%>
<thead>
<tr>
<th>#</th>
<th>Ticket Number</th>
<th>Requester Login</th>
<th>Time Requested (UTC)</th>
<th>Cancel Request</td>
</tr>
</thead>
<tbody>
{% for ticket in ticket %}
<tr>
<td>{{ ticket.id }}</td>
<td>{{ ticket.tt }}</td>
<td>{{ ticket.user }}</td>
<td>{{ ticket.create }}</td>
<td><button type="button" class="btn btn-xs btn-danger">Kill</button></td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
Generally you'd add another view to handle the flip. A note of caution is that some browser helpers preload 'normal' links on webpages to check for viruses and try helpful caching, so avoid using simple links for links that can change data. So we'll use a form instead:
change your <td><button type="button" class="btn btn-xs btn-danger">Kill</button></td> to:
<td>
<form action="{{ url_for('flip') }}" method="post">
<input type="hidden" name="flip" value="{{ ticket.id }}"/>
<input type="submit" class="btn btn-xs btn-danger" value="Kill"/>
</form>
</td>
Then add a view to do the heavy lifting:
#app.route('/flip', methods=['POST'])
def flip():
ticket = Ticket.query.filter_by(id=request.form["flip"]).first_or_404()
ticket.status = 0
db.session.commit()
return redirect(url_for('index'))
So we're just catching the id and seeing if it exists in the database, and if so, we'll flip the status to 0 and then redirect (from flask import redirect) the user back to the index view.

Categories

Resources