I have used the international phone numbers(intlTelInput) in my django app but it seems the form isn't saving the number - javascript

So i have basically used the intl-tel-input plugin in my registration form. My webapp is in django. But whenever i submit the form, i get an error which is like the phone_number field is required, even though i have filled in the number. Seems like the form isn't saving the phone number data. How can i solve this?
form temlplate looks like this:
{% load static %}
{% load crispy_forms_tags %}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="/static/css/register.css">
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.8/css/intlTelInput.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.8/js/intlTelInput.min.js"></script>
</head>
<body>
</body>
</html>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
</body>
</html>
</head>
<body>
<div class="container">
<div class="title">REGISTER </div>
<div class="content">
<form action="#" method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="user-details">
<div class="input-box">
{{form.name|as_crispy_field}}
</div>
<div class="input-box">
{{form.email|as_crispy_field}}
</div>
<div class="input-box">
<span class="details">Phone number</span>
<input id="phone" type="tel" name="phone" />
</div>
<div class="input-box">
{{form.address|as_crispy_field}}
</div>
<div class="input-box">
{{form.nin|as_crispy_field}}
</div>
<div class="input-box">
{{form.LC1_letter|as_crispy_field}}
</div>
<div class="input-box">
{{form.National_Id|as_crispy_field}}
</div>
<div class="input-box">
{{form.password1|as_crispy_field}}
</div>
<div class="input-box">
{{form.password2|as_crispy_field}}
</div>
</div>
<div class="form-check d-flex justify-content-center mb-5">
<input class="form-check-input me-2" type="checkbox" value="" id="form2Example3c" />
<label class="form-check-label" for="form2Example3">
First agree with all statements in Terms of service to continue
</label>
</div>
<div class="button">
<input type="submit" value="Register" href="#">
<input type="submit" value="Login" style="margin-left: 200px;">
</div>
</form>
</div>
</div>
</body>
<script>
const phoneInputField = document.querySelector("#phone");
const phoneInput = window.intlTelInput(phoneInputField, {
onlyCountries: ['ug'],
utilsScript:
"https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.8/js/utils.js",
});
const info = document.querySelector(".alert-info");
function process(event) {
event.preventDefault();
const phoneNumber = phoneInput.getNumber();
info.style.display = "";
info.innerHTML = `Phone number in E.164 format: <strong>${phoneNumber}</strong>`;
}
</script>
</html>
forms.py:
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import AbstractBaseUser
from .models import *
from django.core.exceptions import ValidationError
class RegForm(UserCreationForm):
name = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'username'}))
email = forms.EmailField(widget=forms.EmailInput(attrs={'placeholder': 'Enter your name', 'id':'email', 'name':'email'}))
address = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Enter your District, Subcounty, Village' ,'id':"location"}))
nin = forms.CharField(widget=forms.TextInput(attrs={'placeholder':'Enter your NIN', 'id':"NIN",'name':"nin"}))
LC1_letter = forms.FileField(widget=forms.FileInput(attrs={'name':'upload'}))
National_Id = forms.FileField(widget=forms.FileInput())
def __init__(self, *args, **kwargs):
super(RegForm, self).__init__(*args, **kwargs)
for fieldname in ['LC1_letter', 'nin','password1', 'password2']:
self.fields[fieldname].help_text = None
class Meta:
model = Account
fields = ['email', 'name', 'address', 'phone_number', 'LC1_letter', 'nin', 'National_Id', 'password1', 'password2']
and views.py:
from django.shortcuts import render, redirect
from django.contrib.auth.forms import UserCreationForm
from accounts.forms import RegForm
from django.contrib.auth import login, authenticate
from .models import *
from django.contrib import messages
from django.core.files.storage import FileSystemStorage
# Create your views here.
def register(request):
if request.method == "POST":
form = RegForm(request.POST, request.FILES)
if form.is_valid():
upload = request.FILES['upload']
fss = FileSystemStorage()
file = fss.save(upload.name, upload)
file_url = fss.url(file)
form.save()
return render(request,'main_app/base.html', {'file_url': file_url})
else:
print('Form is not valid')
print(form.errors)
else:
form = RegForm()
return render(request, 'accounts/register.html', {'form': form})

I see you have specify 'phone_number' of your model to be used in your form but on the client side (HTML) you did not include the field in your form so went the form is submited Django is trying to clean and validate the form based on fields entries then the field 'phone_number' is not found in post your data (because there is no field with the name phone_number) so that the error is returned maybe they could have returned a message like ('the field ******** is define in your form class but you did not submit it here').
To get rid of this error you can:
1- Define the field on the client side like:
{{form.phone_number|as_crispy_field}}
2- or like:
<input id="id_phone_number" type="text" name="phone_number" />
As you can see in the second case the name of the field is 'phone_number' not just 'phone' as you defined it in your template.
Now depending on this you can figure out how to do you JS machinery to make things work as you want it to.

