How to get Flask to save user input for radio button? - python

So I am trying to create an interactive quiz application using Flask. However, the issue I am running into is that I can't seem to save and output what the user selected. I tried to fix the quiz_answers function in the app.py and the quiz_solutions.html jinja2 syntax, but got an output that I did not want.
Example Question: What is 2+2?
Multiple choice: Option 1: 4, Option 2: 5, Option 3: 6, etc.
What I want the html page to show:
User selected: Option 2: 5
Correct Answer: Option 1: 4
Here is a what I currently have for app.py:
from flask import Flask, render_template, request
import random, copy
import questions
app = Flask(__name__)
copy_questions = copy.deepcopy(questions.original_questions)
def shuffle(q):
"""
This function is for shuffling
the dictionary elements.
"""
selected_keys = []
i = 0
while i < len(q):
current_selection = random.choice(list(q.keys()))
#current_selection = list(q.keys())
if current_selection not in selected_keys:
selected_keys.append(current_selection)
i = i+1
return selected_keys
questions_shuffled = shuffle(copy_questions)
#app.route('/')
def quiz():
#questions_shuffled = shuffle(copy_questions)
for i in copy_questions.keys():
random.shuffle(copy_questions[i])
return render_template('main.html', q = questions_shuffled, o = copy_questions)
#app.route('/solution', methods=['POST'])
def quiz_answers():
for i in copy_questions.keys():
answered = request.form[i]
if questions.original_questions[i][0] == answered:
return render_template('quiz_solutions.html',q = questions_shuffled, o = copy_questions)
break
if __name__ == '__main__':
app.run(debug=True)
questions.py:
original_questions = {
'What is 2+2': ['Option 1: 4', 'Option 2: 5', 'Option 3: 6',' etc.']
}
main.html:
<h1>Math Quiz</h1>
<form action='/solution' method='POST'>
<!--<form action='/' method='POST'>-->
<ol>
{% for i in q %}
<li>{{i}}</li>
{% for j in o[i] %}
<input type='radio' value='{{j}}' name='{{i}}' />{{j}}
<br>
{% endfor %}
<br>
{% endfor %}
<br>
<input type="submit" value="Submit" />
</ol>
</form>
quiz_solutions.html:
<h1>Math Quiz</h1>
<form method='POST'>
<ol>
{% for i in q %}
<li>{{i}}</li>
{% for j in o[i] %}
<input type='radio' value='{{j}}' name='{{i}}' />{{j}}
<br>
{% endfor %}
{% for j in o[i] %}
{% if j== o[i][0] %}
Correct answer: {{j}}
{% else %}
{% endif %}
{% endfor %}
<br>
{% endfor %}
</ol>
</form>

Related

django terminate adding any input to the database from the form

