Невозможно сохранить данные в sqlite db с помощью Python / SQLAlchemy (Flask)

#python #sqlite #flask #sqlalchemy #flask-sqlalchemy

#python #sqlite #flask #sqlalchemy #flask-sqlalchemy

Вопрос:

Здравствуйте, я борюсь с этой ошибкой уже несколько недель. В моем приложении python / flask мне нужно сохранить pw в таблице db user в SQLite с помощью SQLAlchemy. Кажется, что таблица создана правильно, когда я проверяю sqlite> .schema, там есть столбец pwd. Когда я запускаю приложение, оно возвращает ошибку, в которой говорится, что столбец pwd не существует (см. Ошибку ниже). Я несколько раз пытался удалить таблицу, пытаясь создать новую базу данных, но ничего, я думаю, что таблица создана правильно, но в коде должно быть что-то не так? Также может быть испорчена база данных, но я так не думаю.

Здесь я создаю таблицу и определяю класс User в соответствии с официальной документацией SQLAlchemy

 from flask import Flask 
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
from sqlalchemy import *

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///data-users.sqlite'
db = SQLAlchemy(app)

class User(db.Model):
    
    id = db.Column(db.Integer(), primary_key = True, autoincrement=True)
    username = db.Column(db.String(64), unique = True)
    pwd = db.Column(db.String())

    def __repr__(self):
        return '<User %r>' % self.username
  

Здесь я сохраняю пользовательские данные в таблице

         from store_user_db import User, db
        db.create_all()

        DICP_FTP_DESTINATION_PSW=self.submit_pwd()

        user = User(id=001,username="ita_itf",pwd=DICP_FTP_DESTINATION_PSW)
        db.session.add(user)
        db.session.commit()
  

Это ошибка:

 sqlalchemy.exc.OperationalError

OperationalError: (sqlite3.OperationalError) table user has no column named pwd
[SQL: INSERT INTO user (id, username, pwd) VALUES (?, ?, ?)]
[parameters: (1, 'ita_itf', <read-only buffer for 0x7efe495709f0, size -1, offset 0 at 0x7.....
  

Комментарии:

1. Как насчет вызова db.create_all() вашего определения класса модели пользователя? И я не думаю, что вам нужно добавлять meta и usertable

2. db.create_all() ничего не сделает, таблица уже создана в части метаданных(), если я удалю это, таблица не будет создана, насколько я понимаю, код в классе User предназначен только для определения класса user, а не для создания таблицы, для создания таблицы вы должны использовать функцию Table()

3. Поэтому, если я удалю код #CREATE TABLE с метаданными и т.д., Я повторно инициализирую базу данных, удаляю таблицу, затем запускаю приложение, сообщение об ошибке то же самое. В основном, как я и думал, не пытается сохранить данные в созданной мной таблице, а сохраняет их в несуществующей таблице.

4. Это необычно для использования meta и usertable таким образом, как вы используете их в чистых приложениях flask-sqlalchemy . Возможно, было бы полезно установить SQLALCHEMY_ECHO значение True в вашей конфигурации, чтобы мы могли видеть команды, которые отправляются в базу данных.

5. Хорошо, тогда предположим, что я не буду использовать meta, как мне создать новую таблицу в БД? что это за код?

Ответ №1:

У меня нет большого опыта работы с flask и SQLAlchemy, но вот пример приложения, которое работает для меня. Определения моделей взяты из документации и добавлена тестовая модель во время выполнения, чтобы проверить, способна ли она по-прежнему создавать новые таблицы, и это произошло.

Если у вас большое приложение, я бы предпочел использовать flask-migrate библиотеку, которая может создавать версионные миграции из ваших моделей для создания / изменения ваших таблиц.

 from datetime import datetime
from flask import Flask, request, flash, url_for, redirect, json
from flask_sqlalchemy import SQLAlchemy


app = Flask(__name__)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'

db = SQLAlchemy(app)

class User(db.Model):
    __tablename__ = "user"
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)

    def __repr__(self):
        return '<User %r>' % self.username

class Category(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50), nullable=False)

    def __repr__(self):
        return '<Category %r>' % self.name

class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(80), nullable=False)
    body = db.Column(db.Text, nullable=False)
    pub_date = db.Column(db.DateTime, nullable=False,
        default=datetime.utcnow)

    category_id = db.Column(db.Integer, db.ForeignKey('category.id'),
        nullable=False)
    category = db.relationship('Category',
        backref=db.backref('posts', lazy=True))

    def __repr__(self):
        return '<Post %r>' % self.title

class Test(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50), nullable=False)

    def __repr__(self):
        return '<Test %r>' % self.name

def insertAdminUser():
    admin = User(username='admin', email='admin@example.com')
    db.session.add(admin)
    db.session.commit()

@app.route('/insert-admin', methods = ['GET'])
def insertAdmin():
    insertAdminUser()

    return app.response_class(
        response=json.dumps({
            "message": "inserted"
        }),
        mimetype='application/json'
    )
if __name__ == '__main__':
   db.create_all()
   app.run(debug = True)

  

Комментарии:

1. хорошо, я вижу, поэтому я замечаю, что основное отличие заключается в том, что в коде, который вы разместили в def в классе User, он возвращает что-то, в то время как мой инициализация def ничего не возвращает, основываясь на коде, который я написал, как вы думаете, моя функция def пользовательского класса должна что-то возвращать? В моем случае я должен передать идентификатор, пользователя и пароль, поэтому должен вернуть их все? как мне написать это на практике? Я совсем новичок в python

2. В python __repr__ возвращает объектное представление класса и не требуется. И __init__ (конструктор) — это метод, вызываемый при создании нового экземпляра и не обязанный ничего возвращать. Вы можете определить / переопределить свой собственный __init__ метод. Я думаю, вам следует сначала узнать о ООП Python.

3. Здесь довольно хорошо объяснено, кажется таким простым, но таким образом это не создаст никакой таблицы в моей базе данных! flask-sqlalchemy.palletsprojects.com/en/2.x/quickstart

4. Я знаю, что о init действительно я говорил о repr

5. Если я сделаю это, как в статье, это даже не создаст файл db