hello please can you show the error returned? but as for now i dont see any field called phone defined in your form or an element '#phone' defined in your html

Related

How to create a comment box and comment display feature in flask?

Hi I am currently trying to create a comment box feature in flask. The problem I am facing is that when I click on the submit button, nothing happens. I want the user to be able to see the message they wrote along with their username below the comment box.
Here is my code:
python file:
from flask import Flask, render_template, request
import sqlite3
conn = sqlite3.connect('comments.db')
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS comments
(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, comment TEXT)''')
conn.commit()
#app.route('/add_comment', methods=['POST'])
def add_comment():
name = request.form['name']
comment = request.form['comment']
c.execute("INSERT INTO comments (name, comment) VALUES (?, ?)", (name, comment))
conn.commit()
return render_template('comment.html', name=name, comment=comment)
#app.route('/')
def view_comments():
c.execute("SELECT * FROM comments ORDER BY id DESC")
comments = c.fetchall()
return render_template('index.html', comments=comments)
javascript file:
$(document).ready(function() {
$("#comment-form").submit(function(e) {
e.preventDefault();
$.ajax({
type: "POST",
url: "{{ url_for('add_comment') }}",
data: $(this).serialize(),
success: function(data) {
$("#comments").append(data);
$("#name").val('');
$("#comment").val('');
}
});
});
});
html file:
<form id="comment-form" action="{{ url_for('add_comment') }}" method="post">
<label for="name">Name:</label>
<input type="text" id="name" name="name">
<label for="comment">Comment:</label>
<textarea id="comment" name="comment"></textarea>
<button type="submit">Submit</button>
</form>
<div id="comments">
{% for comment in comments %}
<div class="comment">
<p><strong>{{ comment[1] }}:</strong> {{ comment[2] }}</p>
</div>
{% endfor %}
</div
As you are returning a response from the post method (add_comment), you can skip AJAX use. Here is an example to load the comments on form submission.
app.py:
from flask import Flask, render_template, request, redirect, url_for
import sqlite3
app = Flask(__name__)
conn = sqlite3.connect('comments.db', check_same_thread=False)
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS comments
(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, comment TEXT)''')
conn.commit()
#app.route('/add_comment', methods=['POST'])
def add_comment():
name = request.form['name']
comment = request.form['comment']
c.execute("INSERT INTO comments (name, comment) VALUES (?, ?)", (name, comment))
conn.commit()
return redirect(url_for("view_comments"))
#app.route('/')
def view_comments():
c.execute("SELECT * FROM comments ORDER BY id DESC")
comments = c.fetchall()
return render_template('comment.html', comments=comments)
templates/comment.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Comments Example</title>
</head>
<body>
<form id="comment-form" action="{{ url_for('add_comment') }}" method="post">
<label for="name">Name:</label>
<input type="text" id="name" name="name">
<label for="comment">Comment:</label>
<textarea id="comment" name="comment"></textarea>
<button type="submit">Submit</button>
</form>
<div id="comments">
{% for comment in comments %}
<div class="comment">
<p><strong>{{ comment[1] }}:</strong> {{ comment[2] }}</p>
</div>
{% endfor %}
</div>
</body>
</html>
Output:

custom error message shows and disappears on submit

