user14356245
user14356245

Reputation:

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

Upvotes: 1

Views: 1224

Answers (3)

Mo_-
Mo_-

Reputation: 634

It might be because you're sending the data over GET -- try request.args.get("home") instead and see if that works.

Upvotes: 1

simkusr
simkusr

Reputation: 812

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.

Upvotes: 0

oschlueter
oschlueter

Reputation: 2698

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.

Upvotes: 1

Related Questions