Why does adding Bootstrap stop my Flask application from working? - python

I am learning Flask for the first time so I created a basic application of adding names into an unordered list. The names which is inserted are taken input in a input field. Basically when I didn't add Bootstrap it was working fine but when I added Bootstrap it is doing nothing when I click the button.
Code when no Bootstrap
<form action="{{ url_for('index') }}" method="POST">
<input type="text" name="name" placeholder="Enter your name" style="border-radius: 20px;">
<button>Click Me!</button>
</form>
<ul>
{% for item in task %}
<li> {{ item }} </li>
{% endfor %}
</ul>
Code when Bootstrap added :
<form action="{{ url_for('index') }}" method="POST">
<div class="input-group col-lg-10 col-sm-6">
<input type="text" name="name" class="form-control" placeholder="Enter your name"
style="border-radius: 20px;">
<span class="input-group-btn">
<button class="btn btn-primary" type="button">Click Me!</button>
</span>
</div>
</form>
<ul>
{% for item in task %}
<li> {{ item }} </li>
{% endfor %}
</ul>
This is my application.py :
from flask import Flask
from flask import render_template,request
app = Flask(__name__)
task=[]
#app.route("/",methods=["GET","POST"])
def index():
if request.method=="POST":
name = request.form.get("name")
task.append(name)
return render_template("index.html",task=task)

Your problem probably is not Bootstrap but type="button".
If you use type="button" in <button> even without Bootstrap then you have the same problem.
You have to remove it or use type="submit".
In <button> you can use only
type="submit" to send form to server
type="reset" to clear form (without sending to server)
type="button" to create clickable button but it doesn't send to server and you can assign JavaScript code which run some function after clicking.
BTW: I'm not sure but maybe Bootstrap has some JavaScript file which you has to link in HTML to change button behavior when you use type="button".
Minimal working example
from flask import Flask
from flask import render_template_string, request
app = Flask(__name__)
#app.route("/", methods=["GET","POST"])
def index():
if request.method=="POST":
name = request.form.get("name")
print(name)
return render_template_string("""<form action="{{ url_for('index') }}" method="POST">
<input type="text" name="name" placeholder="Enter your name">
<br>
<button>Button without Type</button>
<br>
<button type="submit">Button type="Submit"</button>
<button type="reset">Button type="Reset"</button>
<button type="button">Button type="Button"</button>
<button type="button" onclick="alert('Clicked')">Button type="Button" with JavaScript</button>
<br>
<input type="submit" value='Input type="Submit"'/>
<input type="reset" value='Input type="Reset"'/>
<input type="button" value='Input type="Button"'/>
<input type="button" onclick="alert('Clicked')" value='Input type="Button" with JavaScript"'/>
</form>""")
app.run()
Doc: < button >, < input >

Change <button> to <input type=“submit” value=“Click Me! />. You can add whatever bootstrap classes you want to style this submit input like a button.

Related

Django UserCreationForm and Bootstrap Forms Layouts

I am trying to extend the UserCreationForm using a Bootstrap layout style for the field username. After the input tag in the registration form, I would like to add a div element like an example that I have readapted from the Bootstrap page: i.e. suggesting the user to enter the same username as the company domain.
Let's focus to the bare minimum. The form readapted from Bootstrap is:
<form class="row gy-2 gx-3 align-items-center method="POST" action="{% url 'register' %} ">
<div class="col-auto">
<div class="input-group">
<input type="text" name="username" class="form-control" placeholder="your.username" id="id_username">
<div class="input-group-text">#company.domain.com</div>
</div>
</div>
<div class="col-auto">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
Which produces the following:
For the moment, I am using only {{form.as_p}} in my html template file:
<form class="row gy-2 gx-3 align-items-center method="POST" action="{% url 'register' %} ">
{{form.as_p}}
<div class="col-auto">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
And I don't know how to add the <div class="input-group-text">#company.domain.com</div> part embedded in a <div class="input-group">...</div> block.
My actual forms.py is a bit more complex, but readapted for this minimum example it contains the widget attributes as follows:
class SignupForm(UserCreationForm):
username = forms.CharField(label="",
widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'your.username'}))
class Meta:
model = User
fields = (
'username',
)
Without additional libraries, is there a way to extend the widget attributes? Is it even possible to use {{form.as_p}} as I am currently doing or should I use another method?
If you want to use only {{ form.as_p }} with bootstrap then you need to install django-bootstrap.
Install it using pip:
pip install django-bootstrap4
After installation, add it in INSTALLED_APPS in settings.py file.
INSTALLED_APPS = [
'bootstrap4',
]
And in templates, you need to load it.
{% load bootstrap4 %}
{% bootstrap_messages %}
<form class="row gy-2 gx-3 align-items-center method="POST" action="{% url 'register' %} ">
{% csrf_token %}
{% bootstrap_form form %} # added `form` here. we don't need to use with as_p.
<div class="form-group">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
This is the way you can use bootstrap along with {{ form.as_p }}
OR
Try another way:
Simply you can use {{ form.username }} inside an input tag in template.
For Example:
<input type="text" value="{{ form.username }}">
<form class="row gy-2 gx-3 align-items-center method="POST" action="{% url 'register' %} ">
<div class="col-auto">
<div class="input-group">
<input type="text" name="username" class="form-control" placeholder="your.username" id="id_username" value="{{ form.username }}"> #Added here
<div class="input-group-text">#company.domain.com</div>
</div>
</div>
<div class="col-auto">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>