I am using flask, html, css and javascript. So what I did was enter a error message in my login form as a new and set display: none. I validate the input credential by comparing values from a SQLite database i set previously. This validation is done inside the flask. When the form is submitted, it is validated inside the flask, however I created a javascript that changes the styling for the error message to display: block. This would show the error message for incorrect fields and the correct input users will be redirected to a new page and hence they wont see the error.
So I was hoping that the error message shows after the form is submitted for the login and the users that key in the right information will be redirected.
Flask:
#app.route('/', methods=['POST', 'GET'])
def tutor_login():
tutor_login_form = LoginAccount(request.form)
if request.method == 'POST' and tutor_login_form.validate():
session.pop('user', None)
admin_account = Admin.query.all()
tutor_account = Tutor.query.all()
for i in admin_account:
admin_id = i.admin_id_num
for j in tutor_account:
tutor_id = j.tutor_id_num
if admin_id == tutor_login_form.id_num.data:
admin_info = Admin.query.filter_by(admin_id_num=tutor_login_form.id_num.data).first()
admin_pass = admin_info.admin_password
if admin_pass == tutor_login_form.password.data:
session['user'] = tutor_login_form.id_num.data
return redirect(url_for('admin_main'))
elif tutor_id == tutor_login_form.id_num.data:
tutor_info = Tutor.query.filter_by(id_num=tutor_login_form.id_num.data).first()
tutor_pass = tutor_info.tutor_password
if tutor_pass == tutor_login_form.password.data:
session['user'] = tutor_login_form.id_num.data
return redirect(url_for('retrieve_tutor_account'))
return render_template('tutorlogin.html')
HTML:
<form class="" action="" method="POST" onsubmit="validate()">
<!-- Input fields -->
<div class="form-group mt-3">
<label for="id_num">Enter Tutor ID:</label>
<input type="text" class="form-control" id="id_num" placeholder="Enter Tutor ID" name="id_num">
</div>
<div class="form-group my-3">
<label for="password">Enter Password:</label>
<input type="password" class="form-control password" id="password" placeholder="Enter Password" name="password">
</div>
<div class="mb-3 text-center" id="error">
ID or Password entered is invalid! Please try again.
</div>
<div class="text-center">
<button type="submit" class="btn btn-primary btn-customized">Login</button>
</div>
<div>
<p class="text-center my-3">Forgot your password? <br> Click here to reset</p>
</div>
</form>
Javascript:
<script>
var error = document.getElementById('error');
function validate(){
error.style.display = "block";
}
</script>
If you want to validate the credentials without a page reload, you need to use Ajax requests.
Where on clicking Submit, the JavaScript will first check if all fields all valid and filled and then send an Ajax request to the Flask app.
Depending on the response of the query you can either show a error message or redirect user to the page you want.
Here's a YouTube video for reference - https://www.youtube.com/watch?v=UmC26YXExJ4

Signup Form Isn't Connecting To Firebase Realtime Database & Authentication

