在Flask中使用数据库:从六月到六月

我之所以受到鼓舞,是因为我渴望帮助同样的Python新手,尤其是像我本人一样与Flask合作。当我们以新手未曾喜欢的方式进行全面,易懂的解释时,我不得不一点一点地寻找信息。没有照片。纯技术文章。有经验的人将感谢您提出意见并提出改进代码的提示。

因此,让我们开始吧。

新年刚过,我就开始学习Python。四个月后,我意识到,理论以及不被推崇的虚构任务的培训不会让您特别学习,所以我决定寻找“战斗”任务。为此,我问朋友们是否有需要编程的实际任务。一个“我的朋友朋友”要我为Telegram实施一个机器人程序(我想念该机器人程序的精髓;没关系-我需要执行有特定客户的任何任务,并根据客户的需要实施)。

为了寻找解决方案,很自然地,我开始的第一件事就是著名的Python Telegram BotpyTelegramBotAPI框架。。首先,作为一个初学者,在我看来只是一个发现-特别是在不了解代码细微差别的情况下,可以快速开始“锯”真正的bot。几天来,我发现无法创建所需的功能。看来他按照文档进行了所有操作,但尚未决定。然后,我意识到我根本不了解框架是如何“在幕后”工作的,以及为什么应该起作用的东西对我不起作用;应该在哪里调用什么命令以及使用什么方法调用。总的来说,我决定抛弃该框架,并尝试更深入地了解Telegram API本身的工作方式以及如何直接使用它,这将使我对情况有更多的控制权,也使我可以更深入地研究使用该API的整个厨房。可能由于不必要而不再使用Python Telegram Bot和pyTelegramBotAPI框架。或者,也许我会回来简化使用Telegram API创建自己的自行车的工作。但是,即使我回来了,我也会对这些框架的工作有更多的了解。

我有一个有关Udemy的未经审查的小型课程,只是为Telegram创建一个机器人。在撰写本文时,这是唯一一个Udemy课程,一个人可以在没有Python Telegram Bot和pyTelegramBotAPI的情况下解决问题(我不会给出链接,因此这不会是广告)。为了解决这个问题,他使用了Flask。顺便说一句,在这里,经过一定的“军事路线”之后,我有机会写下了关于该主题的课程,尽管当然还为时过早-我不会带来任何额外的价值。但是,如果您(经验丰富的程序员)阅读本文,并且对此有所了解,那么您可以创建自己的课程,并且我很乐意以10.99美元(这是Udemy的典型“折价”价)从您那里购买,以学习新的知识。

通常,从课程中,我意识到Flask将使我可以更轻松地处理GET和POST请求。

由于本文专门讨论了如何使用数据库,因此我将对此进行讨论。尽管一直以来,它总是试图描述其他细微之处,例如:将连接设置传输到“秘密”文件,接收和处理从Telegram API接收的数据,如何在没有ssl证书的情况下在本地计算机上接收来自Telegram的webhooks。如果您有兴趣,请告诉我,我将撰写另一篇文章。

在6月份的大约3-4天里,我才明白自己需要离开框架,然后才能自信地从电报中接收数据,处理文本(解析),并取决于用户写的内容,向他发送必要的命令以及按钮(包括覆盖消息和更改按钮)。

对我而言,下一步是连接数据库,以便在其中存储与该bot一起工作的用户,以及与他们在bot中交互有关的数据,这是他面临的任务的一部分。

我在Google所做的第一件事是哈布雷(Habré)的一篇文章,其中翻译了大型教科书米格尔·格林伯格Miguel Grinberg)他的博客原著在这里)。

第四章介绍使用Flask和SQLAlchemy ORM连接到数据库。然后我想:“哇,多么酷,现在问题解决了。”奇怪的是,但是作者建议的文件结构对我不起作用。

我像他一样做类比:

microblog\
  venv\
  app\
    __init__.py
    models.py
  main.py

在main.py中,我使用Telegram API进行了所有主要工作。
在app \ models.py中,我为数据库创建类。
在应用程序__ init__.py中,一切都按照Miguel Grinberg的操作完成。

但是由于某种原因,他们不想在main.py中将我从应用导入数据库app中拉出来。花了大约一个小时在Internet上搜索问题和解决方案。结果,Oleg Molchanov遇到了一个YouTube频道和他的视频“在Flask上创建博客(课程)-创建帖子(模型)和SQLAlchemy”。在那里,我观察了他如何与数据库建立连接,并尝试以这种方式进行操作(无需将models.py文件放入app目录中,而无需创建__init__.py。

通常,现在我的项目结构很容易让人羞辱(而且有点丑陋,这使我感到困惑,也许以后,我将了解如何改进结构):

图片

如您所见,我有app.py,models.py,main.py,app.sqlite(其余文件与当前主题无关)。

在app.py中,我有以下代码:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from config import Config

app = Flask(__name__)
app.config.from_object(Config)
db = SQLAlchemy(app)
migrate = Migrate(app, db)

在models.py中:

from datetime import datetime
from app import db

class Users(db.Model):
    #   
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(120), index=True, unique=True)
    last_name = db.Column(db.String(128))
    first_name = db.Column(db.String(128))
    created = db.Column(db.DateTime, default=datetime.now())
    tasks = db.relationship('Tasks', backref='tasks')

    #     
    # def __init__(self, *args, **kwargs):
    #     super(Users, self).__init__(*args, **kwargs)

    def __init__(self, username, last_name, first_name):
        self.username = username
        self.last_name = last_name
        self.first_name = first_name

    def __repr__(self):
        return '<User {}>'.format(self.username)


