sqllite database with Flask not instantiating - python

I'm trying to make a todo list web app with Flask. I need to make an instance of a database to store the tasks. For some reason when I try to make the instance it doesn't work. I am sure this is the issue because when I remove the part that uses the database from the code it runs fine.
Here is the code
from flask import Flask, render_template, request, redirect
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
flask1 = Flask(__name__)
# I think this is telling our app where to look for the database
# Three slashes == relative path. four == absolute path
flask1.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'
# initializing the database
db = SQLAlchemy(flask1)
class Todo(db.Model):
id = db.Column(db.Integer, primary_key=True)
content = db.Column(db.String(200), nullable=False)
date_created = db.Column(db.DateTime, default=datetime.ctime)
def __repr__(self):
return "<Task %r>" % self.id
# To actually instatiate the database
# 1- start python shell
# 2- import db
# 3- db.create_all()
# 4- exit shell
#flask1.route('/', methods=['POST', 'GET'])
def index():
if request.method == 'POST':
task_content = request.form['content']
new_task = Todo(content=task_content)
try:
db.session.add(new_task)
db.session.commit()
return redirect('/')
except:
return 'there was an issue adding the task'
else:
tasks = Todo.query.order_by(Todo.date_created).first
return render_template('index.html', tasks=tasks)
if __name__ == "__main__":
flask1.run(debug=True)
Now in the else block, if I return render_template like this
return render_template('index.html')
There is no error. This is because I use the tasks variable in my index.html file
Here is the code HTML code that generates the error
<!-- {% for task in tasks %} -->
<tr>
<td>{{ task.content }}</td>
<td> {{task.date_created.date }}</td>
<td>
delete
<br>
Update
</td>
</tr>
<!-- {% endfor %} -->
The error I'm getting right now is TypeError: 'NoneType' object is not iterable. I believe this means that the instance of my database was not successfully created.
I try to create the db instance in the following method
1- open python shell
2- import this script
3- db.create_all()
4- exit python shell
Any help is appreciated
Sorry for a long question

I think you meant to get all the tasks and call all():
tasks = Todo.query.order_by(Todo.date_created).all()

Related

Can't search any non-English [Unicode] using html form on flask app

