flask, database, sqlite3

Django, Flask, Bottle, WSGI, CGI…
Antworten
d4rkdr4g0n1
User
Beiträge: 8
Registriert: Montag 9. Februar 2015, 20:11

Hallo hab ein problem mit meiner Datenbank bzw. table in meiner Datenbank.

folgender Flask-Aufbau:
blog/
-blog.py
-sql.py
-comments.db

templates/
-welcome.html
-show_entry.html
-login.html

static/
-bootstrap css bzw js datein

blog.py

Code: Alles auswählen

import sqlite3
from flask import Flask, render_template, g, request, url_for, redirect

app = Flask(__name__)
app.database = 'comments.db'


@app.before_request
def before_request():
    g.db = sqlite3.connect("comments.db")


@app.teardown_request
def teardown_request(exception):
    if hasattr(g, 'db'):
        g.db.close()


@app.route('/')
def home():
    return 'Hello World!'


@app.route('/welcome')
def welcome():
    return render_template("welcome.html")


@app.route('/login', methods=['GET', 'POST'])
def login():
    error = None
    if request.method == 'POST':
        if request.form['username'] != 'admin' or request.form['password'] != 'admin':
            error = 'Invalid credentials. Please try again.'
        else:
            return redirect(url_for('home'))
    return render_template('login.html', error=error)


@app.route('/show_entry')
def show_entry():
    posts = g.db.execute("SELECT title, text FROM posts").fetchall()
    return render_template("show_entry.html", posts=posts)


if __name__ == '__main__':
    app.run(debug=True)
für die datenbank habe ich eine weitere Datei angelegt
sql.py

Code: Alles auswählen

import sqlite3


conn = sqlite3.connect('comments.db')

conn.execute('''CREATE TABLE posts
	(ID INTEGER PRIMARY KEY AUTOINCREMENT,
		title TEXT NOT NULL,
		text TEXT NOT NULL);''')
dannach noch die html-Datein:
login.html, welcome.html und
show_entry.html

Code: Alles auswählen

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>Flask Blog</title>
    <meta name="viewport" content="width=device-width, initial-scale1.0">
    <link href="static/bootstrap.min.css" rel="stylesheet" media="screen">
</head>
<body>

            <div class="container">
                <h3>Posts:</h3>
                {% for post in posts %}
                    <strong>Title:</strong> {{ post.title }}
                    <strong>Post:</strong>  {{ post.text }}
                <br>
                {% endfor %}
            </div>




</body>
</html>
die html datein befinden sich im templates Ordner

wenn ich den projekt ausführe und teste bekomme ich folgende Fehlermeldung raus.

sqlite3.OperationalError
OperationalError: no such table: posts

Code: Alles auswählen

posts = g.db.execute("SELECT title, text FROM posts").fetchall()
ich habe jedoch eine table in meiner comments.db datei
Wo liegt der Fehler hier ? Ich bin schon am verzweifeln warum das nicht funktioniert.

ps.:ich benutze python 2.7 und neuste flask version
BlackJack

