Transferring a randomly generated DB key between GET and POST - python

I'm having trouble with the POST section of the code below. I've come to the conclusion that after the form is sent from login the key variable is being reloaded and the integer change to no longer always match for the logic. But for some reason if i print riddle and dbanswer to the terminal, it always works.
I'm new to Python and Flask and am not sure if there's a way to fix this bug in my code by re-arranging it or using some sort of redirect to process the GET and POST separately so that the key is fixed between the two.
#app.route("/", methods=['GET','POST'])
def HomePage():
key = random.randint(1,3)
riddle = con.get("riddle:%i" %key)
dbanswer = con.get("riddle:%i:answer" %key)
# print(riddle)
# print(dbanswer)
if request.method == 'GET':
return render_template("login.html", riddle = riddle)
elif request.method =="POST":
answer = request.form['answer']
if answer == dbanswer:
return render_template("welcome.html")
else:
return render_template("login.html", riddle = riddle)
else:
return "<h2>Invalid request</h2>"

Just store the key in the form.
if request.method == 'GET':
return render_template('login.html', riddle=riddle, riddle_id=key)
Then in your login.html form, use that value:
<input type="hidden" name="riddle_id" value="{{ riddle_id }}"/>
Now when you POST that form to your view, you can grab it to complete the circle:
if request.method == "POST":
answer = request.form['answer']
riddle_id = request.form['riddle_id']
if answer == con.get("riddle:%i:answer" % riddle_id):
return render_template("welcome.html")

Related

Passing Variable (View --> Template --> View)

Problem: I want to generate a random number, and ask the user to calculate the addition of these two. Then, I want to evaluate the number and see if the solution is correct.
My issue: I can do everything except the evaluation bit, as the values of the random numbers change!
HTML file:
<p> What is {{ a }} + {{ b }} ? </p>
<form action="{% url 'form_handle' %}" method="POST">{% csrf_token %}
{{form.as_p}}
<button type="submit">Submit</button>
</form>
FORM file:
class MyForm(forms.Form):
num1 = forms.CharField(max_length=20)
VIEW file:
def form_handle(request):
if request.method == 'POST':
form = MyForm(request.POST) # if post method then form will be validated
if form.is_valid():
cd = form.cleaned_data
num1 = cd.get('num1')
#num2 = cd.get('num2')
#result = cd.get('result')
if float(num1) == float(a + b):
# give HttpResponse only or render page you need to load on success
return HttpResponse("Good job!")
else:
# if sum not equal... then redirect to custom url/page
return HttpResponseRedirect('rr/') # mention redirect url in argument
else:
a = random.randrange(5,10);
b = random.randrange(10,20);
form = MyForm() # blank form object just to pass context if not post method
return render(request, "rr.html", {'form': form, 'a': a, 'b':b})
The error I get is "local variable 'a' referenced before assignment". I did try and change initialisation of a and b, and put the code right after the function declaration but that did not work either, as the function would compare the numbers (a + b) with another set of randomly generated numbers
Any help is much appreciated, or perhaps a new approach to this problem. Do note that I am a beginner in Python though
You can try to store a and b in session data:
def form_handle(request):
if request.method == 'POST':
form = MyForm(request.POST) # if post method then form will be validated
if form.is_valid():
cd = form.cleaned_data
num1 = cd.get('num1')
#num2 = cd.get('num2')
#result = cd.get('result')
a = request.session.get('a', 0)
b = request.session.get('b', 0)
if float(num1) == float(a + b):
# give HttpResponse only or render page you need to load on success
return HttpResponse("Good job!")
else:
# if sum not equal... then redirect to custom url/page
return HttpResponseRedirect('rr/') # mention redirect url in argument
else:
a = random.randrange(5,10);
b = random.randrange(10,20);
request.session['a'] = a
request.session['b'] = b
form = MyForm() # blank form object just to pass context if not post method
return render(request, "rr.html", {'form': form, 'a': a, 'b':b})

How to pass a value to a form for unittest?

I want to write test for my code and pass a value to a form how can i do that? I have two form in my code and this value should pass just to one of them.
my unittest:
def test_user_has_project(self):
resp = self.client.post('/register/', NEW_USER)
self.assertRedirects(resp, '/register/confirm/')
confirmation_code = self.client.session['confirm_code']
resp = self.client.post('/register/confirm/',
{'confirm_code':confirmation_code})
but this code pass confirmation code to both forms.
my views:
if request.method == 'POST':
form = forms.RegistrationConfirmForm(request.POST)
if (form.is_valid() and
form.cleaned_data['confirm_code'] == request.session['confirm_code']):
# Register the user in the backend
form = forms.RegistrationForm(request.session['registering_user'])
sorry. I'm a beginner in both coding and asking question!

2 forms, 1 view, 2 SQL tables in Django

