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

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.

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.

Python Flask: sqlalchemy.exc.ArgumentError: Could not parse rfc1738 URL from string 'sqlite

I am learning Python Flask and I am working to a blog as personal project. I am using a combination of Flask and Sqlite but I am stuck because it seems that my system (I am using Windows 10) is not able to find the path to the database. This is my code:
from flask import Flask, render_template, request, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite: ////C:/Users/admin/Desktop/Blog_Project/blog.db'
db = SQLAlchemy(app)
class Blogpost(db.Model):
id = db.Column(db.Integer, primary_key = True)
title = db.Column(db.String(50))
subtitle = db.Column(db.String(50))
author = db.Column(db.String(20))
date_posted = db.Column(db.DateTime)
content = db.Column(db.Text)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/about')
def about():
return render_template('about.html')
#app.route('/post')
def post():
return render_template('post.html')
#app.route('/contact')
def contact():
return render_template('contact.html')
#app.route('/prova')
def prova():
return render_template('prova.html')
#app.route('/add')
def add():
return render_template('add.html')
#app.route('/addpost', methods=['POST'])
def addpost():
title = request.form['title']
subtitle = request.form['subtitle']
author = request.form["author"]
content = request.form['content']
post = Blogpost(title=title, subtitle=subtitle, author=author, content=content, date_posted=datetime.now())
db.session.add(post)
db.session.commit()
return redirect(url_for('index'))
if __name__ == "__main__":
app.run(debug = True)
But when I try to add a post in the corresponding webpage, I get this error:
sqlalchemy.exc.ArgumentError
sqlalchemy.exc.ArgumentError: Could not parse rfc1738 URL from string 'sqlite: ////C:/Users/admin/Desktop/Blog_Project/blog.db'
Actually the database should exist, since I see the file in my folder (the path is the one in the code)
Have you got any idea how I can solve the problem?
Try using double slashes:
sqlite: ////C:\\Users\\admin\\Desktop\\Blog_Project\\blog.db
or if you want to stay on windows, use the windows formation:
sqlite: ////C:\Users\admin\Desktop\Blog_Project\blog.db
you can learn more in this detailed answer: Windows path in Python
For the convenience of Linux and Windows users, I have summarized the solutions for this problem on Windows and Linux:
from sqlalchemy import create_engine
# relative path on Linux: with three slashes
e = create_engine('sqlite:///relative/path/to/database.db')
# absolute path on Linux: with four slashes
e = create_engine('sqlite:////absolute/path/to/database.db')
# absolute path on Windows
e = create_engine('sqlite:///C:\\absolute\\path\\to\\database.db')
For detailed documents: SQLAlchemy 1.4 Documentation
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///blog.db'

sqllite database with Flask not instantiating

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()

Cannot add comment to SQL db in python Flask app

I am new to programming and have setup a small website with a comments section on pythonanywhere.com, relaying heavily on their tutorial. But when I post a comment in the form, the comment is not added to the database and for some reason the program redirects me to the index page (the intention is to redirect to stay on the same page)
Any suggestions as to what I might be doing wrong would be greatly appreciated!
The pyhthon code:
import random
from flask import Flask, request, session, redirect, url_for, render_template, flash
from flask.ext.sqlalchemy import SQLAlchemy
from werkzeug.routing import RequestRedirect
app = Flask(__name__)
app.config["DEBUG"] = True
SQLALCHEMY_DATABASE_URI = "mysql+mysqlconnector://{username}:{password}#{hostname}/{databasename}".format(
username="username",
password="password",
hostname="hostname",
databasename="majaokholm$majaokholm",
)
app.config["SQLALCHEMY_DATABASE_URI"] = SQLALCHEMY_DATABASE_URI
app.config["SQLALCHEMY_POOL_RECYCLE"] = 299
db = SQLAlchemy(app)
class Comment(db.Model):
__tablename__ = "comments"
id = db.Column(db.Integer, primary_key=True)
content = db.Column(db.String(4096))
#app.route("/")
def index():
return render_template("index_page.html")
#app.route('/post', methods=["GET", "POST"])
def post():
if request.method == "GET":
return render_template("post_page.html", comments=Comment.query.all())
comment = Comment(content=request.form["contents"])
db.session.add(comment)
db.session.commit()
return redirect(url_for('post'))
and the form from the HTML template:
<form action="." method="POST">
<textarea class="form-control" name="contents" placeholder="Enter a
comment"></textarea>
<input type="submit" value="Post comment">
</form>
Thanks a lot in advance!
Currently, the action="." in the form actually points to the root of the current directory, which for /post happens to be just / and thus points to the index.
It's always better to use action="{{ url_for('your_target_view') }}" instead.
get rid of action=".", you can use action=""

Flask 405 Error

I keep getting this error when trying to insert some simple text into a db.
Method Not Allowed
The method is not allowed for the requested URL."
I'm moving from PHP to python so bear with me here.
The code is:
from flask import Flask, request, session, g, redirect, url_for, \
abort, render_template, flash
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:password#localhost/pythontest'
db = SQLAlchemy(app)
app = Flask(__name__)
#app.route('/justadded/')
def justadded():
cur = g.db.execute('select TerminalError, TerminalSolution from Submissions order by id desc')
entries = [dict(title=row[0], text=row[1]) for row in cur.fetchall()]
return render_template('view_all.html', entries=entries)
#app.route('/new', methods= "POST")
def newsolution():
if not request.method == 'POST':
abort(401)
g.db.execute('INSERT INTO Submissions (TerminalError, TerminalSolution, VALUES (?, ?)'
[request.form['TerminalError'], request.form['TerminalSolution']])
g.db.commit()
flash('Succesful')
return redirect(url_for('justadded'))
#app.route('/')
def index():
return render_template('index.html')
#app.route('/viewall/')
def viewall():
return render_template('view_all.html')
if __name__ == '__main__':
app.run()
And the html code for the form is:
<form action="/new" method="POST">
<input name="TerminalError" id="searchbar" type="text" placeholder="Paste Terminal error here...">
<input name="TerminalSolution" id="searchbar" type="text" placeholder="Paste Terminal solution here...">
<button type="submit" id="search" class="btn btn-primary">Contribute</button>
</form>
The error has nothing to do with inserting data into the database, it's the methods argument of your /new route.
Instead of this:
#app.route('/new', methods= "POST")
do this:
#app.route('/new', methods= ["POST"])
The list of valid methods needs to be given as an array.

Categories