Bekerja dengan database di Flask: dari Juni hingga Juni

Saya terinspirasi untuk menulis artikel ini dengan keinginan untuk membantu pendatang baru yang sama untuk Python secara umum dan untuk bekerja dengan Flask pada khususnya, seperti saya. Sambil mengerjakan tugas penjelasan yang holistik dan dapat dimengerti dalam gaya yang kami, para pendatang baru, tidak temukan. Saya harus mencari informasinya sedikit demi sedikit. Tidak akan ada gambar. Artikel murni teknis. Orang yang berpengalaman akan berterima kasih atas komentar dan tips memperbaiki kode.

Jadi mari kita mulai.

Saya mulai belajar Python setelah Tahun Baru. Setelah empat bulan, saya menyadari bahwa teorinya, serta pelatihan dalam tugas fiksi yang tidak masuk ke dalam dorongan, Anda tidak akan secara khusus belajar, saya memutuskan untuk mencari tugas "memerangi". Untuk melakukan ini, saya bertanya kepada teman-teman saya apakah mereka memiliki tugas nyata yang perlu diprogram. Satu "teman teman saya" meminta saya untuk mengimplementasikan bot untuk Telegram (saya kehilangan esensi dari bot; itu tidak masalah - saya perlu mengambil tugas apa pun yang memiliki pelanggan tertentu dan mengimplementasikannya sesuai keinginan pelanggan).

Dalam mencari solusi, wajar bahwa hal pertama yang saya mulai adalah Python Telegram Bot yang terkenal dan kerangka kerja pyTelegramBotAPI.. Pada awalnya, sebagai seorang pemula, menurut saya itu hanya sebuah penemuan - itu mungkin terutama tanpa memahami nuansa kode untuk dengan cepat mulai "menggergaji" bot asli. Selama beberapa hari saya menemukan fakta bahwa saya tidak dapat membuat fungsionalitas yang saya butuhkan. Tampaknya dia melakukan segalanya sesuai dengan dokumentasi, tetapi tidak diputuskan. Lalu saya menyadari bahwa saya tidak mengerti sama sekali bagaimana kerangka kerja bekerja "di bawah tenda" dan mengapa sesuatu yang seharusnya bekerja tidak bekerja untuk saya; di mana dan apa perintah harus dipanggil dan dengan metode apa. Secara umum, saya memutuskan untuk mengesampingkan kerangka kerja dan mencoba memahami lebih dalam bagaimana Telegram API itu sendiri bekerja dan bagaimana Anda dapat bekerja dengannya secara langsung, yang akan memberi saya lebih banyak kontrol atas situasi, dan juga memungkinkan saya untuk mempelajari lebih dekat seluruh dapur bekerja dengan API. Ada kemungkinan bahwa saya tidak akan kembali menggunakan Python Telegram Bot dan kerangka kerja pyTelegramBotAPI sebagai tidak perlu.Atau mungkin saya akan kembali untuk mempermudah pekerjaan saya membuat sepeda sendiri dengan API Telegram. Tetapi bahkan jika saya kembali, saya akan memahami lebih banyak tentang pekerjaan kerangka kerja ini.

Saya memiliki kursus kecil yang tidak ditinjau tentang Udemy hanya untuk membuat bot untuk Telegram. Pada saat penulisan ini, ini adalah satu-satunya kursus Udemy di mana seseorang akan menyelesaikan masalah tanpa Python Telegram Bot dan pyTelegramBotAPI (saya tidak akan memberikan tautan, sehingga ini bukan iklan). Untuk mengatasinya, ia menggunakan Flask. Di sini, omong-omong, setelah melalui "jalur militer" tertentu, saya memiliki kesempatan untuk menuliskan mata kuliah saya tentang hal ini, meskipun, tentu saja, terlalu dini - saya tidak akan membawa nilai tambahan. Tetapi jika Anda, seorang programmer yang lebih berpengalaman membaca artikel ini, tahu banyak tentang ini, maka Anda dapat membuat kursus Anda sendiri dan saya akan senang membelinya dari Anda dengan harga $ 10,99 (harga "diskon" khas untuk Udemy) untuk mempelajari sesuatu yang baru.

Secara umum, dari kursus, saya menyadari bahwa Flask akan memungkinkan saya untuk membuat hidup lebih mudah untuk memproses permintaan GET dan POST.

Karena artikel ini secara khusus dikhususkan untuk bekerja dengan database, saya akan membicarakan hal ini. Meskipun, sepanjang waktu, tergoda untuk menggambarkan kehalusan lainnya, seperti: mentransfer pengaturan koneksi ke file "rahasia", menerima dan memproses data yang diterima dari API Telegram, cara menerima kait web dari Telegram pada komputer lokal tanpa sertifikat ssl. Jika Anda berminat, beri tahu saya dan saya akan menulis artikel terpisah.

Sekitar 3-4 hari dari waktu Juni saya, saya perlu memahami bahwa saya harus menjauh dari kerangka kerja sebelum saya dapat dengan percaya diri menerima data dari Telegram, memproses teks (penguraian), dan bergantung pada apa yang ditulis pengguna, kirimkan perintah yang diperlukan, serta tombol (termasuk menimpa pesan dan mengubah tombol).

