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

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:

Related

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

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

Getting Django view dictionary key in Javascript, but instead of considering it a String, considers a Variable Name

I am doing a project in Django. In my views I send data to the HTML pages with dictionaries. I can easily access that data on HTML, but when I try to access it on Javascript I can't because Javascripts thinks it's a variable name.
For example, I have a log in page. If the credentials are wrong, I send them to the same page and tell them that the username or password are wrong. I want to keep the previously written username on the form, so the person only needs to rewrite the password. I send the username from the view to the Javascript, but I can't access it.
My view code:
def login_form(request):
assert isinstance(request, HttpRequest)
if 'username' and 'password' in request.POST:
user = request.POST['username']
passw = request.POST['password']
if rightcredentials(user,passw):
tparams = {
'message': 'login successful',
}
return render(request, 'about.html', tparams)
else:
tparams = {
'login' : 'failure1',
'username_info' : user
}
return render(request, 'login_form.html', tparams)
Javascript code:
{% if login == 'failure1' %}
<form action="." method="post">
{% csrf_token %}
<div class="program-info">
<h3 class="program-title">Sign Into Your Account</h3>
<p>Wrong Username or password</p>
<div class="form-group">
<input type="text" value="" class="form-control" name="username" id="username" placeholder="Username">
</div>
<div class="form-group">
<input type="password" class="form-control" name="password" placeholder="Password">
</div>
<button type="submit" class="btn btn-primary">Log In</button>
</div>
</form>
<script type="text/javascript">
{% autoescape off %}
var paramvalue = {{ username_info }}
{% endautoescape %}
document.getElementById("username").value = paramvalue;
</script>
{%endif%}
After inserting username: 'pedro' and the wrong password on the form I get the following error:
Uncaught ReferenceError: pedro is not defined
Is there a way to access the string username_info or a way to convert the variable name to a string?
Wrapping the {{ }} in quotation marks should do the trick
{% autoescape off %}
var paramvalue = "{{ username_info }}"
{% endautoescape %}

How do I create a function that is when I click the delete, it will ask me... in html

How do I create a function that is when I click the delete, it will ask me, if I click YES it will delete and, I click NO it won't delete and still stay that page.
I am using FLASK.
Here are my coding
<button class="button button2" style="float: right; font-size:30px;" onclick="deletefunction()">Delete it</button>
<script>
function deletefunction() {
if (confirm('Do you want to delete it?')) {
yourformelement.submit();
} else {
return false;
}
}
</script>
Here is an example of the jinga code :
<form action={{ url_for('delete_function') }} method=post>
<input type=hidden name="row_number" value="{{ row.number }}">
<button type="submit" onclick="return confirm('{{ 'Are you sure to delete ?'}}');return false;">{{"Delete"}}</button>
</form>
and in a working example:
from flask import Flask,request,abort,render_template_string
app = Flask(__name__)
#app.route("/", methods=["GET"])
def hello_world():
return render_template_string("""<!DOCTYPE html>
<html>
<head><title>Test</title></head>
<body>
<h1>Hello World</h1>
{% for number in [0,1,'b']%}
<h2>{{ number }}</h2>
<form action={{ url_for('delete_function') }} method=post>
<input type=hidden name="row_number" value="{{ number }}">
<button type="submit" onclick="return confirm('{{ 'Are you sure to delete ?'}}');return false;">{{"Delete"}}</button>
</form>
{% endfor %}
</body>
</html>
""")
#app.route("/delete-function", methods=["POST"])
def delete_function():
row_number = request.form['row_number'][:20]
try:
int_row_number = int(row_number)
except ValueError:
return abort(404)
return "Trying to delete row "+str(int_row_number)
if __name__ == '__main__':
app.run()

Get the value of a variable from http get or post

I have this html page:
<head>
<h1>Prueba TFG</h1>
</head>
<body>
<form method="POST" action="">
Introduce KeyWord <input type="text" name="key">
<input type="submit" name="submit" value="Submit">
</form>
</body>
I would like get the value of "name", the input of the page, using JavaScript and pass this value to python. How can i do that?
Thank you so much!
You can use flask, a Python webframework, and utilize its builtin capability to access data from a request:
First, create your HTML and store in a file named user_input.html:
<html>
<head>
<h1>Prueba TFG</h1>
</head>
<body>
<form method="POST" action="/">
Introduce KeyWord <input type="text" name="key">
<input type="submit" name="submit" value="Submit">
</form>
</body>
</html>
Then, create the routes with flask:
import flask
app = flask.Flask(__name__)
#app.route('/', methods=['GET', 'POST']):
def home():
if flask.request.method == 'POST':
keyword = flask.request.form['key']
#do something with keyword
return "<p>You entered {}</p>".format(keyword)
return flask.render_template('user_input.html')
However, to include javascript, you can use ajax with jquery to pass the variable to the script:
<html>
<head>
<h1>Prueba TFG</h1>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
</head>
<body>
Introduce KeyWord <input type="text" name="key" id='key'>
<button type='button' class='enter'>Submit</button>
<div id='result'></div>
</body>
<script>
$('document').ready(function(){
$('.enter').click(function(){
var value = $('#key').val();
$.ajax({
url: "/get_keyword",
type: "get",
data: {keyword:value},
success: function(response) {
$("#result").html(response);
$('#result').html(response);
},
error: function(xhr) {
}
});
});
});
</script>
</html>
In the app:
#app.route('/', methods=['GET', 'POST'])
def home():
return flask.render_template('user_input.html')
#app.route('/get_keyword')
value = flask.request.args.get('query')
return 'received value'

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