class Tasks(db.Model):
    #    
    __tablename__ = 'tasks'
    id = db.Column(db.Integer, primary_key=True)
    owner_id = db.Column(db.Integer(), db.ForeignKey('users.id'))
    name = db.Column(db.String(120), index=True)
    start = db.Column(db.Boolean, default=False)
    finish = db.Column(db.Boolean, default=False)
    created_on = db.Column(db.DateTime, default=datetime.now())
    updated_on = db.Column(db.DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow)

    #     
    def __init__(self, *args, **kwargs):
        super(Tasks, self).__init__(*args, **kwargs)

    # def __init__(self, name, last_name, first_name):
    #     self.name = name
    #     self.last_name = last_name
    #     self.first_name = first_name

    def __repr__(self):
        return '<Tasks {}>'.format(self.name)

在config.py中:

import os
from dotenv import load_dotenv
load_dotenv()

basedir = os.path.abspath(os.path.dirname(__file__))


#    
class Config(object):
    DEBUG = True
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'you-will-never-guess'
    # SQLALCHEMY_DATABASE_URI = 'postgresql+psycopg2://{user}:{pw}@{url}/{db}'.format(user=os.environ.get('POSTGRES_USER'),
    #                                                                                 pw=os.environ.get('POSTGRES_PW'),
    #                                                                                 url=os.environ.get('POSTGRES_URL'),
    #
    #                                                                                 db=os.environ.get('POSTGRES_DB'))
    SQLALCHEMY_DATABASE_URI = (os.environ.get('DATABASE_URL') or
                               'sqlite:///' + os.path.join(basedir, 'app.sqlite')) + '?check_same_thread=False'
    SQLALCHEMY_TRACK_MODIFICATIONS = False  # silence the deprecation warning

如您所知,我从设置中删除了连接的直接值,并将其呈现为.env,以便它们不会在产品或SVN中闪耀。

首先,在SQLALCHEMY_DATABASE_URI中将app.db(现在为app.sqlite)写入数据库。是的,是的,并按照说明Miguel Grinberg的指示写下来。我希望您了解需要用.sqlite替换它。在此之前,我想过一个小时的痛苦尝试来运行代码。

您可以通过转到调试控制台在sqlite中创建数据库和表(例如,在PyCharm中,我具有工具-> Python或调试控制台:

图片

在这里,我们首先将所需的方法连接到所需的文件中(我从模型import db中获得了该方法),成功连接后,指定db.create_all()命令。之后,将创建一个包含所有必要表的数据库。值得一提的是,如果我从应用程序import db中执行并运行db.create_all()命令,则似乎已创建了数据库文件,但这将是一种废话,而不是数据库(我不明白为什么)。

当我解决了这个问题时,我再次想到现在已经没有困难了。仅需为main.py编写一个函数,该函数在某些情况下会将数据从Telegram写入数据库。好吧,我从模型导入用户并在正确的位置连接了该函数:

try:
    find_user_in_db(username, first_name, last_name)
except NameError:
    print("user  ")
except:
    print("An exception occurred")

def add_users_to_db(username, last_name, first_name):
    """
        
    :return:
    """
    data = Users(username, last_name, first_name)
    db.session.add(data)
    db.session.commit()

def find_user_in_db(username, first_name, last_name):
    """
               
    :param username:
    :param first_name:
    :param last_name:
    :return:
    """
    user = db.session.query(Users).filter(Users.username == f'{username}').all()
    if not user:
        add_users_to_db(username, first_name, last_name)

在最后一个函数中,第一个代替user = db.session.query(Users).filter(Users.username == f'{username}')。First_or_404()代表Users.query.filter_by(username ='{username}')。 first_or_404()。在这里,我还花了大约半个小时来了解数据库中的此查询不起作用并且不接收任何数据,因此不会发送对数据库的查询。 Google提示了一篇小文章,其中有人说使用db.session.query(用户)更好。为什么这样,我xs并没有浪费时间进行分析。之后,数据开始被写入数据库。

本文到此结束,因为我描述了我想描述的内容并解决了将数据库连接到Flask的问题。

撰写本文仅出于阅读说明时我们“爱”六月的原因。我本人也试图找到将数据库连接到Flask的说明。我没有找到任何完整的说明,因此我不得不克服困难。好吧,我决定将自己的经历描述为下一位寻求现成说明的人。

PS谁正在寻找直接现成的解决方案,然后我问GitHub上存储库

PSS,如果有人进行代码审查并提出改进建议,我将感到非常高兴。

谢谢您的关注。

All Articles