Langkah selanjutnya bagi saya adalah menghubungkan database untuk menyimpan pengguna yang bekerja dengan bot di dalamnya, serta data tentang interaksi mereka dalam bot sebagai bagian dari tugas yang menghadangnya.

Hal pertama yang saya lakukan di Google adalah artikel dari Habré dengan terjemahan buku teks besar Miguel Grinberg (yang asli dari blognya ada di sini ).

Bab keempat membahas koneksi ke database menggunakan Flask dan SQLAlchemy ORM. Lalu saya berpikir: "Wah, keren sekali, sekarang masalahnya sudah terpecahkan." Anehnya, tetapi struktur file yang penulis sarankan tidak bekerja untuk saya.

Saya melakukan dengan analogi seperti itu:

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

Di main.py, saya melakukan semua pekerjaan utama dengan API Telegram.
Di app \ models.py, saya membuat kelas untuk database.
Di app \ __ init__.py, semuanya dilakukan seperti yang ditulis Miguel Grinberg.

Tetapi untuk beberapa alasan, di main.py, mereka tidak ingin menarik saya dari aplikasi impor db, aplikasi. Menghabiskan sekitar satu jam mencari masalah, solusi di Internet. Akibatnya, Oleg Molchanov menemukan saluran YouTube dan videonya "Membuat Blog di Labu (pelajaran) - Membuat Posting (Model) dan SQLAlchemy". Di sana saya menyaksikan bagaimana dia membuat koneksi ke database dan mencoba untuk pergi dengan cara ini (tanpa meletakkan file models.py ke direktori app, tanpa membuat __init__.py.

Secara umum, sekarang struktur proyek saya mudah dipermalukan (dan sedikit jelek, yang membingungkan saya, mungkin di masa depan saya akan mengerti cara meningkatkan struktur):

gambar

Seperti yang Anda lihat, saya punya app.py, models.py, main.py, app.sqlite (sisa file tidak berhubungan dengan topik saat ini).

Di app.py saya memiliki kode ini:

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)

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

Di 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

Seperti yang sudah Anda pahami, dari pengaturan saya menghapus nilai langsung untuk koneksi dan membuatnya dalam .env sehingga mereka tidak akan bersinar pada prod atau di SVN.

Pertama, app.db (di mana app.sqlite sekarang) ditulis kepada saya dalam SQLALCHEMY_DATABASE_URI sebagai database. Ya, ya, dan tulis, seperti ditunjukkan dalam instruksi Miguel Grinberg. Saya harap Anda mengerti bahwa Anda perlu menggantinya dengan .sqlite. Sebelum itu, saya memikirkan satu jam setelah upaya menyakitkan untuk menjalankan kode.

Anda dapat membuat database dan tabel dalam sqlite dengan masuk ke konsol debugging (misalnya, di PyCharm Saya punya Alat -> Python atau Debug Console:

gambar

Di sini, pertama-tama kita menghubungkan metode yang kita butuhkan dalam file yang diinginkan (saya memilikinya dari model import db), dan setelah koneksi berhasil, tentukan perintah db.create_all (). Setelah itu, sebuah database dengan semua tabel yang diperlukan akan dibuat. Perlu diketahui bahwa jika saya melakukannya dari aplikasi import db dan menjalankan perintah db.create_all (), maka file database tampaknya dibuat, tetapi itu akan menjadi semacam omong kosong, dan bukan database (saya tidak mengerti mengapa).

Ketika saya memecahkan masalah ini, saya berpikir lagi bahwa sekarang tidak ada kesulitan yang tersisa. Tetap hanya menulis fungsi untuk main.py, yang, di bawah peristiwa tertentu, akan menulis data dari Telegram ke database. Yah, saya terhubung dari model impor Pengguna dan di tempat yang tepat disebut fungsi:

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)

Pada fungsi terakhir, pertama alih-alih user = db.session.query (Users) .filter (Users.username == f '{username}'). First_or_404 () berdiri Users.query.filter_by (username = '{username}'). first_or_404 (). Di sini saya juga menghabiskan sekitar setengah jam untuk memahami bahwa permintaan ini dalam database tidak berfungsi dan tidak menerima data apa pun, sehingga permintaan ke database tidak dikirim. Google meminta satu artikel kecil di mana orang mengatakan bahwa lebih baik menggunakan db.session.query (Pengguna). Mengapa begitu, saya xs, tidak membuang waktu menganalisis. Setelah itu, data mulai ditulis ke database.

Ini menyimpulkan artikel ini karena saya menggambarkan apa yang ingin saya gambarkan dan memecahkan masalah menghubungkan database ke Flask.

Artikel ini ditulis hanya untuk alasan bahwa kita “Juni” suka ketika membaca instruksi. Saya sendiri juga mencoba menemukan instruksi untuk menghubungkan database ke Flask. Saya tidak menemukan instruksi yang lengkap, jadi saya harus melewati rintangan. Yah, saya memutuskan untuk menggambarkan pengalaman saya sebagai orang berikutnya yang akan mencari instruksi yang sudah jadi.

PS Siapa yang mencari solusi langsung jadi, maka saya bertanya ke repositori di GitHub

PSS Saya akan senang jika seseorang melakukan review kode dan memberikan rekomendasi mereka untuk perbaikan.

Terimakasih atas perhatiannya.

All Articles