I have 4 data table created with sqlalchemy + mysql.
2 is with English data and other 2 with Bangla[unicode] data. Everything is working fine when i search from my html form and showing the result from every table on my local computer.
after deploying on a cPanel based shared hosting non-English data not showing anymore. [ if i create loop every data shows but not showing any filter data when i search after hosting.
even when i use non-English url it's not working on production server. but in local computer works fine.
I don't know whats the porblem.
here all the code
app.py:
from flask import Flask, render_template, abort, session, redirect, request,url_for,make_response
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime,timedelta
from flask_admin import Admin
from flask_admin.contrib.sqla import ModelView
import sqlalchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = "mysql+pymysql://usernameisok:passwordisok#localhost/sobdarth_sobdartho"
app.config['SECRET_KEY'] = "tanvir.comahmedoke"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
admin = Admin(app)
Model:
This tables data not showing anything when i search but other English table works fine.
class BanglaBangla(db.Model):
word_id = db.Column(db.Integer, primary_key=True)
bn_word = db.Column(db.String(70), nullable=False)
word_type = db.Column(db.Text, nullable=True)
core_meaning = db.Column(db.Text, nullable=True)
bn_definition = db.Column(db.Text, nullable=True)
next = db.Column(db.String(70), nullable=True)
prev = db.Column(db.String(70), nullable=True)
def __repr__(self):
return f'<bn_to_bn id: {self.word_id}, word: {self.bn_word}>'
Routing:
#app.route("/bangla-to-bangla/")
def bn2bn():
try:
word1 = request.args.get('bangla2bangla')
return redirect(url_for('bn2bn_result', bn_word=word1))
except:
return render_template('files/bn2bn/bn2bn404.html')
#app.route("/bangla-to-bangla/<bn_word>")
def bn2bn_result(bn_word):
try:
bangla = BanglaBangla.query.filter_by(bn_word=bn_word).one()
return render_template('files/bn2bn/bn2bn.html', bn_word=bangla)
except:
return render_template("files/bn2bn/bn2bn404.html")
Templates:
<form method="get" action="/bangla-to-bangla/">
<input type="text" name="bangla" id="bangla" {% if bn_word.bn_word == None %} placeholder="Type Word..."{% else %} value="{{ bn_word.bn_word }}" {% endif %}>
<button>Search</button>
</form>
<div class="meaning outputs" >
<h1>{{ bn_word.bn_word }} Meaning In Bangla</h1>
<p><b>{{ bn_word.core_meaning }}</b> ({{ bn_word.word_type }})</p>
</div>
this is how i started my app with requirements.txt :
Click to check the image
Try to contact with your hosting provider maybe.
Not Sure Whats the problem. hope someone help you.

Why does my Flask-SQLAlchemy update query not change my table content

I'm making a flask website, in which I have a SQLite database with a table called mainscreen. On my home screen I have some text which is got from mainscreen - content column. I'm trying to retrieve the data from my textarea in my form which is supposed to update my mainscreen table. Although I'm correctly being redirected to my home.html, I can't see my changes being made, i.e my table is not gettng updated.
MainScreen table structure
|- mainscreen
|- id = integer - primary key
|- content = varchar(1000)
Required Code
flaskapp.py
from flask import Flask, render_template, [...]
from flask_login import [...]
from myproject.__init__ import User, MainScreen
from werkzeug.security import generate_password_hash,check_password_hash
from flask_sqlalchemy import SQLAlchemy
import os
app = Flask(__name__)
app.config['SECRET_KEY'] = [...]
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.abspath(os.path.join(os.path.dirname( __file__ ), 'data.sqlite'))
db = SQLAlchemy(app)
#app.route('/updated', methods=['POST', 'GET'])
def change_home():
if request.method == 'GET':
new_content = request.form.get('home', False)
mainContent = MainScreen.query.get(1)
mainContent.content = new_content
db.session.commit()
return redirect(url_for('home'))
else:
return redirect(url_for('login'))
#app.route('/loggedin', methods=['POST', 'GET'])
def login():
[... ...]
datas = {}
datas['content'] = onlycontent
return render_template('loggedin.html', data=datas)
myproject / __init __.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import [...]
from flask_login import UserMixin
import os
app = Flask(__name__)
db = SQLAlchemy(app)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.abspath(os.path.join(os.path.dirname( __file__ ), os.pardir, 'data.sqlite'))
class MainScreen(db.Model, UserMixin):
__tablename__ = 'mainscreen'
id = db.Column(db.Integer, primary_key=True)
content = db.Column(db.String(1000), unique=False, nullable=False)
def __init__(self, id, content):
self.id = id
self.content = content
def __repr__(self):
return f'<MainScreen {self.id} {self.content}>'
loggedin.html
<form action="{{url_for('change_home')}}" method="get">
<table>
<tr>
<td width="10%">
<h4>Home Page</h4>
</td>
<td class="padding-right:5%">
<textarea name="home" rows="7">{{data['content']}}</textarea>
</td>
<td>
<input type="submit" class="btn btn-primary"></input>
</td>
</tr>
</table>
</form>
home.html
#app.route('/home')
#app.route('/')
def home():
datas = {}
MainContent = MainScreen.query.get(1)
content = MainContent.content
datas['aboutme'] = content
return render_template('home.html', data=datas)
pip freeze
Flask==1.1.2
Flask-Login==0.5.0
Flask-Migrate==2.5.3
Flask-SQLAlchemy==2.4.4
SQLAlchemy==1.3.19
SQLAlchemy-Utils==0.33.2
Update 1
After setting some breakpoints, it appears that my new_content variable is not getting the data. It returns None. Since my content column is set to NOT NULL, that's probably the reason it's not getting updated. I need to figure out why my new_content variable is not retrieving the data
Update 2
It seems my variable mainContent.content is now getting updated - I had to retrieve the data by putting home in double quotes. Now my db.session.commit() doesn't seem to be working. From some online research I found that I might have made some errors in the way I'm initializing flask-sqlalchemy, so I've added some more code related to my initialisation. Thank you, your help is appreciated
It might be because you're sending the data over GET -- try request.args.get("home") instead and see if that works.
You're populating your text area with data['content']:
<textarea name="home" rows="7">{{data['content']}}</textarea>
This should be empty because you don't pass any value in data['content'] to render_template:
#app.route('/home')
#app.route('/')
def home():
datas = {} # empty dict
MainContent = MainScreen.query.get(1)
content = MainContent.content
datas['aboutme'] = content # set datas['aboutme'] but not datas['content']
return render_template('home.html', data=datas) # pass {'aboutme': content} to Jinja
You should either set datas['content'] = content in home() or access data['aboutme'] in loggedin.html.
Possible issue is due to that you are not passing mainContent to store it.
#app.route('/updated', methods=['POST', 'GET'])
def change_home():
if request.method == 'GET':
new_content = request.form.get('home', False)
mainContent = MainScreen.query.get(1)
mainContent.content = new_content
db.session.add(mainContent) # add this line and this should work
db.session.commit()
return redirect(url_for('home'))
else:
return redirect(url_for('login'))
Also your are trying to access form data in the GET method which I think doesn't contain form data that is in the front-end.
if request.method == 'GET':
new_content = request.form.get('home', False)
If you need to set some info, you either need to use POST to send the form data or you need to store in the session['<key>'] your expected value.
I hope this will help on finding the issue.

Flask : ValueError: not enough values to unpack (expected 2, got 1)

I am a Newbee in Python, Flask and API, and trying to learn it with my own project.
The API I am querying requires Basic Authentication.
Created a login.html and dashboard.html as templates of Flask.
Created a module myclasses.py
and the reporter.py which is the main module for Flask Views and other code.
login.html request user for IP, Username and Password which is captured in (/) view, and then forwarded to the Function defined in MyClasses.py using "call_api" to form the API and the function returns the Data.
Now I don't know and not sure how to proceed with forwarding the received data as json to (/dashboard) view for parsing and displaying in Dashboard template page.
from flask import Flask, render_template, url_for, redirect, request, json
from MyClasses import call_api
app = Flask(__name__)
data = "no data"
status_code = 0
#app.route('/dashboard')
def dashboard():
return render_template('dashboard.html', data=data, status_code=status_code)
#app.route('/', methods=["GET", "POST"])
def login():
if request.method == "POST":
creds = {'ipaddr': request.form['inip'],
'username': request.form['inusername'],
'password': request.form['inpassword'],
'entity': 'info'
}
request_dump = call_api(creds['ipaddr'], creds['username'], creds['password'], creds['entity'])
if request_dump[1] == 200:
global data
global status_code
data = (json.dumps(request_dump[0], indent=2))
status_code = request_dump[1]
return redirect(url_for('dashboard')), status_code, data
else:
return render_template('login.html')
else:
return render_template('login.html')
I am getting error, what does this means?
ValueError: not enough values to unpack (expected 2, got 1)
If I remove status_code, data, it works fine.
return redirect(url_for('dashboard')), status_code, data
for sure, I am not doing it the right way in many areas of this code.
Also, If you guys tell me on how to debug the code when flask is involved, I tried using breakpoints in PyCharm but code does not stops when I browse the templates.
Appreciate you help and Thank you for the time.
reconstructing the dictionary to a customized (data that I need) within the dashboard() as well as correcting the Flask template with {% for loop %} resolved the issue.
Flask Template snippet below:
<table class="containertbl">
<tbody>
{% for key,value in ddo.items() %}
<tr>
<th scope="row">{{ key }}</th>
<td>{{ value }}</td>
</tr>
{% endfor %}
</tbody>
</table>

Flask App will not load app.py (The file/path provided (app) does not appear to exist)

My flask app is outputting 'no content' for the for() block and i dont know why.
I tested my query in app.py , here is app.py:
# mysql config
app.config['MYSQL_DATABASE_USER'] = 'user'
app.config['MYSQL_DATABASE_PASSWORD'] = 'mypass'
app.config['MYSQL_DATABASE_DB'] = 'mydbname'
app.config['MYSQL_DATABASE_HOST'] = 'xxx.xxx.xxx.xxx'
mysql = MySQL()
mysql.init_app(app)
c = mysql.connect().cursor()
blogposts = c.execute("SELECT post_title, post_name FROM mydbname.wp_posts WHERE post_status='publish' ORDER BY RAND() LIMIT 3")
#app.route('/', methods=('GET', 'POST'))
def email():
form = EmailForm()
if request.method == 'POST':
if form.validate() == False:
return 'Please fill in all fields <p>Try Again</p>'
else:
msg = Message("Message from your visitor",
sender='contact#site.com',
recipients=['contact#site.com'])
msg.body = """
From: %s
""" % (form.email.data)
mail.send(msg)
#return "Successfully sent message!"
return render_template('email_submit_thankyou.html')
elif request.method == 'GET':
return render_template('index.html', blogposts)
This is what my app.py looks like.
Below is my index.html in templates/:
<ul>
{% for blogpost in blogposts %}
<li>{{blogpost[0]}}</li>
{% else %}
<li>no content...</li>
{% endfor %}
<div class="clearL"> </div>
</ul>
I checked the query, and it returns desired output like:
ID post_title post_name
1 a title here a-title-here
2 a title here2 a-title-here2
3 a title here3 a-title-here3
If i try to restart the dev server by running export FLASK APP=app.py', thenflask run`, i get an error of:
Error: The file/path provided (app) does not appear to exist. Please verify the path is correct. If app is not on PYTHONPATH, ensure the extension is .py
I've also tried running via export FLASK_APP=app.py then python -m flask run - this also gives the same error.
Thoughts on how to resolve?
You haven't got anything in your template called blogposts. You need to use keyword arguments to pass the data:
return render_template('index.html', blogposts=blogposts)
Also note you should really do that query inside the function, otherwise it will only ever execute on process start and you'll always have the same three posts.
I had same problem. I solved it as change directory of terminal to the folder containing app.py and then run
export FLASK_APP=app.py
then, you should run
python -m flask run

Unable to use flask.g to access variables in other functions

I'm trying to use flask.g to store variables that can be accessed in other functions, but I don't seem to be doing something correctly. The application generates the following error when I try to access g.name: AttributeError: '_RequestGlobals' object has no attribute 'name'.
The documentation for flask.g says:
Just store on this whatever you want. For example a database
connection or the user that is currently logged in.
Here's a complete, minimal example that illustrates the error that I receive when trying to access the variable outside of the function it was created in. Any help would be greatly appreciated.
#!/usr/bin/env python
from flask import Flask, render_template_string, request, redirect, url_for, g
from wtforms import Form, TextField
application = app = Flask('wsgi')
#app.route('/', methods=['GET', 'POST'])
def index():
form = LoginForm(request.form)
if request.method == 'POST' and form.validate():
name = form.name.data
g.name = name
# Need to create an instance of a class and access that in another route
#g.api = CustomApi(name)
return redirect(url_for('get_posts'))
else:
return render_template_string(template_form, form=form)
#app.route('/posts', methods=['GET'])
def get_posts():
# Need to access the instance of CustomApi here
#api = g.api
name = g.name
return render_template_string(name_template, name=name)
class LoginForm(Form):
name = TextField('Name')
template_form = """
{% block content %}
<h1>Enter your name</h1>
<form method="POST" action="/">
<div>{{ form.name.label }} {{ form.name() }}</div><br>
<button type="submit" class="btn">Submit</button>
</form>
{% endblock %}
"""
name_template = """
{% block content %}
<div>"Hello {{ name }}"</div><br>
{% endblock %}
"""
if __name__ == '__main__':
app.run(debug=True)
The g object is a request-based object and does not persist between requests, i.e. g is recreated between your request to index and your request to get_posts.
Application Globals in Flask:
Flask provides you with a special object that ensures it is only valid for the active request and that will return different values for each request. In a nutshell: it does the right thing, like it does for request and session.
For persistent storage of tiny data between requests use sessions instead. You may (but should not) get away with storing the data in the app object directly for global (all sessions) application state, similar to what config does, if you find a really good reason to do so.
For more complex data use databases.
If you need to track authentication information, I'd suggest one of the Flask plugins like Flask-Login or Flask-Principal.
For example, we use Flask-Principal. It raises the identity-loaded signal when somebody authenticates (or it detects an authentication cookie). We then map their logged-in identity with a user in our database. Something like this:
# not actual code
#identity_loaded.connect_via(app)
def on_identity_loaded(sender, identity):
user = Person.query.filter(Person.username==identity.person.username).one()
g.user = user
and then we can use g.user in any controller or template. (We're actually ripping a lot of this out, it was a easy, lazy hack that's caused more trouble than it's worth.)
If you don't want to use a module, there's a built-in signal you can hook into at the start of every request:
http://flask.pocoo.org/docs/tutorial/dbcon/
# This runs before every request
#app.before_request
def before_request():
g.user = your_magic_user_function()
and g.user would then be magically available everywhere.
I hope that helps!
Just use sessions in flask. In your case, you just want to save the user/name in your request and the easiest way is to use sessions.
from flask import session
app.secret_key = 'some key for session'
Then, your functions could be changed as below:
#app.route('/', methods=['GET', 'POST'])
def index():
form = LoginForm(request.form)
if request.method == 'POST' and form.validate():
session['name'] = form.name.data
return redirect(url_for('get_posts'))
else:
return render_template_string(template_form, form=form)
#app.route('/posts', methods=['GET'])
def get_posts():
if 'name' in session:
name = session['name']
else:
name = "Unknown"
return render_template_string(name_template, name=name)
I will like to shed more light on the use of g global in storing data. g only store data with a request and when redirecting to another route, the g global is set back to null i.e it reset back to nothing. This means whatever set to g in one request can't be access in another request. Use sessions to store data that will be accessed across request.
One benefit of using g global is when connecting to a database to fetct a user. For example, may be the admin from the database. The admin can be store in the g global using the below method.
from flask import Flask, g
app = Flask(__name__)
#app.before_request
def text():
g.a = User.query.filter_by(email='admin#gmail.com')
#app.route("/getTrue", methods=['GET', 'POST'])
def getTrue():
form = UserForm()
if form.validate_on_submit():
if g.a == form.email.data:
return "Admin is logged in"
else:
return "User is logged in"
return render_template('login.html', form=form)
In the example above, the g can be use to save data which will be use in another request. I hope this help. Thanks

Categories