I'm trying to connect my repl.it HTML and CSS website to Google Firebase using JavaScript for a school project and there is a signup form for a user to complete in order to signup to the website which should then take them to the login page where they can login and then proceed to customise their profile.
Once the user enters their first name, surname, email and password, it should validate the email (must have xxx#whatever.com or something along those lines) and password fields (more than 6 characters long) and click on the button "register now" it should send them directly to the login.html webpage where they log in with their details and then it will take them to their profile where they can customise it.
What should happen:
user enters their first name, surname, email and password
the email and password should be validated automatically with the password having the requirement of having to be over 6 characters and the email with the form of xxx#whatever.com (or something along those lines)
click the button "register now" and it should submit the data to the firebase realtime database and authentication users (I currently use the email and password sign up/in validation but I don't know how to get it to work)
user should be redirected to the login page where they login with their information
user clicks on login button then redirected to profile page
I've tried many alternatives and it was working a while back but I had no idea how to redirect the user to the login.html webpage so I messed around a bit and the code stopped working.
Now, in my current code, when the user enters their details, it doesn't even sumbit let alone clear the form.
So far this is what my javascript file looks like:
signup.js
function initializeApp() {
const firebaseConfig = {
apiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,
authDomain: xxxxxxxxxxxxxxxxxxxxxxxxx,
databaseURL: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,
projectId: xxxxxxxx,
storageBucket: xxxxxxxxxxxxxxxxxx,
messagingSenderId: xxxxxxxxxx,
appId: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
const firestore = firebase.firestore()
// Listen for form submit
const signupform = document.getElementById('signupform');
form.addEventListener('signupform', submitData);
const db = firestore.collection("signupform");
// Submit form
function submitData(e){
e.preventDefault();
//Get value
var fname = getInputVal('fname');
var sname = getInputVal('sname');
var email = getInputVal('email');
var password = getInputVal('password')
// Save message
saveMessage(fname, sname, email, password);
// Show alert
document.querySelector('.alert').style.display = 'block';
// Hide alert after 3 seconds
setTimeout(function(){
document.querySelector('.alert').style.display = 'none';
},3000);
// Clear form
document.getElementById('signupform').reset();
}
// Function to get form value
function getInputVal(id){
return document.getElementById(id).value;
}
// Save message to firebase
const saveMessage= function(fname, sname, email, password){
firestore.collection("signupform").add({
fname,
sname,
email,
password
})
}
}
This is what my HTML looks like and it's connected to my JS file:
signup.html
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="signup.js"></script>
<!-- The core Firebase JS SDK is always required and must be listed first -->
<script type="module" src="https://www.gstatic.com/firebasejs/xxxx/firebase-app.js"></script>
<!-- Add Firebase products that you want to use -->
<script type="module" src="https://www.gstatic.com/firebasejs/xxxx/firebase-auth.js"></script>
<script type="module" src="https://www.gstatic.com/firebasejs/xxxx/firebase-firestore.js"></script>
<script type="module" src="https://www.gstatic.com/firebasejs/xxxx/firebase-database.js"></script>
<title>Sign Up | QuizMe</title>
<link rel="stylesheet" href="signup.css">
<style>
#import url('https://fonts.googleapis.com/css2?family=Poppins:wght#300;400;500;600;700&display=swap');
</style>
<style>
#import url('https://fonts.googleapis.com/css2?family=Lobster+Two:ital,wght#1,700&display=swap');
</style>
<style>
#import url('https://fonts.googleapis.com/css2?family=Josefin+Sans&display=swap');
</style>
</head>
<body onload="initializeApp()">
<header class="page__header header">
<div class="header__container container">
<div class="header__body">
<div class="header__leftside">
QuizMe
</div>
<div class="header__rightside">
<div class="header__menu header-menu">
<ul class="header-menu__list">
<li class="header-menu__item">
Home
</li>
<li class="header-menu__item">
About
</li>
<li class="header-menu__item">
Play
</li>
<li class="header-menu__item">
Leaderboard
</li>
<li class="header-menu__item">
Profile
</li>
</ul>
</div>
<div class="header__mob">
<div class="header__mob-menu">
<i class='bx bx-menu' ></i>
</div>
</div>
</div>
</div>
</div>
</header>
<div class="main-container">
<div class="left">
</div>
<div class="right">
<div class="text-content">
<div class="main_div">
<div class="wrapper">
<div class="title">Registration</div>
<form action="#" id="signupform">
<div class="alert">Signup Successful!</div>
<div class="input-box">
<input type="text" class="form-control" id="fname" name="fname" placeholder="Enter your first name" required>
</div>
<div class="input-box">
<input type="text" class="form-control" id="sname" name="sname" placeholder="Enter your surname" required>
</div>
<div class="input-box">
<input type="text" class="form-control" id="email" name="email" placeholder="Enter your email" required>
</div>
<div class="input-box">
<input type="password" class="form-control" id="password" name="password" placeholder="Create password" required>
</div>
<div class="policy">
<input id="field_terms" onchange="this.setCustomValidity(validity.valueMissing ? 'Please indicate that you accept the Terms and Conditions' : '');" type="checkbox" required name="terms">
<h3>By signing up, you agree to our terms and conditions</h3>
</div>
<div class="input-box button">
<input type="submit" id="submitData" name="submitData" value="Register Now">
</div>
<div class="text">
<h3>Already have an account? Login now</h3>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<script>document.getElementById("field_terms").setCustomValidity("Please indicate that you accept the Terms and Conditions");</script>
</body>
</html>

How can i use filepond javascript library in Django template?

Intro: I have Django web app where users are allowed to create posts. Each post has multiple images that are associated with that post.
What I want to do: I want to use Filepond javascript library for remove, add more and previews of selected images.
The issue: The code below is working ok without filepond library but if i try to use filepond library the form is submitting only title input without files.
views.py
class NewsCreateView(CreateView):
form_class = FileForm
template_name = 'create.html'
success_url = '/'
def form_valid(self, form):
post = form.save(commit=False)
post.author = self.request.user
post.save()
for f in self.request.FILES.getlist('filepond'):
FileModel.objects.create(post=post, file=f)
return super().form_valid(form)
create.html
<link href="https://unpkg.com/filepond/dist/filepond.css" rel="stylesheet">
<link href="https://unpkg.com/filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css" rel="stylesheet">
<div class="content">
<div class="row">
<div class="col-md-12">
<div class="hpanel" style="margin-top: 10px;">
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group">
<input type="text" id="id_title" name="title" class="form-control">
<input type="file" id="id_file" name="file" multiple="true">
</div>
<button class=" btn btn-success btn-block" type="submit">Submit</button>
</form>
</div>
</div>
</div>
</div>
<script src="https://unpkg.com/filepond-plugin-image-preview/dist/filepond-plugin-image-preview.min.js"></script>
<script src="https://unpkg.com/filepond/dist/filepond.min.js"></script>
<script>
FilePond.registerPlugin(
FilePondPluginImagePreview
);
FilePond.create(
document.querySelector('input[type="file"]')
);
</script>
It's not possible to set a file input value, see: https://pqina.nl/blog/the-trouble-with-editing-and-uploading-files-in-the-browser/
So FilePond won't update the existing file input.
You either have to upload the file asynchronously by setting the FilePond server property or use the Filepond File Encode plugin to encode the file as base64 data which can be sent to the server as a string.

Making django html form perform 2 actions on submit

I'm working on a django web app, and there's an html form which I need to do 2 things when the form is submitted: create a record in the app's database and post some of the values collected to another website (e.g. a payment site).
The problem I'm having is getting the form to do the 2 things simultaneously. I know an HTML form can only have one action, and I've read some posts here on StackOverflow about using javascript to get the form to execute 2 or more actions, but everything I've tried so far hasn't worked for this situation. They all seem to get only one action to work.
This is what my django template looks like right now:
{% extends "some other template" %}
{% block content %}
<div>
...
<form id=form1" name="trans_form" method="POST" >
...
<!--DATA TO POST TO PAYMENT SITE-->
<input type="hidden" name="transaction_id" value="some value" />
<input type="hidden" name="transaction_amount" value="some value"/>
<input type="hidden" name="customer_id" value="some value" />
<input type="hidden" name="customer_name" value="some value" />
<!--DATA TO POST TO PAYMENT SITE-->
...
<!--DATA TO POST TO APP DATABASE-->
<input type="hidden" name="user" value="{{ user.id }}">
<input type="hidden" name="type" value="CC">
<input type="hidden" name="ref_no" value="{{ ref_no }}">
Amount: <input type="text" name="amount" id="id_amount" required />
Ref ##: <span>{{ ref_no }}</span>
Date: <span>{{ cur_date|date:'d/m/Y' }}</span>
Submit
<!--DATA TO POST TO APP DATABASE-->
...
</form>
...
</div>
{% endblock %}
{% block script %}
<script>
function submitForm()
{
createRecord(document.forms["trans_form"]);
sendToPay(document.forms["trans_form"]);
}
function sendToPay(f)
{
f.action= "www.paymentsite.com";
f.target = null;
f.onsubmit = null;
f.submit();
}
function createRecord(f)
{
f.action = "url to view that creates the record in database";
f.target = "_blank";
f.onsubmit = null;
f.submit();
}
</script>
{% endblock %}
What do you think? Am I trying to achieve the impossible? If not, point me in the right direction. Thanks.
Why not simply POST to the payment site from your controller:
def handle_payment(request):
post_to_payment_site(request)
write_payment_info_to_db(request)
def post_to_payment_site(request):
data = {'transaction_id': request.form['transaction_id',
# etc.
}
requests.post('payment-provider-url', data=data)
If you cannot accept POST data intended for your payment provider then you can do one of the following things:
Send your payment provider an XHR request - this requires that your payment provider properly implement CORS for the endpoint you are posting to. When that request completes, you can submit the form normally.
Change the target attribute of your form to point at an iframe or a new tab / window. Then, when the iframe loads, remove the target attribute, switch the action back to your endpoint and submit.
I finally solved my problem. I'm not sure it is the most efficient solution, but here it is.
I made one more HTML page to act as a middleman between my app and the payment site. It's a very simple page, practically a replica of the first form page but with only the required fields to be posted to the payment site. This way, there's no need for much JavaScript. Submitting the form creates a record in the app database, sends the needed data to the "middleman", which then posts the data to the payment site. The user never actually sees the middleman throughout the process.
Like I said, this might not be the most efficient solution, but it works fine.
First, here's the code for the views.py:
def write_payment_info_to_db(request):
dt = datetime.now()
form = Form()
err = False
if request.method == 'POST':
#Collect data to send to GTPay
transaction_id = request.POST['transaction_id']
transaction_amount = request.POST['transaction_amount']
customer_id = request.POST['customer_id']
customer_name = request.POST['customer_name']
#Create record in db for "valid" form data
form = Form(request.POST)
if form.is_valid():
form.save()
return render_to_response('middleman.html', {'transaction_id': transaction_id,
'transaction_amount': transaction_amount,
'customer_id': customer_id,
'customer_name': customer_name},
context_instance=RequestContext(request))
else:
err = form.errors
return ...
else:
return ...
And here's the middleman:
<html>
<body onload="document.submit2paymentsite_form.submit()">
<form name="submit2paymentsite_form" action="payment-provider-url" target="_self" method="POST">
{% csrf_token %}
<input type="hidden" name="transaction_id" value="{{ transaction_id }}" />
<input type="hidden" name="transaction_amount" value="{{ transaction_amount }}" />
<input type="hidden" name="customer_id" value="{{ customer_id }}" />
<input type="hidden" name="customer_name" value="{{ customer_name }}" />
</form>
</body>

Categories