In an auction web. I'm trying to terminate adding any input (bids, comments and add to watchlist) by any user to the database if the owner of the product press on 'close ' button so I tried to implement this pseudo code:
in views.py
function listing:
t = 1
if t == 1:
if owner clicks on the close button:
...
t = 2
if the user adds a comment:
...
if the user adds a bid:
...
if user clicks on add to watchlist button:
...
else:
return message ('Auction has ended')
I have implemented this code and the listing page accepted entries and inputs after the owner of the listing clicked on the 'close' button. I also tried to change the value of t to a boolean value ( t = True, if t == True, if user clicked: return t = False) but it didn't work. so what is the problem.
def entry(request, name):
enter = listing.objects.get(title = name)
f= bids.objects.filter(product_id = enter)
x = 0
z = ""
last = None
ended = None
like = "k"
t = 1
if t == 1:
if request.method == 'POST' and request.POST.get("bid"):
biddd = int(request.POST['bid'])
user = request.user
if biddd > x:
bids.objects.create(bid= biddd , product_id= listing.objects.get(title = name).id, user = user)
for object in f:
if object.bid > x:
if object.bid > x:
x = object.bid
if request.method == 'POST' and request.POST.get('close_bid'):
final = listing.objects.get(title = name)
last = bids.objects.get(bid = x, product = final).user
t = 2
elif request.method == 'POST' and request.POST.get("bid"):
bidd = int(request.POST['bid'])
if bidd >= x:
messages.info(request, 'bid accepted')
z = "#0a720e"
else:
messages.info(request, 'bid already present')
z = "#f44336"
elif request.method == 'POST' and request.POST.get("watchlist"):
if request.user.is_authenticated:
productt = listing.objects.get(title = name)
user = request.user
exist = watchlist.objects.filter(product = productt, user = user)
if exist.exists():
messages.info(request, 'Already added to your watchlist')
else:
watchlist.objects.create(product = productt, user = user)
else:
return render(request, "auctions/login.html")
elif request.method == 'POST' and request.POST.get("comments"):
if request.user.is_authenticated:
comment = request.POST['comments']
product = listing.objects.get(title = name)
user = request.user
comments.objects.create(comment = comment, user = user, product = product)
else:
return render(request, "auctions/login.html")
commentproduct = listing.objects.get(title = name)
commentss= comments.objects.filter( product = commentproduct)
else:
messages.info(request, 'Auction has ended')
return render(request, "auctions/entry.html" , {"enter":enter, "bid": f, "x": x, "z":z, "comments":commentss, "winner": last, "ended": ended, "l": l})
in entry.html:
{% extends "auctions/layout.html" %}
{% load static %}
{% block body %}
<h1>Listing: {{enter}}</h1>
<img src="{{enter.image}}">
<p>{{enter.description}}</p>
<h3>Current Bid: {{x}}</h3>
<form action = "#" method="POST">
{% csrf_token %}
<label>Add bid:</label>
<input type="number" name="bid">
<input type="submit">
</form>
{% for message in messages %}
<div class="alert" style="background-color:{{z}}">
<span class="closebtn" onclick="this.parentElement.style.display='none';">×</span>
{{message}}
</div>
{% endfor %}
<form method='POST' action='#'>
{% csrf_token %}
<button type="submit" name="watchlist" value="Add to watchlist"> Add to watchlist</button>
</form>
{% for message in messages %}
<h5>{{message}}</h5>
{% endfor %}
<h2>Details:</h2>
<p><strong>Owner:</strong> {{enter.author}}</p>
<p><strong>Category:</strong> {{enter.category}}</p>
<br>
<h2>Add a comment:</h2>
<form method="POST" action="#">
{% csrf_token %}
<textarea name="comments" placeholder="Add a comment" style="width:600px"></textarea>
<input type="submit" value="Add comment">
</form>
{% if user.is_authenticated and user == enter.author %}
<form method='POST' action='#'>
{% csrf_token %}
<button type="submit" name="close_bid" value="Close bid"> Close Bid</button>
</form>
{% endif %}
<h2>Comments:</h2>
{% for comment in comments %}
<h3>{{comment.user}}:</h3>
<p>{{comment.comment}}</p>
{% endfor %}
{% if user.is_authenticated and user == winner %}
<div class="alert" style="background-color:green">
<span class="closebtn" onclick="this.parentElement.style.display='none';">×</span>
You won!
</div>
{% elif not user.is_authenticated %}
<p></p>
{% else %}
<div class="alert" style="background-color:red">
<span class="closebtn" onclick="this.parentElement.style.display='none';">×</span>
You lost!
</div>
{% endif %}
{% if user.is_authenticated and user == winner %}
<p>
You won!
</p>
{% elif not user.is_authenticated %}
<p>.</p>
{% else %}
<p>you lost</p>
{% endif %}
{% endblock %}

Elasticsearch Python Django: How to limit the output text content and highlight the input keyword