Two buttons in one form connect two different python function

The problem is that I have two buttons in a form. Additionally, both buttons are running though the same function. How do i force the "Save" button to run though a different function when clicked?
I can post the python code later if necessary.
<form action="/predict" class="form-upload" method="post" enctype="multipart/form-data">
<h1 class="h3 mb-3 font-weight-normal">Please Upload Image</h1>
<input autofocus class="form-control" id="image" name="image" required type="file"><br>
<button type = "submit" name = "predict" formaction="/predict" class="btn btn-lg btn-primary btn-block">Predict</button>
<button type = "submit" name = "save" formaction = "/add" class="btn btn-lg btn-primary btn-block" >Save</button>
{% if image_loc %}
<img id="img" class="mb-4" src="static/{{ image_loc }}" alt="" width="256" height="256">
<h3 id="nm" class="h3 mb-3 font-weight-normal">Prediction: {{ p }}</h3><br>
{% endif %}
</form>
You can use formaction attribute on the button. It overrides the action attribute of the form.
MDN

Why request.method is not getting invoked?

I have a read-only textbox which preloaded value from database which upon a button click sends it's value to a method present in backend to perform DELETE query of sql. The problem is occuring when I am click on the button the method is invoked but the request.method condition is not invoked. It is directly going to the end return statement of the method.
#app.route('/home/delete_reminder/<string:id_val>',methods=['GET','POST'])
#is_logged_in
def delete_reminder(id_val):
if request.method=='POST':
desc = request.form['description']
x = desc.split(',')
cur = mysql.connection.cursor()
cur.execute('DELETE FROM set_reminder WHERE DATE=%s,SUBJECT=%s,DESCRIPTION=%s',[x[0],x[1],x[2]])
cur.execute('DELETE FROM recur WHERE RECUR_NEXT=%s',[id_val])
flash('Reminder Deleted','danger')
mysql.connection.commit()
cur.close()
return redirect(url_for('search_reminder_to_delete'))
This is my backend code.
<form method="POST">
{% for data in value %}
<div class="form-group">
<label>Description</label>
<input type="text" name="description" class="form-control" readonly="true" value="{{data.DATE}},{{data.SUBJECT}},{{data.DESCRIPTION}}">
</div>
Delete Reminder
{% endfor %}
</form>
This is the html part.
Your button isn't a button, it's a link. You aren't submitting your form.
If you want to fo that then you need to make you form tag:
<form method="POST" action="/home/delete_reminder/{{data.RECUR_NEXT}}">
and switch your button to be a real button that submits the form:
<div class="button">
<button type="submit" class="btn btn-warning">Send your message</button>
</div>
EDIT: Seeing that you want to have multiple possible routes for your form based on the loop.
You could try and use the formaction attribute, although it isn't going to be supported by every browser version.
<form method="POST">
{% for data in value %}
<div class="form-group">
<label>Description</label>
<input type="text" name="description" class="form-control" readonly="true" value="{{data.DATE}},{{data.SUBJECT}},{{data.DESCRIPTION}}">
</div>
<div class="button">
<button formaction="/home/delete_reminder/{{data.RECUR_NEXT}}" class="btn btn-warning" type="submit" class="btn btn-warning">Delete Reminder</button>
</div>
{% endfor %}
However this will still result in your description field that is passed to the request having every single description from the whole form in a list or possibly just the last one as a single value (I can't quite remember the behaviour of multiple inputs with the same name), which I don't think is what you're expecting to happen.
It may just be easiest to create a separate form for each link in a loop to be honest:
{% for data in value %}
<form method="POST" action="/home/delete_reminder/{{data.RECUR_NEXT}}">
<div class="form-group">
<label>Description</label>
<input type="text" name="description" class="form-control" readonly="true" value="{{data.DATE}},{{data.SUBJECT}},{{data.DESCRIPTION}}">
</div>
<div class="button">
<button class="btn btn-warning" type="submit" class="btn btn-warning">Delete Reminder</button>
</div>
</form>
{% endfor %}

How to link user post with its session using flask and MongoDB?

I am trying to link users post using Flask. For instance, A user add a new product into the database from a form and it be displayed on its User template.
I don't know whether the post should be added to the database linked by user Id or I just need to use its session.
I have a simple function that I use in the form to insert the post into the collection but I don know whether I need to improve to link with the session user?
app.py:
#app.route('/insert_product', methods=['POST'])
def insert_product():
products=mongo.db.products
products.insert_one(request.form.to_dict())
return redirect(url_for('index'))
User template:
<form class="text-center border border-light p-5" action="{{url_for('insert_product')}}" method='POST'>
<p class="h4 mb-4">Add a new product</p>
<div class="form-row mb-4">
<!-- Category -->
<select class="form-control " name="category_name">
<option disabled selected>Select Category</option>
{% for cat in category %}
<option value='{{cat.category_name}}'>{{cat.category_name}}</option>
{% endfor %}
</select>
</div>
<!-- Product Name -->
<input type="text" id="product_name" name="product_name" class="form-control mb-4" placeholder="Product Name" required>
<!-- Price -->
<input type="number" min="1" step="any" id="#" name="price" class="form-control mb-4" placeholder="Price" required>
<input type="text" id="url" name="url" class="form-control mb-4" placeholder="Add Image URL"> {% if session['email'] != None %}
<input type="text" id="seller" name="seller" class="form-control mb-4" placeholder="Seller Name" value="{{session['name']}}" required> {% endif %}
<div class="form-group green-border-focus">
<textarea class="form-control" id="product_description" name='product_description' placeholder="Add product description" rows="3" required></textarea>
</div>
<!-- Sign up button -->
<button class="btn btn-info my-4 btn-block" type="submit">Submit</button>
<hr>
<!-- Terms of service -->
<p>By clicking
<em>Sign up</em> you agree to our
terms of service
</form>
I am able to display the post and all other CRUD functions. Just this small issue I would like to know to complete my project. Thank you.
I found the answer. I just needed to match the seller name into the collection with the section name using pymongo declaring it as a variable items=mongo.db.find({'seller':session.get('name')}) looping to retrieve the products/posts:
#app.route('/user')
def user():
items=mongo.db.products.find({'seller':session.get('name')})
category=mongo.db.category.find()
email = session.get('email')
if not email:
return redirect(url_for('login'))
return render_template('user.html', category=category, items=items)
Retrieving all the products done by its logged/session users:
{% for item in items%}
code here..
{% endfor %}

How create an array with checkboxes in Flask

I'm starting in flask, so i have many questions about it. And one of them is how to create an array based on name of the checkbox input?
In other words, python will follow the logic: for each of type "checkbox", which ones were filled?
I have those codes:
index.html
{% block content %}
<form method="POST" action="">
<div class="card" style="margin:50px 0">
<div class="card-header"><b>Letters</b></div>
<ul class="list-group list-group-flush">
<li class="list-group-item">A
<label class="switch ">
<input type="checkbox" name="A" class="danger">
<span class="slider round"></span>
</label>
</li>
<li class="list-group-item">B
<label class="switch ">
<input type="checkbox" name="B" class="danger">
<span class="slider round"></span>
</label>
</li>
<li class="list-group-item">C
<label class="switch ">
<input type="checkbox" name="C" class="danger">
<span class="slider round"></span>
</label>
</li>
</ul>
<button type="submit">Go</button>
</div>
</form>
{% endblock content %}
And funcs.py
from flask import Flask, render_template, url_for, redirect, request
app = Flask(__name__)
app.config['SECRET_KEY'] = '0000'
#app.route('/')
def index():
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
When the user has checked boxes named "A" and "C", python creates an array and display the array shortly afterwards when the user submit.
checked = ["A", "C"]
Your HTML is heading in the right direction, but a few minor changes for Flask to handle this effectively.
First, set the current value of the name attribute to the value attribute. This will determine values Flask pulls during the form post. Secondly, set the name attribute to have a common value.
<input type="checkbox" value="A" class="danger" name='my_checkbox'>
<input type="checkbox" value="B" class="danger" name='my_checkbox'>
<input type="checkbox" value="C" class="danger" name='my_checkbox'>
After the HTML is configured as such, you can use the getlist method from Flask's request module.
print(request.form.getlist('my_checkbox'))
>>> ['A', 'C']
When a POST request is sent to the flask server you can get form contents from request.form. which is a dictionary based off of the POST request.
With check boxes, if the box is ticked the input name in <input type="checkbox" name="A" class="danger"> would be in this dictionary. Therefore you can check for the check box like so:
if "A" in request.form:
checked.append("A") # You can of course append any arbitrary value

Categories