I have an issue with the program am trying to develop. I have a function that will send OTP code to user when they request to login. the OTP code should be sent through email to the registered users. the problem is that my code now accepts every email and it doesn't validate the users from the database. How can I do this?
UPDATED the new code!
I updated my code that i previously posted because initially I had issue in getting the OTP also. Someone helped me to point my mistake and I corrected them. But still the existing email verification has no luck. Please help!
this is my updated script
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js" type='text/javascript'>
{% block title %}
{% endblock %}
{% block content %}
<h1>OTP Verification Page</h1>
<br>
<br>
<p>
</script>
<div id="email_div" style="display: block;" >
<label for="email">Email</label>
<input type="text" name="email" id="email">
<button onclick="ajax_send_otp()">Send OTP</button>
</div>
<div id="verify_text_div"></div>
<div id="otp_div" style="display: none;" >
<label for="email">OTP</label>
<input type="text" name="otp" id="otp">
<button onclick="verify_otp()">Verify</button>
</div>
</p>
{% endblock %}
<script>
var otp_from_back="";
function ajax_send_otp(){
document.getElementById("email_div").style.display='none';
email = document.getElementById("email");
$.post("/send_otp",
{
"email":email.value,
"csrfmiddlewaretoken":"{{csrf_token}}"
},
function(data, status){
if(status=="success"){
otp_from_back = data;
document.getElementById("otp_div").style.display='block';
}
}
);
}
function verify_otp(){
var user_otp=document.getElementById("otp").value;
if (user_otp==otp_from_back){
document.getElementById("verify_text_div").style.color="green";
document.getElementById("verify_text_div").innerHTML="OTP Verified";
setTimeout(window.location.assign("http://127.0.0.1:8000/login/"),2000);
document.getElementById("otp_div").style.display="none";
document.getElementById("form_div").style.display="block";
}
else{
document.getElementById("verify_text_div").style.color="red";
document.getElementById("verify_text_div").innerHTML="Try Again!!";
}
}
</script>
and this is my updated views.py file
def otp_verification(request):
return render(request, 'otp.html')
def generateOTP():
digits = "0123456789"
OTP = ""
for i in range(4):
OTP += digits[math.floor(random.random() * 10)]
return OTP
def send_otp(request):
email = request.GET.get("email")
print(email)
o = generateOTP()
#email = EmailMessage(
# subject='Nithya FYP OTP',
# body= ('OTP request', o),
# from_email=EMAIL_HOST_USER,
#to=[email],
#)
#mail.send()
print(o)
return HttpResponse(o)
Try validating your email and checking if the email exists in your database.
email = request.POST['email']
if validate_email(email) and User.objects.filter(email=email).exists():
...
else:
...
Related
I am new to django and html. below is my first test web page of a simple online calculator.
I found a problem that when clicking the "submit" button, it tends to jump to a new web page or a new web tab. this is not what I want. Once the user input the data and click "submit" button, I want the "result" field on the page directly show the result (i.e. partially update only this field) without refresh/jump to the new page. Also I want the user input data kept in the same page after clicking "submit".
I saw there might be several different ways to do this work, iframe/AJAX. Since I am new, what is the really simplest way to achieve this goal? BTW, I dont write javascripts.
html:
<form method="POST">
{% csrf_token %}
<div>
<label>num_1:</label>
<input type="text" name="num_1" value="1" placeholder="Enter value" />
</div>
<div>
<label>num_2:</label>
<input type="text" name="num_2" value="2" placeholder="Enter value" />
</div>
<br />
<div>{{ result }}</div>
<button type="submit">Submit</button>
</form>
view.py
def post_list(request):
result = 0
if request.method == "POST":
num1 = request.POST.get('num_1')
num2 = request.POST.get('num_2')
result = int(num1) + int(num2)
print(request.POST)
print(result)
context = {
'result': result
}
return render(request, 'blog/post_list.html', context)
This is a simple example of using Ajax, which I hope will be useful to you.
first you need change post_list view:
view
from django.http import JsonResponse
def post_list(request):
if request.method == "POST":
num1 = request.POST.get('num_1')
num2 = request.POST.get('num_2')
result = int(num1) + int(num2)
return JsonResponse({"result":result})
else:
return render(request, 'blog/post_list.html', context={"result":0})
I use JsonResponse because I just want to get the result data in ajax and display it in the html , for GET request render the html file and for POST request use JsonResponse to return a json like context.
And your html file should to be a look like this:
html
<script src="https://code.jquery.com/jquery-3.6.0.js" integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk=" crossorigin="anonymous"></script>
<form method="POST" id="post-form">
{% csrf_token %}
<div>
<label>num_1:</label>
<input type="text" name="num_1" value="1" placeholder="Enter value" />
</div>
<div>
<label>num_2:</label>
<input type="text" name="num_2" value="2" placeholder="Enter value" />
</div>
<br />
<div id="result" >{{ result }}</div>
<button type="submit" >Submit</button>
</form>
<script>
$(document).ready(
$('#post-form').submit(function(e){
e.preventDefault();
var serializedData = $(this).serialize();
$.ajax({
type:"POST",
url: "/your_url/",
data: serializedData,
success: function(data){
$("#result").text(data["result"]);
}
});
})
);
</script>
First I added jQuery cdn and then your html file, except that I added attribute id=post-form to the form and added id=result, then <script> tag was added and jquery function inside the tag was execute when your form Submited(detect event by the id #post-form).
And get the data(num_1, num_2) by serialize method then use Ajax to send POST reqeust to the view function(post_list), in Ajax you just need to pass serializedData and url(also you can use the Django url tag or set it in action form or...), After that we need to send data to the html(means the result data we received from the View).
in success function Ajax you can add html tag to your html file or
replace the some values,...
In Ajax, you must specify your URL to send the data.
for example if you have this url.py
urls.py
from .views import post_list
urlpatterns = [
path("posts_list/", post_list, name="post_list"),
]
In ajax you can add an address like this:
$.ajax({
type:"POST",
url: "/posts_list/",
....
Or
$.ajax({
type:"POST",
url: "{% url 'post_list' %}",
....
And if you have app_name in urls.py you can added url: "{% url 'app_name:post_list' %}",
This part takes care of sending the link to the user. So far it does the job perfectly and I always get the email
app = Flask(__name__)
app.secret_key = 'b11223344AaadD$$r.,IIr]]tP[tu#urr'
app.config.from_pyfile('config.cfg')
mail = Mail(app)
s = URLSafeTimedSerializer(app.config['SECRET_KEY'])
engine = create_engine("postgresql://postgres:andersen23#localhost:5432/test")
db = scoped_session(sessionmaker(bind=engine))
#app.route('/recover', methods=['POST', 'GET'])
def recover():
headline = 'Recover Your Password'
alert = 'Type Your Email'
alert_ = ''
if request.method == 'GET':
return render_template('recover.html', headline=headline, alert1=alert, alert=alert_)
email = request.form.get('email')
session['email'] = email
mail1 = db.execute("SELECT contact0.email FROM person JOIN contact0 ON contact0.id = person.id
WHERE email = :email",
{"email": email}).fetchone()
token = s.dumps(email, salt='confirm')
link = url_for('confirm', token=token, _external=True)
msg = Message('Confirm Email', sender='esdavitnem#gmail.com', recipients=[email])
name = db.execute(
"SELECT person.first_name FROM person JOIN contact0 ON contact0.id = person.id WHERE email =
:username",
{"username": email}).fetchone()
if not isinstance(mail1, type(None)):
alert_ = f"Link Sent to {email}! \n Expires in 5 minutes!"
msg.body = f"Dear {name[0]}, \n\nYour link is {link} \n\nBest,\nDavid from Drunkify"
mail.send(msg)
return render_template('recover.html', headline=headline, alert1=alert, alert=alert_)
if isinstance(mail1, type(None)):
alert_ = f"No user exists with {email} email"
return render_template('recover.html', headline=headline, alert1=alert, alert=alert_)
This part takes care of opening the token and showing an html code to the user.
My main issue is that render_template only works with one html file in my templates.
register1.html is a page for my user to change their password. But the code error message keeps suggesting me to redirect them to register.html
#app.route('/confirm_email/<token>')
def confirm(token):
headline = 'Type Your New Password'
try:
email = s.loads(token, salt='confirm', max_age=300)
except SignatureExpired:
return 'The Token Expired'
return render_template('register1.html', headline=headline)
Register1.html
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Title Page-->
<title>Recover Your Password</title>
<link href="../static/main.css" rel="stylesheet" media="all">
</head>
<body>
<div class="page-wrapper bg-gra-01 p-t-180 p-b-100 font-poppins">
<div class="wrapper wrapper--w780">
<div class="card card-3">
<div class="card-heading"></div>
<div class="card-body">
<h2 class="title">Change Your Password</h2>
<form action = "{{ url_for('confirm') }}" method="post">
<div class="form-group">
<input class="form-control" type="password"
placeholder="New Password" name="password" required>
<div class="help-block with-errors"></div>
</div>
<div class="p-t-10">
<button type="submit" class="btn btn--pill btn--green">
Submit
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</body>
</html>
What you're seeing is a mismatch in expectations between
def confirm(token):
which expects an argument, and
{{ url_for('confirm') }}
which isn't providing one, but lives in a form that does provide password as part of the POST parameters (a different mechanism). I'm wondering if you didn't intend to do
{{ url_for('recover') }}
instead.
I have made this HTML code:
<h3>your major is {{user.userprofile.major}}</h3>
This will correctly show the major on the webpage, but I want to use this string to get something from another table in view.
How would I pass this string to view?
edit:
Here is my view.py
def dashboardView(request):
obj = BooksFile.objects.all()
query = BooksFile.objects.filter(book_major='cs)
return render(request, 'dashboard.html', {'books': obj, 'major': query})
def registerView(request):
if request.method == "POST":
form = UserCreationForm(request.POST)
profile_form = UserProfileForm(request.POST)
if form.is_valid() and profile_form.is_valid():
user = form.save()
profile = profile_form.save(commit=False)
profile.user = user
profile.save()
return redirect('login_url')
else:
form = UserCreationForm()
profile_form = UserProfileForm()
context = {'form': form, 'profile_form': profile_form}
return render(request, 'registration/register.html', context)
here is my template:
{% extends 'index.html' %}
{% block content %}
<h1>Welcome, {{user.username}}</h1>
<h2>Your major is {{user.userprofile.major}}</h2>
{% for book in books %}
<h3>Your book name is {{book.book_name}}</h3>
{% endfor %}
{% endblock %}
I am trying to show the book names from the booksfile table by corresponding major that user has. Right its showing the books that has "cs" attribute because I manually put "cs" in the get function in view. I am trying to send the major string from template to view, so that I can put what ever the user's major is in the get function. Or is there any other way to do it.
You need to use a form in your template and submit it to call your view. i.e.
<form action="your_view_url" method="POST">
<input type="text" name="major" value="{{user.userprofile.major}}"/>
<input type="submit"/>
</form>
an then in your view you access that with:
if request.POST:
major = request.POST.get('major')
As per documentation: https://docs.djangoproject.com/en/2.2/topics/forms/
First of all you have to get the value of model with help of queryset, and put it in the dictionary and then pass it with the template.
In views:
def get(self, request):
queryset = Model_name.objects.all()
ctx = {
'queryset': queryset,
}
return render(request, 'page_name(or template_name).html', ctx)
in template:
<form action="{%url'(your_view_name without brackets)'%}" method="POST">
{% for data in queryset%}
<span class="username">{{data.name(field of your model)}} .
</span>
<span class="email">{{data.email(field of your model)}} .
</span>
{% endfor%}
</form>
I'm working on a simple flask application that displays a basic form with user, pass, verify pass, and email. The way I have it right now, if there are no errors, instead of going to the page i tell it to (welcome.html), it just goes back to my home page (index.html). There are comments in the code to guide you through it. Please help I've been racking my brain and the internet and trying lots and lots of things for the past week, and i need this for school or else im gonna fail. Here is my application code:
from flask import Flask, request, redirect, render_template
import jinja2
import cgi
app = Flask(__name__)
app.config['DEBUG'] = True
#app.route("/", methods=['GET'])
def index():
return render_template("index.html")
#if my form makes a post request at the route / (as defined in the form in the index page), then go to index again, or welcome page
#app.route("/", methods=['POST'])
def welcome():
username = str(request.form.get('username-actual'))
password = str(request.form.get('password-actual'))
verifiedpassword = str(request.form.get('verifedpassword-actual'))
email = str(request.form.get('email-actual'))
#if (not username) or len(username) < 3 or len(username) > 20 or ' ' in username: IGNORE THIS
#If any of the fields have any of these conditions, fill the error message with the message. otherwise, empty
if username == '' or len(username) < 3 or len(username) > 20 or ' ' in username:
usererror = "Invalid username lol"
else:
usererror = ""
if password == '' or len(password) < 3 or len(password) > 20 or ' ' in password:
passworderror = "Invalid password lol"
else:
passworderror = ""
if verifiedpassword != password:
verifiedpassworderror = "Passwords dont match lol"
else:
verifiedpassworderror = ""
if email == '' or len(email) < 3 or len(email) > 20 or ' ' in email or '#' not in email:
emailerror = "Invalid email lol"
else:
emailerror = ""
#if any of the error messages are not empty (meaning there are error messages), render the home page again, with the necessary strings provided for jinja
if len(usererror) > 0 or len(passworderror) > 0 or len(verifiedpassworderror) > 0 or len(emailerror) > 0:
return render_template("index",usererror=usererror,
passworderror=passworderror,
verifiedpassworderror=verifiedpassworderror,
emailerror=emailerror,
username=username,
email=email,)
#otherwise, go to the welcome page, with the necessary username
else:
return render_template("welcome.html",username=username)
app.run()
and here is my two form, index.html and welcome.html, respectively:
<!doctype html>
<html>
<head>
<title>
User Sign-up
</title>
<style>
.error { color:red; }
</style>
</head>
<body>
<h1>Sign-up</h1>
<br>
<form action="/" method="post">
<div>
<label>Username: <input type="text" name="username-actual" value="{{username}}"></label>
<p class="error">{{usererror}}</p>
</div>
<div>
<label>Password: <input type="password" name="password-actual"></label>
<p class="error">{{passworderror}}</p>
</div>
<div>
<label>Verify Password: <input type="password" name="verifiedpassword-actual"></label>
<p class="error">{{verifypassworderror}}</p>
</div>
<div>
<label>Email (optional): <input type="text" name="email-actual" value="{{email}}"></label>
<p class="error">{{emailerror}}</p>
</div>
<div>
<input type="submit" name="sign-up-submit" value="Sign Up!">
</div>
</form>
</body>
</html> <p></p>
Here is my welcome.html:
Welcome, {{username}}!
I've been able to use a django form and template to insert data to the database. I can also display the data in a very basic HTML page. However, am completely unable to figure out how I go about editing the data. Am assuming that I can at least reuse the django template I used to create a new database entry to also edit the entries thus eliminating the need to create an "edit" template.
Mind you I can edit the entry in console but in the browser I just can't seem to get my head around to how to load the data, which variables carry my primary key when I click on a link of a displayed vehicle and how to pass the fetched data from the database to the form to allow for editing etc. I've checked the admin site for guidance on how it does it on that end but still.... no luck.
Here is my insert code: How do I modify this to allow me to edit the data displayed by the vehicle.html further below?
views.py
vehicle_add - inserts to database
def vehicle_add(request):
if request.method == 'POST':
form = VehicleForm(request.POST)
if form.is_valid():
newvehicle = Vehicle()
vdetails = form.cleaned_data
newvehicle.reg_number= vdetails['regnumber']
newvehicle.model= vdetails['model']
newvehicle.manufacturer= vdetails['manufacturer']
newvehicle.year= vdetails['year']
newvehicle.chassis_number= vdetails['chasisnumber']
Vehicle.save(newvehicle)
return HttpResponseRedirect('/vehicle')
else:
form = VehicleForm()
return render_to_response('vehicle_add.html', {'form': form}, context_instance=RequestContext(request))
The vehicle.html loads the data in a simple HTML format as below:
{% for v in obj %}
<tr><td>{{ v }}</td></tr>
{% endfor %}
The link is displayed like this: http://localhost:8000/vehicle_add/2/
More Info:
vehicle_add.html
{% extends "base.html" %}
{% block title %}Add Vehicle{% endblock %}
{% block page %}Add Vehicle{% endblock %}
{% block content %}
<html>
<head>
<style type="text/css">
ul.errorlist {
margin: 0;
padding: 0;}
.errorlist li {
background-color: red;
color: white;
display: block;
font-size: 10px;
margin: 0 0 3px;
padding: 4px 5px;}
</style>
</head>
<body>
<section id = "mainform">
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form action="" method="post">{% csrf_token %}
<div class="field">
{{ form.regnumber.errors }}
<label for="id_regnumber">Reg #:</label>
{{ form.regnumber }}</div>
<div class="field">
{{ form.model.errors }}
<label for="id_model">Model:</label>
{{ form.model }}</div>
<div class="field">
{{ form.manufacturer.errors }}
<label for="id_manufacturer">Manufacturer:</label>
{{ form.manufacturer }}</div>
<div class="field">
{{ form.year.errors }}
<label for="id_year">Year:</label>
{{ form.year }}</div>
<div class="field">
{{ form.chasisnumber.errors }}
<label for="id_chasisnumber">Chasis #:</label>
{{ form.chasisnumber }}</div>
<div class="field">
<input type="submit" value="Submit">
<input type="submit" value="Clear">
</div></form></section>
</body>
</html>
{% endblock %}
Trial and Error:
This is what I've tried to do with my view but with no luck:
def vehicle_add(request):
if request.method == 'POST':
form = VehicleForm(request.POST)
if form.is_valid():
newvehicle = Vehicle()
vdetails = form.cleaned_data
newvehicle.reg_number= vdetails['regnumber']
newvehicle.model= vdetails['model']
newvehicle.manufacturer= vdetails['manufacturer']
newvehicle.year= vdetails['year']
newvehicle.chassis_number= vdetails['chasisnumber']
Vehicle.save(newvehicle)
return HttpResponseRedirect('/vehicle')
else:
#WORKING ON THIS
form = VehicleForm
newvehicle = Vehicle.objects.get(pk=9)
form = VehicleForm(newvehicle)
return render_to_response('vehicle_add.html', {'form': form}, context_instance=RequestContext(request))
But on doing so I get different type of errors. Am not even sure if that is how to do it. Can somebody point me in the right direction?
EDIT
Here is the current error:
Caught AttributeError while rendering: 'Vehicle' object has no attribute 'get'
In template d:\dev\workspace\vehicle_request\vehicle_request\mvmanager\templates\vehicle_add.html, error at line 31
It then highligths this part of the template: {{ form.regnumber }}
forms.py
class VehicleForm(forms.Form):
regnumber = forms.CharField(
max_length=7,
label='Reg #:',
widget = forms.TextInput(attrs={'size':7}) )
model = forms.CharField(
label='Model',
widget = forms.TextInput(attrs={'size':25}) )
manufacturer = forms.CharField(
max_length=25,
label='Manufacturer',
widget = forms.TextInput(attrs={'size':25}) )
year = forms.IntegerField(
label='Year',
widget = forms.TextInput(attrs={'size':4}) )
chasisnumber = forms.CharField(
required=False, label='Chasis #',
widget = forms.TextInput(attrs={'size':25}) )
Modify url conf line to use parameters in url,
e.g.:
(r'^vehicle_add/(\d+)/$','app.views.vehicle_add')
In vehicle_add first parameter (second after self parameter) will be vehicle_id taken from url.
You can name it as you wish,
e.g. vehicle_id.
Use it :
newvehicle= Vehicle.objects.get(pk=vehicle_id)
Pass the form a dict:
#WORKING ON THIS
# form = VehicleForm <<< THIS LINE IS UNNECESSARY
newvehicle = Vehicle.objects.get(pk=9)
form = VehicleForm(newvehicle.__dict__)