@d4rkdr4g0n1: Bist Du sicher dass *das* die ``comments.db``-Datei ist die verwendet wird? Ist `blogs/`` zu dem Zeitpunkt tatsächlich das aktuelle Arbeitsverzeichnis?

Zum ``AUTOINCREMENT`` möchtest Du vielleicht noch mal in der SQLite-Dokumentation nachlesen ob Du das wirklich haben möchtest.
d4rkdr4g0n1
User
Beiträge: 8
Registriert: Montag 9. Februar 2015, 20:11

Ein kleiner eddit bei blog.py:

Code: Alles auswählen

@app.route('/show_entry')
def show_entry():
    g.db = before_request()
    cur = g.db.execute('SELECT title, text FROM posts')
    posts = [dict(title=row[0], text=row[1]) for row in cur.fetchall()]
    g.db.close()
    return render_template("show_entry.html", posts=posts)
Durch das AUTOINCREMENT habe ich mir erhofft später auf die DB via ID zuzugreifen. Es ist jedoch, für meinen Fall, unnötig nach dem ich mir die sqlite3 docu durchgelesen habe.
Somit habe ich es gelöscht.
Komischer weise wenn ich es in PyCharm 4.0.4 kompeliere, kommt immer wieder der selbe Fehler. (obwohl die DB connected ist)
Wenn ich aber händisch in der cmd die blog.py datei ausführe und dannach auf die Seite 127.0.0.1:5000/show_entry gehe, erscheint alles richtig und die Posts werden angezeigt.
BlackJack

@d4rkdr4g0n1: Ich bleibe bei meiner Vermutung mit dem aktuellen Arbeitsverzeichnis. Das wird in beiden Fällen einfach ein anderes sein. Und mit ”der” ``comments.db`` bist Du dann nicht verbunden sondern es wird halt beim `connect()` in einem anderen Verzeichnis eine ``comments.db`` angelegt. Der `connect()`-Aufruf schlägt ja nicht fehl wenn die Datei nicht existiert sondern legt sie dann einfach an. Eine Ausnahme wird dann nur ausgelöst wenn in dem Verzeichnis wo das passiert ein Problem beim anlegen der Datei besteht.

Die Zeilen 3 und 6 sollten da eigentlich nicht stehen. Genau für so etwas sind doch die Dekoratoren da um Funktionen zu registrieren die etwas am Anfang und am Ende von jeder Anfragebearbeitung machen. Und wenn man das schon lokal macht muss man das `Cursor`-Objekt auch nicht als Attribut an `g` binden.

Wenn Du (auch) über die Spaltennamen auf Ergebnisse zugreifen möchtest, dann schau Dir mal das `row_factory`-Attribut auf `Connection`-Objekten und `sqlite3.Row` an. Wobei ich an der Stelle wahrscheinlich schon auf eine Abstraktionsschicht wie SQLAlchemy zurückgreifen würde, denn sonst bekommt man Probleme wenn man irgendwann ein anderes RDBMS als SQLite als Datenhaltung verwenden möchte.
d4rkdr4g0n1
User
Beiträge: 8
Registriert: Montag 9. Februar 2015, 20:11

Ich habe das jetzt noch einmal überarbeitet und jetzt funktioniert der Eintrag in die DB(table wird gefunden). Bei PyCharm 4 kenn ich mich wohl nicht gut genug aus um die DB irgendwie in den Verzeichnis reinzubringen. Bin auf den Sublime Text Editor umgestiegen und da schau her alles funktioniert wie gewollt.

Hier noch mal der Code dazu:

Code: Alles auswählen

from flask import Flask, render_template, g, request, flash, redirect, url_for
import sqlite3

app = Flask(__name__)
app.secret_key = 'password'

def connect_db():
	return sqlite3.connect("test.db")

@app.before_request
def before_request():
    g.db = connect_db()

@app.teardown_request
def teardown_request(exception):
    db = getattr(g, 'db', None)
    if db is not None:
        db.close()


@app.route('/')
def show_entries():
	cur = g.db.execute('SELECT title, description from posts')
	entries = [dict(title=row[0], description=row[1]) for row in cur.fetchall()]
	return render_template('show_entry.html', entries=entries)

@app.route('/add', methods=['POST'])
def add_entry():
	g.db.execute('INSERT INTO posts (title, description) VALUES (?,?)', [request.form['title'], request.form['description']])
	g.db.commit()
	#flash('New entry was succesfully posted')
	return redirect(url_for('show_entries'))
	

if __name__ =='__main__':
	app.run(debug=True)
und die erforderlichen HTML-Dateien:

Code: Alles auswählen

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>Flask Blog</title>
    <meta name="viewport" content="width=device-width, initial-scale1.0">
    <link href="static/bootstrap.min.css" rel="stylesheet" media="screen">
</head>
<body>
            <div class="container">
            <h3>Schreib dein Post:</h3>
                <form action="{{ url_for('add_entry')}}" method="post" class="add-entry">
                    <dl>
                        <dt>Title:
                        <dd><input type="text" size="30" name="title">
                        <dt>Text:
                        <dd><textarea name="description" rows="5" cols="40"></textarea>
                        <dd><input type="submit" value="Share">
                    </dl>
                </form>  
                   <h3>Posts:</h3>
                   {% for post in entries %}
                      <br>
                      <strong>Title:</strong> {{ post.title }}
                      <strong>Post:</strong>  {{ post.description }}
                   {% endfor %}
           </div>
</body>
</html>
Ich versuche jetzt die Grundbausteine zu erlernen da ich die Funktionen ausbauen will (bin flask und python neuling :oops: ). Würde gerne noch eine TimeStamp-Funktion einfügen bin mir allerding nicht sicher ob das sqlite3 beherscht. Und somit werde ich wohl auf SQLAlchemy umsteigen müssen. Auch deswegen weil es viel leichter ist die Bilder in die DB einzubeziehen :?: :K

mfg Gregor

ps.: Danke für die rasche Hilfe BlackJack
Antworten