This is my search function in views.py
def search(request, pk, slug):
es = Elasticsearch()
es_client = Elasticsearch(['http://127.0.0.1:9200'])
print('called search')
search_text = request.GET.get('qq')
print('Search text: {}'.format(search_text))
print('cluster id/ ealstic search index: {}'.format(pk))
s = None
count = 0
try:
if search_text:
s = Search(index=str(pk)).using(es_client).query("match", content=search_text)
response = s.execute()
count = 0
for hit in s:
count += 1
print(str(count) + ' - ' + str(hit.currnet_url))
#print(hit.content)
else:
print('nothing more found')
else:
print('No text to search')
except Exception as e:
count = 0
print('Exception caught')
msg = 'Cluster is not ready to be searched'
return render(request, 'base_app/cluster_search.html', {'warning':msg, 'count':count})
return render(request, 'base_app/cluster_search.html', {'cluster':slug, 'hits':s, 'count':count})
This is how I am indexing data to Elasticsearch.
def elastic_indexer(text, depth, url, clusrer_id):
es_client = Elasticsearch(['http://127.0.0.1:9200'])
doc = {
"date": time.strftime("%Y-%m-%d"),
"currnet_url": url,
"depth": depth,
"content": text
}
res = es_client.index(index= str(clusrer_id), doc_type="_doc", body=doc)
print(res["result"])
This is the frontend template where the users input a text to search.
{% extends "account/base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block head_title %}{% trans "Search" %}{% endblock %}
{% block content %}
Go Back
<P style="font-size:17px;">You are searching in {{cluster.title}}</P>
<form method="GET" action="">
{% csrf_token %}
<button class="btn btn-primary" action="">Search</button>
<input id="q" name="qq" type="text" placeholder="enter search text here" style="width: 500px;">
</form>
{% if hits %}
<table>
{% for hit in hits %}
<tr>
<td>Hit: {{hit.currnet_url}}</td>
</tr>
<tr>
<td>Content: {{hit.content}}</a></td>
</tr>
{% empty %}
<h3> No search result found </h3>
{% endfor %}
</table>
{% endif %}
<div class="pagination">
<span class="step-links">
{% if page_obj.has_previous %}
« first
previous
{% endif %}
<span class="current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
next
last »
{% endif %}
</span>
</div>
{% endblock %}
This is returning everything, all the text stored in "content", how do I limit this to only the user's input text and only show limited characters before and after the input text? and including highlighting the input text? Please help me out
Example:
What it shows:
*User inputs text, assuming it's "django"*
hits: https://www.djangoproject.com/
Content: all of the scraped text stored in "content"
What I want it to show:
User inputs text, assuming it's "django"
hits: https://www.djangoproject.com/
Content: 10 words before "django" and 10 words after "django"

How to create for and if loop for inputs in jinja flask

I have a python snippet to append a list, and returning it back as a string. The input box will pop up one by one until end for. This snippet works just fine.
x=4
list=[]
for i in range(1,x):
for j in range(1,x):
if i<j:
a = input(' {} vs {} ?: '.format(i,j))
list.append(a)
string = " ".join(str(x) for x in list)
print(string)
Output:
1 vs 2 ?: 1
1 vs 3 ?: 1
2 vs 3 ?: 1
1 1 1
However I want to use it in flask, how can I apply this in jinja with correct syntax? here's what i've tried so far and it didn't work:
def function():
if request.method == 'POST':
x = 4
list = []
a = request.form["a"]
list.append(a)
string = " ".join(str(x) for x in list)
return render_template('index.html', x=x, a=a, string=string)
return render_template('index.html')
and the template:
<form method="post" action="{{ url_for('function') }}">
<div>
{% for i in range(1, x) %}
{% for j in range(1, x) %}
{% if i < j %}
<p>' {} vs {} ?: '.format(i,j)</p>
<input type="text" name="a" id="a">
<div class="input-group-append">
<button class="btn type="submit" value="Submit">Enter</button>
</div>
{% endif %}
{% endfor %}
{% endfor %}
</div>
</form>
{{string}}
You can use the getlist function to query all the values of the input fields with the same name attributes.
#app.route('/', methods=['GET', 'POST'])
def index():
x = 4
if request.method == 'POST':
data = request.form.getlist('a', type=str)
rslt = ' '.join(data)
return render_template('index.html', **locals())
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<form method="post">
{% set ns = namespace(idx=0) %}
{% for i in range(1,x) %}
{% for j in range(i+1,x) %}
<div>
<label>{{ '{} vs {}'.format(i,j) }}</label>
<input type="text" name="a" value="{{data and data[ns.idx]}}" />
</div>
{% set ns.idx = ns.idx + 1 %}
{% endfor %}
{% endfor %}
<input type="submit" />
</form>
{% if rslt %}
<output>{{ rslt }}</output>
{% endif %}
</body>
</html>
You can also write it a little shorter.
from itertools import combinations
#app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
data = request.form.getlist('a', type=str)
rslt = ' '.join(data)
x = 4
pairs = combinations(range(1,x), 2)
return render_template('index.html', **locals())
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<form method="post">
{% for i,j in pairs %}
<div>
<label>{{ '{} vs {}'.format(i,j) }}</label>
<input type="text" name="a" value="{{data and data[loop.index0]}}" />
</div>
{% endfor %}
<input type="submit" />
</form>
{% if rslt %}
<output>{{ rslt }}</output>
{% endif %}
</body>
</html>

Counter increment in template outside of for loop

I need to do a counter increment within a loop. I had a look at django for.counter, but unfortunately, my increments dont exactly occur within each iteration of the loop. So is there any way at all that I can implement increment of a variable within django template, without going to great pains to implement a new object in my code to do this without such an increment?
In the following code, I am writing the lines {{ count = 0 }}, {{ count += 1 }} just for illustration purpose. I know it wont work. The following is a very simplified form of my template:
<div class="jumbotron slotgroup slotavailable mb-1 mt-5" id="jumbo_week_avail">
<div class="slot-header" role="alert">
Headertext
</div>
{% if weeklyslotsav %}
{% for day,daynum in weekzip %}
{{ count = 0 }}
{% if daynum in weeklyslotsav.day %}
{% for weekslotav in weeklyslotsav %}
{% if weekslotav.day == daynum %}
<div class="row row_week_avail{{ weekslotav.day }}" id="row_week_avail{{ weekslotav.day }}_{{ count }}">
</div>
{{ count += 1 }}
{% endif}
{% endfor %}
{% else %}
<div class="row row_week_avail{{ daynum }}" id="row_week_avail{{ daynum }}_0">
</div>
{% endif %}
{% endfor %}
{% else %}
{% for weekday, weeknum in weekzip %}
<div class="row row_week_avail{{ weeknum }}" id="row_week_avail{{ weeknum }}_0">
</div>
{% endfor %}
{% endif %}
</div>
The following is a segment from my views:
def edit_doctorslots(request, cliniclabel, doctor_id):
doctor_id=int(doctor_id)
doc = get_object_or_404(doctor, docid=doctor_id)
cl = Clinic.objects.get(label=cliniclabel)
print("Clinic name", cl.name)
regularslotsav = ''
try:
regularslotsav = Timeslots.objects.filter(clinic =cl, doctor =doc, available =True)
except:
pass
regularslotsbr = ''
try:
regularslotsbr = Timeslots.objects.filter(clinic =cl, doctor =doc, available =False)
except:
pass
weekavzip = ''
try:
weeklyslotsav = Weekdays.objects.filter(clinic =cl, doctor =doc, available =True)
weekav = range(0, len(weeklyslotsav))
weekavzip = list(zip(weeklyslotsav, weekav))
except:
pass
weeklyslotsbr = ''
try:
weeklyslotsbr = Weekdays.objects.filter(clinic =cl, doctor =doc, available =False)
except:
pass
formslot = SlotForm()
formspecialdays = SpecialdaysForm()
formweekdays = WeekdaysForm()
weekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
weekdaynum = [0,1,2,3,4,5,6]
weekzip = list(zip(weekdays, weekdaynum))
newweekzip = weekzip
return render(request, 'clinic/editslots0.html', {'rnd_num': randomnumber(), 'clinic': cl, 'doctor': doc, 'formslot': formslot, 'formspecialdays': formspecialdays, 'formweekdays': formweekdays, 'weekzip': weekzip, 'newweekzip': newweekzip, 'regav': regularslotsav, 'regbr': regularslotsbr, 'weekav': weekavzip, 'weekbr': weeklyslotsbr, 'weeklyslotsav': weeklyslotsav })
I've seen many similiar questions on SO. However in all of them I've seen people introducing for.counter. But this is not suitable for my purpose.
You can use with tag to set variables in template as -
{% with count=0 %}
{{ count}}
...do other stuffs
{% endwith %}
and for maths you could use django math filters like
{{ count|add:"1" }}
You can code you with use of both.
For more about setting variable in django template - How to set a value of a variable inside a template code?
and for using math in django - How to do math in a Django template?
Hope this helps you.

Next and Before Links for a django paginated query

I'm trying to make a search form for Django.
Its a typical search form and then returns a table of matches. I wish to paginate the tables returned.
The problem lies in the Previous and Next buttons.
The links for the return query goes to /records/search/?query=a (search sample is a)
The page outputs the table and its previous and next links. However the links redirect to /records/search/?page=2 and the page displays a blank table.
Any help on which links I should pass for Prev/Next?
search.html:
{% extends 'blank.html' %}
{% block content %}
<div class="row">
<form id="search-form" method="get" action=".">
{{ form.as_p }}
<input type="submit" value="Search" />
</form>
</div>
<br><br>
//display table code//
{% if is_paginated %}
<div class="pagination">
<span class="step-links">
{% if agent_list.has_previous %}
forrige
{% endif %}
<span class="current">
Page {{ agent_list.number }} of {{ agent_list.paginator.num_pages }}.
</span>
{% if agent_list.has_next %}
Next
{% endif %}
</span>
</div>
{% endif %}
{% endblock %}
and the search view:
def search_page(request):
form = SearchForm()
agents = []
show_results=False
if request.GET.has_key('query'):
show_results=True
query=request.GET['query'].strip()
if query:
form=SearchForm({'query': query})
agents = \
Agent.objects.filter(Q(name__icontains=query))
paginator = Paginator(agents, 10)
page = request.GET.get('page')
try:
agents = paginator.page(page)
except PageNotAnInteger:
agents = paginator.page(1)
except EmptyPage:
agents = paginator.page(paginator.num_pages)
variables = RequestContext(request,
{ 'form': form,
'agent_list': agents,
'show_results': show_results,
'is_paginated': True,
}
)
return render_to_response('search.html', variables)
I've seen the similar questions but I can't understand/make them work. Any help?
Edit:
For a quickfix (haven't really looked at the cons)
I added a variable in my view:
variables = RequestContext(request,
{ 'form': form,
'agent_list': agents,
'show_results': show_results,
'is_paginated': True,
**'query': query,**
}
)
Where query without the quotes is the recieved query variable.
Then simply change the URL to:
Previous
If you have a better way of answering the question, please do or appending a URL to your currently opened URL.
I would recommend putting the solution in a template tag like so:
myapp/templatetags/mytemplatetags.py:
from django import template
register = template.Library()
#register.simple_tag
def url_replace(request, field, value):
d = request.GET.copy()
d[field] = value
return d.urlencode()
#register.simple_tag
def url_delete(request, field):
d = request.GET.copy()
del d[field]
return d.urlencode()
Then from templates do:
{% load mytemplatetags %}
...
previous
you can use {{ request.get_full_path }} this tag to get current url.
Next
this worked for me
The below works before and after a search form has been submitted:
Views.py
class PostListView(ListView):
model = Post #.objects.select_related().all()
template_name = 'erf24/home.html' # <app>/<model>_<viewtype>.html
context_object_name = 'posts' # default >> erf24/post_list.html
ordering = ['date_posted']
paginate_by = 3
def is_valid_queryparam(param):
return param != '' and param is not None
def invalid_queryparam(param):
return param == '' and param is None
class SearchView(ListView):
model = Post #.objects.select_related().all()
template_name = 'erf24/home.html' # <app>/<model>_<viewtype>.html
context_object_name = 'posts' # default >> erf24/post_list.html
ordering = ['date_posted']
paginate_by = 3
def get_queryset(self): # new
key = self.request.GET.get('key')
minp = self.request.GET.get('min')
maxp = self.request.GET.get('max')
if is_valid_queryparam(key):
obj = Post.objects.filter(Q(content__icontains=key) | Q(location__icontains=key)).distinct().order_by('date_posted')
if is_valid_queryparam(minp):
obj = Post.objects.filter(Q(price__gte=minp)).distinct().order_by('date_posted')
if is_valid_queryparam(maxp):
obj = Post.objects.filter(Q(price__lte=maxp)).distinct().order_by('date_posted')
if is_valid_queryparam(minp) & is_valid_queryparam(maxp):
obj = Post.objects.filter(Q(price__gte=minp) & Q(price__lte=maxp)).distinct().order_by('date_posted')
if is_valid_queryparam(key) & is_valid_queryparam(minp) & is_valid_queryparam(maxp):
obj = Post.objects.filter(Q(content__icontains=key) | Q(location__icontains=key)).distinct()
obj = obj.filter(Q(price__gte=minp) & Q(price__lte=maxp)).order_by('date_posted')
if invalid_queryparam(key) & invalid_queryparam(minp) & invalid_queryparam(maxp):
obj = Post.objects.all()
return obj
url.py
urlpatterns = [
path('', PostListView.as_view(), name='erf24-home'),
path('search/', SearchView.as_view(), name='erf24-search'),
]
Home.html
<form action="{% url 'erf24-search' %}" method="GET">
<div class="form-group">
<label for="inputAddress">Search keyword</label>
<input type="text" class="form-control" id="key" name="key" placeholder="keyword">
</div>
<label for="">Price</label>
<div class="form-row">
<div class="form-group col-md-6">
<input type="number" class="form-control" id="min" name="min" placeholder="min price">
</div>
<div class="form-group col-md-6">
<input type="number" class="form-control" id="max" name="max" placeholder="max price">
</div>
</div>
<button type="submit" class="btn btn-primary btn-sm mt-1 mb-1">Search</button>
<button type="reset" class="btn btn-secondary btn-sm mt-1 mb-1">Clear</button>
</form>
{% for post in posts %}
<article class="media content-section">
<div class="media-body">
<div class="article-metadata">
<img class="rounded-circle article-img" src="{{ post.author.profile.image.url }}" alt="">
{{ post.author }}
<small class="text-muted">{{ post.date_posted }}</small>
<!-- use |date: "specs" to filter date display -->
</div>
<h2>
{{ post.price }}
</h2>
<p class="article-content">{{ post.content }}</p>
<p class="article-content">{{ post.location }}</p>
<p><a class="like-btn" data-href="{{ post.get_api_like_url }}" href="">{{ post.likes.count }}
{% if user in post.likes.all %} Unlike
{% else %} Like
{% endif %}
</a></p>
</div>
{% for image in post.image_set.all %}
<img class="account-img" src="{{ image.image.url }}" alt="">
{% endfor %}
</article>
{% endfor %}
{% if is_paginated %}
{% if page_obj.has_previous %}
First
Previous
{% 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 %}
Next
Last
{% endif %}
{% endif %}
Worked like a charm :) Enjoy!
You can use {{ request.get_full_path }} template tag
Next
you can use this, I use it because I use filters in the url itself, so all the url params are used to build the next or previous url
import re
from django import template
register = template.Library()
PAGE_NUMBER_REGEX = re.compile(r'(page=[0-9]*[\&]*)')
#register.simple_tag
def append_page_param(value,pageNumber=None):
'''
remove the param "page" using regex and add the one in the pageNumber if there is one
'''
value = re.sub(PAGE_NUMBER_REGEX,'',value)
if pageNumber:
if not '?' in value:
value += f'?page={pageNumber}'
elif value[-1] != '&':
value += f'&page={pageNumber}'
else:
value += f'page={pageNumber}'
return value
then, in your pagination nav you can call it like this:
{% append_page_param request.get_full_path page_obj.previous_page_number %}

Categories