I'm struggling to understand how to submit data from two django forms into two separate database tables from the same view. I only want one submit button. While this question got me closer to the solution, I'm getting errors and the data is not writing to the database. I think this code actually checks the two forms against each other instead of submitting both forms in one go. Any ideas?
Here's what I've tried:
For one form --> one table. This works, so it's a start.
# views.py
def BookFormView(request):
if request.method == 'POST':
form = BookForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect("/books/")
else:
form = BookForm()
return render(request, 'books/createbooks.html',
{'form' : form})
However, when I add this form in from forms.py to get the subsequent views.py I get local variable 'book_form' referenced before assignment. That's usually an easy global-vs-local variable issue to fix, but I don't know what it means in this case.
def BookFormView(request):
if request.method == 'POST':
if 'book' in request.POST:
book_form = BookForm(request.POST, prefix='book')
if book_form.is_valid():
book_form.save()
return HttpResponseRedirect("/books/")
bookdetailsform = BookDetailsForm(prefix='bookdetails')
elif 'bookdetails' in request.POST:
bookdetailsform = BookDetailsForm(request.POST, prefix='bookdetails')
if bookdetailsform.is_valid():
bookdetailsform.save()
return HttpResponseRedirect("/books/")
book_form = BookForm(prefix='book')
else:
book_form = BookForm(prefix='book')
bookdetailsform = BookDetailsForm(prefix='bookdetails')
return render(request, 'books/createbook.html',
{'book_form' : book_form,
'bookdetailsform': bookdetailsform})
Based on the question's comments:
def BookFormView(request):
if request.method == 'POST':
book_form = BookForm(request.POST, prefix='book')
bookdetailsform = BookDetailsForm(request.POST, prefix='bookdetails')
if book_form.is_valid() and bookdetailsform.is_valid():
book_form.save()
bookdetailsform.save()
return HttpResponseRedirect("/books/")
else:
book_form = BookForm(prefix='book')
bookdetailsform = BookDetailsForm(prefix='bookdetails')
return render(request, 'books/createbook.html',
{'book_form': book_form, 'bookdetailsform': bookdetailsform})
I think the problem is that when a user submits a bookdetails post request,
it will be handled under if 'book' in request.POST: condition. Why?
because string bookdetails contains string book, no matter the type of request they do, it will be handled with if book in request.POST: condition.
I believe fixing that if condition problem is the first step.

flask edit a database field and retain previous value using wtf form

After saving a value into my database, I am rendering an edit_field html.
the form auto-populates with prior data.
how do i save the original data so i can check which fields changed?
here is my skeleton edit view
#app.route('/edit/<name>/<goal>/<strategy>/<task>', methods=['GET', 'POST'])
def edit_task(name,goal,strategy,task):
ptask=models.Tasks.query.filter_by(task=task).first()
form = task_form(obj=ptask)
form.populate_obj(ptask)
tform=task_form(request.values)
if request.method == 'POST' and form.validate_on_submit():
complete=tform.complete.data
#check if complete changed
db.session.commit()
return redirect(url_for('task_outline',name=name,goal=goal,strategy=strategy))
return render_template('edit_task.html', tform=tform,form=form,ptask=ptask)
This most likely will work in Flask, however I've only ever done this using Pyramid
db.session.is_modified(ptask)
#returns True/False
As suggested by limasxgoesto0, I used the get_history, and it worked. here is me testing, and solving my how to test a boolean for change and assign a new date for fresh True's.
from my view:
#app.route('/edit/<name>/<goal>/<strategy>/<task>', methods=['GET', 'POST'])
def edit_task(name,goal,strategy,task):
..... more view missing here.....
ptask=models.Tasks.query.filter_by(task=task)
if request.method == 'POST' and form.validate_on_submit():
print 'now ',get_history(ptask, 'complete')[0]
print 'before ',get_history(ptask, 'complete')[2]
if get_history(ptask, 'complete')[0]==[True] and get_history(ptask, 'complete')[2]==[False]:
print 'changed from false to true'
ptask.completeDate=datetime.datetime.utcnow()
if get_history(ptask, 'complete')[0]==[False] and get_history(ptask, 'complete')[2]==[True]:
print 'changed from true to false'
ptask.completeDate=None
db.session.commit() if request.method == 'POST' and form.validate_on_submit():

submitting two forms one after another

I am working on my first django webaite, I am trying to submit two forms one after the other.
Here is the views.py :
def home(request):
import json
if request.method == 'POST':
form = MajorForm(request.POST)
if form.is_valid():
url = 'http://www.mysite.com:8082'
dataout = {'my':'data'}
headers = {'content-type':'application/json'}
r = requests.post(url,data=json.dumps(dataout),headers=headers)
return collector(request)
else:
return HttpResponse("thnx")
else:
form = MajorForm()
return render(request,'index.html',{'form':form})
def collector(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
return HttpResponse("thanx")
else:
return HttpResponse("not valid")
else:
form = ContactForm();
return render(request,'collector.html',{'form':form})
So the first view calls the second view. The first form works fine, and the second form is also displayed fine, but submitting the second form does not work at all ( I was never able to get to form.is_valid path). Maybe this entire approach of calling one view from another is not correct? What would be the right one?
Please indent your code correctly. Also you are missing an else in the collector function when the request.method is not POST.

Categories

Resources