Hoe Flask-SQLAlchemy te gebruiken om te communiceren met databases in een Flask-toepassing

De auteur heeft het Free and Open Source Fund geselecteerd om een donatie te ontvangen als onderdeel van het Write for DOnations-programma.

Introductie

In webapplicaties heb je meestal een database nodig, wat een georganiseerde verzameling gegevens is. Je gebruikt een database om persistente gegevens op te slaan en te onderhouden die efficiënt kunnen worden opgehaald en bewerkt. Bijvoorbeeld, in een social media-applicatie heb je een database waar gebruikersgegevens (persoonlijke informatie, berichten, reacties, volgers) worden opgeslagen op een manier die efficiënt kan worden bewerkt. Je kunt gegevens toevoegen aan een database, deze ophalen, bewerken of verwijderen, afhankelijk van verschillende vereisten en voorwaarden. In een webapplicatie kunnen deze vereisten zijn dat een gebruiker een nieuw bericht toevoegt, een bericht verwijdert of hun account verwijdert, wat hun berichten al dan niet verwijdert. De handelingen die je uitvoert om gegevens te manipuleren, zullen afhangen van specifieke functies in je applicatie. Bijvoorbeeld, je wilt misschien niet dat gebruikers berichten zonder titels toevoegen.

Deploy je Flask-applicaties vanuit GitHub met behulp van DigitalOcean App Platform. Laat DigitalOcean zich richten op het schalen van je app.

Flask is een lichtgewicht Python webframework dat handige tools en functies biedt voor het maken van webapplicaties in de Python-taal. SQLAlchemy is een SQL toolkit die efficiënte en hoog presterende toegang tot databases biedt voor relationele databases. Het biedt manieren om te communiceren met verschillende database-engines zoals SQLite, MySQL en PostgreSQL. Het geeft je toegang tot de SQL-functionaliteiten van de database. Het geeft je ook een Object Relationele Mapper (ORM), waarmee je queries kunt uitvoeren en gegevens kunt verwerken met behulp van eenvoudige Python-objecten en -methoden. Flask-SQLAlchemy is een Flask-extensie die het gebruik van SQLAlchemy met Flask vergemakkelijkt, door tools en methoden te bieden om met je database te communiceren in je Flask-applicaties via SQLAlchemy.

In deze tutorial bouw je een klein studentenbeheersysteem dat laat zien hoe je de Flask-SQLAlchemy-extensie gebruikt. Je zult het met Flask gebruiken om basis taken uit te voeren, zoals verbinding maken met een databaseserver, een tabel maken, gegevens aan je tabel toevoegen, deze ophalen, en items in je database bijwerken en verwijderen. Je zult SQLAlchemy gebruiken met SQLite, hoewel je het ook met andere database-engines kunt gebruiken, zoals PostgreSQL en MySQL. SQLite werkt goed met Python omdat de Python-standaardbibliotheek de sqlite3-module biedt, die door SQLAlchemy op de achtergrond wordt gebruikt om te communiceren met SQLite-databases zonder dat er iets hoeft te worden geïnstalleerd. SQlite is standaard geïnstalleerd op Linux-systemen en wordt op Windows geïnstalleerd als onderdeel van het Python-pakket.

Vereisten

Stap 1 — Het installeren van Flask en Flask-SQLAlchemy

In deze stap installeert u de benodigde pakketten voor uw applicatie.

Met uw virtuele omgeving geactiveerd, gebruikt u pip om Flask en Flask-SQLAlchemy te installeren:

  1. pip install Flask Flask-SQLAlchemy

Zodra de installatie succesvol is voltooid, ziet u een regel die lijkt op de volgende aan het einde van de uitvoer:

Output
Successfully installed Flask-2.0.3 Flask-SQLAlchemy-2.5.1 Jinja2-3.0.3 MarkupSafe-2.1.0 SQLAlchemy-1.4.31 Werkzeug-2.0.3 click-8.0.4 greenlet-1.1.2 itsdangerous-2.1.0

Met de vereiste Python-pakketten geïnstalleerd, zult u vervolgens de database instellen.

Stap 2 — Het opzetten van de Database en het Model

In deze stap zul je je databaseverbinding opzetten en een SQLAlchemy database model maken, wat een Python-klasse is die de tabel vertegenwoordigt waarin je gegevens worden opgeslagen. Je zult de database initialiseren, een tabel voor studenten maken op basis van het model dat je zult verklaren, en een paar studenten toevoegen aan je studententabel.

Instellen van de Databaseverbinding

Open een bestand genaamd app.py in je flask_app-directory. Dit bestand bevat code voor het instellen van de database en je Flask-routes:

  1. nano app.py

Dit bestand zal verbinding maken met een SQLite-database genaamd database.db, en een klasse genaamd Student hebben die je database-studententabel vertegenwoordigt voor het opslaan van studenteninformatie, naast je Flask-routes. Voeg de volgende import-verklaringen toe aan de bovenkant van app.py:

flask_app/app.py
import os
from flask import Flask, render_template, request, url_for, redirect
from flask_sqlalchemy import SQLAlchemy

from sqlalchemy.sql import func

Hier importeer je het os-module, wat je toegang geeft tot diverse interfaces van het besturingssysteem. Je zult het gebruiken om een bestandspad te construeren voor je database.db-databestand.

Vanuit het flask-pakket importeer je vervolgens de nodige helpers die je nodig hebt voor je toepassing: de Flask-klasse om een instantie van een Flask-toepassing te maken, de render_template()-functie om sjablonen te renderen, het request-object om verzoeken te behandelen, de url_for()-functie om URL’s voor routes samen te stellen, en de redirect()-functie om gebruikers om te leiden. Voor meer informatie over routes en sjablonen, zie Hoe sjablonen te gebruiken in een Flask-toepassing.

Vervolgens importeer je de SQLAlchemy-klasse uit de Flask-SQLAlchemy-extensie, die je toegang geeft tot alle functies en klassen van SQLAlchemy, naast helpers en functionaliteit die Flask integreert met SQLAlchemy. Je zult het gebruiken om een database-object te maken dat verbinding maakt met je Flask-toepassing, waardoor je tabellen kunt maken en manipuleren met behulp van Python-klassen, objecten en functies zonder dat je de SQL-taal hoeft te gebruiken.

Je importeert ook de func-helper uit de sqlalchemy.sql-module om SQL-functies te benaderen. Je zult het nodig hebben in je studentenbeheersysteem om een standaard aanmaakdatum en -tijd in te stellen voor wanneer een studentenrecord wordt gemaakt.

Onder de imports stel je vervolgens het pad naar het databasebestand in, instantieer je je Flask-toepassing, en configureer en verbind je je toepassing met SQLAlchemy. Voeg de volgende code toe:

flask_app/app.py

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

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] =\
        'sqlite:///' + os.path.join(basedir, 'database.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)

Hier construeer je een pad voor je SQLite-databasebestand. Je definieert eerst een basisdirectory als de huidige directory. Je gebruikt de os.path.abspath() functie om het absolute pad van de huidige bestandsdirectory te krijgen. De speciale __file__ variabele bevat het pad van het huidige app.py bestand. Je slaat het absolute pad van de basisdirectory op in een variabele genaamd basedir.

Vervolgens maak je een Flask-toepassingsinstantie genaamd app, die je gebruikt om twee Flask-SQLAlchemy configuratie sleutels te configureren:

  • SQLALCHEMY_DATABASE_URI: De database-URI om de database aan te geven waarmee je een verbinding wilt tot stand brengen. In dit geval volgt de URI het formaat sqlite:///pad/naar/database.db. Je gebruikt de os.path.join() functie om intelligent de basisdirectory die je geconstrueerd en opgeslagen hebt in de variabele basedir, en de bestandsnaam database.db te combineren. Dit zal verbinden met een databasebestand database.db in je flask_app directory. Het bestand zal worden aangemaakt zodra je de database initialiseert.

  • SQLALCHEMY_TRACK_MODIFICATIONS: Een configuratie om het volgen van wijzigingen aan objecten in- of uit te schakelen. Je stelt het in op False om het volgen uit te schakelen en minder geheugen te gebruiken. Voor meer informatie, zie de configuratiepagina in de documentatie van Flask-SQLAlchemy.

Opmerking:

Als je een andere database-engine wilt gebruiken zoals PostgreSQL of MySQL, moet je de juiste URI gebruiken.

Voor PostgreSQL gebruik je het volgende formaat:

postgresql://username:password@host:port/database_name

Voor MySQL:

mysql://username:password@host:port/database_name

Zie voor meer informatie de SQLAlchemy-documentatie voor motorconfiguratie.

Nadat u SQLAlchemy heeft geconfigureerd door een database-URI in te stellen en het bijhouden uit te schakelen, maakt u een databaseobject met behulp van de SQLAlchemy-klasse, waarbij u de toepassingsinstantie doorgeeft om uw Flask-toepassing te verbinden met SQLAlchemy. U slaat uw databaseobject op in een variabele genaamd db. U zult dit db-object gebruiken om met uw database te communiceren.

De Tabel Declareren

Met de databaseverbinding tot stand gebracht en het databaseobject gemaakt, zult u het databaseobject gebruiken om een databasetabel voor studenten te maken, die wordt vertegenwoordigd door een model — een Python-klasse die erft van een basisklasse die Flask-SQLAlchemy biedt via de db-database-instantie die u eerder heeft aangemaakt. Om een studententabel als model te definiëren, voegt u de volgende klasse toe aan uw app.py-bestand:

flask_app/app.py
# ...

class Student(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    firstname = db.Column(db.String(100), nullable=False)
    lastname = db.Column(db.String(100), nullable=False)
    email = db.Column(db.String(80), unique=True, nullable=False)
    age = db.Column(db.Integer)
    created_at = db.Column(db.DateTime(timezone=True),
                           server_default=func.now())
    bio = db.Column(db.Text)

    def __repr__(self):
        return f'<Student {self.firstname}>'

Hier maakt u een Student-model, dat erft van de db.Model-klasse. Dit vertegenwoordigt de studententabel. U gebruikt de db.Column-klasse om kolommen voor uw tabel te definiëren. Het eerste argument vertegenwoordigt het kolomtype, en extra argumenten vertegenwoordigen kolomconfiguratie.

Je definieert de volgende kolommen voor het Student model:

  • id: Het studenten-ID. Je definieert het als een integer met db.Integer. primary_key=True definieert deze kolom als een primair sleutel, die door de database een unieke waarde zal toekennen voor elk invoer (dat is een student).
  • voornaam: De voornaam van de student. Een string met een maximale lengte van 100 karakters. nullable=False geeft aan dat deze kolom niet leeg mag zijn.
  • achternaam: De achternaam van de student. Een string met een maximale lengte van 100 karakters. nullable=False geeft aan dat deze kolom niet leeg mag zijn.
  • email: De e-mail van de student. Een string met een maximale lengte van 80 karakters. unique=True geeft aan dat elke e-mail uniek moet zijn voor elke student. nullable=False geeft aan dat deze kolom niet leeg mag zijn.
  • leeftijd: De leeftijd van de student.
  • created_at: De tijd waarop het studentenrecord is aangemaakt in de database. Je gebruikt db.DateTime om het te definiëren als een Python datetime object. timezone=True schakelt ondersteuning voor tijdzones in. server_default stelt de standaardwaarde in de database in bij het maken van de tabel, zodat standaardwaarden worden afgehandeld door de database in plaats van het model. Je geeft het de func.now() functie door die de SQL now() datetime functie aanroept. In SQLite wordt dit weergegeven als CURRENT_TIMESTAMP bij het maken van de studententabel.
  • bio: De biografie van de student. db.Text() geeft aan dat de kolom lange teksten bevat.

Zie de SQLAlchemy documentatie voor kolomtypen anders dan de typen die je hebt gebruikt in de voorgaande codeblok.

De speciale __repr__ functie stelt je in staat om elk object een stringweergave te geven om het te herkennen voor debugdoeleinden. In dit geval gebruik je de voornaam van de student.

Het app.py bestand ziet er nu als volgt uit:

flask_app/app.py
import os
from flask import Flask, render_template, request, url_for, redirect
from flask_sqlalchemy import SQLAlchemy

from sqlalchemy.sql import func


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

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] =\
        'sqlite:///' + os.path.join(basedir, 'database.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)


class Student(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    firstname = db.Column(db.String(100), nullable=False)
    lastname = db.Column(db.String(100), nullable=False)
    email = db.Column(db.String(80), unique=True, nullable=False)
    age = db.Column(db.Integer)
    created_at = db.Column(db.DateTime(timezone=True),
                           server_default=func.now())
    bio = db.Column(db.Text)

    def __repr__(self):
        return f'<Student {self.firstname}>'

Sla app.py op en sluit het.

Het maken van de database

Nu je de databaseverbinding en het studentenmodel hebt ingesteld, zul je de Flask-shell gebruiken om je database en je studententabel te maken op basis van het Student-model.

Met je virtuele omgeving geactiveerd, stel je het app.py-bestand in als je Flask-toepassing met behulp van de FLASK_APP-omgevingsvariabele. Open vervolgens de Flask-shell met het volgende commando in je flask_app-directory:

  1. export FLASK_APP=app
  2. flask shell

A Python interactive shell will be opened. This special shell runs commands in the context of your Flask application, so that the Flask-SQLAlchemy functions you’ll call are connected to your application.

Importeer het database-object en het studentenmodel, en voer vervolgens de functie db.create_all() uit om de tabellen te maken die zijn geassocieerd met je modellen. In dit geval heb je slechts één model, wat betekent dat het aanroepen van de functie slechts één tabel in je database zal maken:

  1. from app import db, Student
  2. db.create_all()

Laat de shell draaien, open een ander terminalvenster en navigeer naar je flask_app-directory. Je zult nu een nieuw bestand genaamd database.db zien in flask_app.

Let op:

De functie db.create_all() maakt geen tabel opnieuw aan of werkt deze niet bij als deze al bestaat. Bijvoorbeeld, als je je model wijzigt door een nieuwe kolom toe te voegen, en de functie db.create_all() uitvoert, wordt de wijziging die je aanbrengt in het model niet toegepast op de tabel als de tabel al bestaat in de database. De oplossing is om alle bestaande databasetabellen te verwijderen met de functie db.drop_all() en ze vervolgens opnieuw aan te maken met de functie db.create_all() zoals hier:

  1. db.drop_all()
  2. db.create_all()

Dit zal de wijzigingen toepassen die je aanbrengt in je modellen, maar zal ook alle bestaande gegevens in de database verwijderen. Om de database bij te werken en bestaande gegevens te behouden, moet je schema migratie gebruiken, waarmee je je tabellen kunt aanpassen en gegevens kunt behouden. Je kunt de Flask-Migrate-extensie gebruiken om SQLAlchemy-schema-migraties uit te voeren via de Flask-commandoregelinterface.

Als je een foutmelding ontvangt, controleer dan of je database-URI en je modelverklaring correct zijn.

Tabel Populeren

Nadat je de database en de studententabel hebt aangemaakt, zul je de flask-shell gebruiken om enkele studenten aan je database toe te voegen via het Student-model.

Gebruik dezelfde flask-shell die je eerder hebt geopend, of open een nieuwe met je virtuele omgeving geactiveerd in je flask_app-directory:

  1. flask shell

Om een ​​student toe te voegen aan uw database, importeert u het database-object en het Student-model, en maakt u een instantie van het Student-model door het studentengegevens door te geven via trefwoordargumenten zoals volgt:

  1. from app import db, Student
  2. student_john = Student(firstname='john', lastname='doe',
  3. email='[email protected]', age=23,
  4. bio='Biology student')

Het student_john-object vertegenwoordigt een student die aan de database zal worden toegevoegd, maar dit object is nog niet naar de database geschreven. Bekijk het object in de Flask-shell om de representatiestring te zien die u hebt geconstrueerd met de __repr__()-methode:

  1. student_john

U ontvangt de volgende uitvoer:

Output
<Student john>

U kunt de waarde van kolommen krijgen met behulp van de klasse-attributen die u hebt gedefinieerd in het Student-model:

  1. student_john.firstname
  2. student_john.bio
Output
'john' 'Biology student'

Omdat deze student nog niet aan de database is toegevoegd, zal de ID ervan None zijn:

  1. print(student_john.id)
Output
None

Om deze student aan de database toe te voegen, moet u deze eerst toevoegen aan een database-sessie, die een database-transactie beheert. Flask-SQLAlchemy biedt het db.session-object waarmee u uw database-wijzigingen kunt beheren. Voeg het student_john-object toe aan de sessie met behulp van de db.session.add()-methode om het voor te bereiden om naar de database te worden geschreven:

  1. db.session.add(student_john)

Dit zal een INSERT-statement uitgeven, maar u krijgt geen ID terug omdat de database-transactie nog steeds niet is vastgelegd. Om de transactie te bevestigen en de wijziging in de database toe te passen, gebruikt u de db.session.commit()-methode:

  1. db.session.commit()

Nu student John aan de database is toegevoegd, kunt u zijn ID krijgen:

  1. print(student_john.id)
Output
1

U kunt ook de db.session.add()-methode gebruiken om een item in de database te bewerken. Bijvoorbeeld, u kunt de e-mail van de student als volgt aanpassen:

  1. student_john.email = '[email protected]'
  2. db.session.add(student_john)
  3. db.session.commit()

Gebruik de Flask-shell om een paar meer studenten aan je database toe te voegen:

  1. sammy = Student(firstname='Sammy',
  2. lastname='Shark',
  3. email='[email protected]',
  4. age=20,
  5. bio='Marine biology student')
  6. carl = Student(firstname='Carl',
  7. lastname='White',
  8. email='[email protected]',
  9. age=22,
  10. bio='Marine geology student')
  11. db.session.add(sammy)
  12. db.session.add(carl)
  13. db.session.commit()

Nu kun je alle records in de studententabel opvragen met het query-attribuut met de all()-methode:

  1. Student.query.all()

Je ontvangt de volgende uitvoer:

Output
[<Student john>, <Student Sammy>, <Student Carl>]

Op dit punt heb je drie studenten in je database. Vervolgens maak je een Flask-route voor de startpagina en toon je alle studenten in je database erop.

Stap 3 — Alle Records Weergeven

In deze stap maak je een route en een sjabloon om alle studenten in de database op de startpagina weer te geven.

Laat de Flask-shell draaien en open een nieuw terminalvenster.

Open je app.py-bestand om een route voor de startpagina toe te voegen:

  1. nano app.py

Voeg de volgende route toe aan het einde van het bestand:

flask_app/app.py

# ...

@app.route('/')
def index():
    students = Student.query.all()
    return render_template('index.html', students=students)

Sla het bestand op en sluit het.

Hier maak je een index() weergavefunctie met behulp van de app.route() decorator. In deze functie vraag je de database op en haal je alle studenten op met behulp van het Student model met het query attribuut, waarmee je één of meer items uit de database kunt ophalen met verschillende methoden. Je gebruikt de all() methode om alle studentenvermeldingen in de database te krijgen. Je slaat het queryresultaat op in een variabele genaamd students en geeft deze door aan een sjabloon genaamd index.html die je rendert met behulp van de render_template() helperfunctie.

Voordat je het index.html sjabloonbestand maakt waarop je de bestaande studenten in de database zult weergeven, maak je eerst een basissjabloon, die alle basis-HTML-code zal bevatten die andere sjablonen ook zullen gebruiken om herhaling van code te voorkomen. Vervolgens maak je het index.html sjabloonbestand dat je hebt gerenderd in je index() functie. Voor meer informatie over sjablonen, zie Hoe sjablonen te gebruiken in een Flask-applicatie.

Maak een templates map aan, open dan een nieuw sjabloon genaamd base.html:

  1. mkdir templates
  2. nano templates/base.html

Voeg de volgende code toe binnen het base.html bestand:

flask_app/templates/base.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        .title {
            margin: 5px;
        }

        .content {
            margin: 5px;
            width: 100%;
            display: flex;
            flex-direction: row;
            flex-wrap: wrap;
        }

        .student {
            flex: 20%;
            padding: 10px;
            margin: 5px;
            background-color: #f3f3f3;
            inline-size: 100%;
        }

        .bio {
            padding: 10px;
            margin: 5px;
            background-color: #ffffff;
            color: #004835;
        }

        .name a {
            color: #00a36f;
            text-decoration: none;
        }

        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }
    </style>
</head>
<body>
    <nav>
        <a href="{{ url_for('index') }}">FlaskApp</a>
        <a href="#">Create</a>
        <a href="#">About</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>
</html>

Sla het bestand op en sluit het af.

Deze basissjabloon heeft alle HTML-boilerplate die je nodig hebt om te hergebruiken in je andere sjablonen. Het title-blok zal worden vervangen om een titel in te stellen voor elke pagina, en het content-blok zal worden vervangen door de inhoud van elke pagina. De navigatiebalk heeft drie links: een voor de indexpagina, die linkt naar de index()-weergavefunctie met behulp van de url_for()-hulpfunctie, een voor een Maak-pagina, en een voor een Over-pagina als je ervoor kiest om deze toe te voegen aan je applicatie. Je zult dit bestand later bewerken nadat je een pagina hebt toegevoegd voor het maken van nieuwe studenten om de Maak-link functioneel te maken.

Volgende, open een nieuw index.html-sjabloonbestand. Dit is het sjabloon waarnaar wordt verwezen in het app.py-bestand:

  1. nano templates/index.html

Voeg de volgende code eraan toe:

flask_app/templates/index.html
{% extends 'base.html' %}

{% block content %}
    <h1 class="title">{% block title %} Students {% endblock %}</h1>
    <div class="content">
        {% for student in students %}
            <div class="student">
                <p><b>#{{ student.id }}</b></p>
                <b>
                    <p class="name">{{ student.firstname }} {{ student.lastname }}</p>
                </b>
                <p>{{ student.email }}</p>
                <p>{{ student.age }} years old.</p>
                <p>Joined: {{ student.created_at }}</p>
                <div class="bio">
                    <h4>Bio</h4>
                    <p>{{ student.bio }}</p>
                </div>
            </div>
        {% endfor %}
    </div>
{% endblock %}

Sla het bestand op en sluit het.

Hier breid je de basissjabloon uit en vervang je de inhoud van het contentblok. Je gebruikt een <h1>-kop die ook dient als titel. Je gebruikt een Jinja for-loop in de regel {% for student in students %} om door elke student in de students-variabele te gaan die je hebt doorgegeven vanuit de index()-weergavefunctie naar dit sjabloon. Je toont de student-ID, hun voornaam en achternaam, e-mail, leeftijd, de datum waarop ze aan de database zijn toegevoegd, en hun bio.

Terwijl je in je flask_app map bent met je geactiveerde virtuele omgeving, vertel Flask over de applicatie (app.py in dit geval) door de FLASK_APP omgevingsvariabele te gebruiken. Stel vervolgens de FLASK_ENV omgevingsvariabele in op development om de applicatie in ontwikkelingsmodus uit te voeren en toegang te krijgen tot de debugger. Voor meer informatie over de Flask-debugger, zie Hoe fouten afhandelen in een Flask-toepassing. Gebruik de volgende opdrachten om dit te doen:

  1. export FLASK_APP=app
  2. export FLASK_ENV=development

Vervolgens, voer de applicatie uit:

  1. flask run

Met de ontwikkelingsserver actief, bezoek de volgende URL met je browser:

http://127.0.0.1:5000/

Je ziet de studenten die je aan de database hebt toegevoegd op een pagina die lijkt op de volgende:

Je hebt de studenten die in je database staan weergegeven op de indexpagina. Als volgende stap maak je een route voor een studentenpagina, waar je de gegevens van elke individuele student kunt tonen.

Stap 4 — Weergeven van een Enkel Record

In deze stap zul je de Flask-shell gebruiken om studenten op te vragen op basis van hun ID, en een route en een sjabloon maken om de gegevens van elke student op een aparte pagina weer te geven.

Tegen het einde van deze stap zal de URL http://127.0.0.1:5000/1 een pagina zijn die de eerste student weergeeft (omdat het de ID 1 heeft). De URL http://127.0.0.1:5000/ID zal de post weergeven met het bijbehorende ID nummer, indien aanwezig.

Laat de ontwikkelingsserver draaien en open een nieuw terminalvenster.

Open de Flask-shell voor een demonstratie van hoe je studenten kunt bevragen:

  1. flask shell

Om records op te vragen en gegevens uit de database op te halen, biedt Flask-SQLAlchemy een query attribuut op de modelklasse. Je kunt de methoden ervan gebruiken om records te krijgen met een specifieke filter.

Bijvoorbeeld, je kunt de filter_by() methode gebruiken met een parameter zoals voornaam die overeenkomt met een kolom in de tabel met een argument om een specifieke student op te halen:

  1. from app import db, Student
  2. Student.query.filter_by(firstname='Sammy').all()
Output
[<Student Sammy>]

Hier haal je alle studenten op met Sammy als hun voornaam. Je gebruikt de all() methode om een lijst van alle resultaten te krijgen. Om het eerste resultaat te krijgen, wat hier het enige resultaat is, kun je de first() methode gebruiken:

  1. Student.query.filter_by(firstname='Sammy').first()
Output
<Student Sammy>

Om een student op te halen via zijn ID, kun je filter_by(id=ID) gebruiken:

  1. Student.query.filter_by(id=3).first()

Of je kunt de kortere get() methode gebruiken, waarmee je een specifiek item kunt ophalen met behulp van zijn primaire sleutel:

  1. Student.query.get(3)

Beide zullen hetzelfde resultaat opleveren:

Output
<Student Carl>

Je kunt nu de shell verlaten:

  1. exit()

Om een ​​student op te halen aan de hand van hun ID, maak je een nieuwe route aan die een pagina rendert voor elke individuele student. Je zult de get_or_404()-methode gebruiken die Flask-SQLAlchemy biedt, wat een variant is van de get()-methode. Het verschil is dat get() de waarde None retourneert wanneer er geen resultaat overeenkomt met het opgegeven ID, en get_or_404() een 404 Not Found HTTP-reactie retourneert. Open app.py voor wijziging:

  1. nano app.py

Voeg de volgende route toe aan het einde van het bestand:

flask_app/app.py
# ...

@app.route('/<int:student_id>/')
def student(student_id):
    student = Student.query.get_or_404(student_id)
    return render_template('student.html', student=student)

Sla het bestand op en sluit het.

Hier gebruik je de route '/<int:student_id>/', met int: als een converter die de standaardstring in de URL omzet naar een geheel getal. En student_id is de URL-variabele die de student zal bepalen die je op de pagina zult weergeven.

Het ID wordt doorgegeven vanuit de URL naar de student()-weergavefunctie via de student_id-parameter. Binnen de functie vraag je de studentencollectie op en haal je een student op aan de hand van het ID met behulp van de get_or_404()-methode. Dit zal de studentgegevens opslaan in de student-variabele als deze bestaat, en reageren met een 404 Not Found HTTP-fout als er geen student met het opgegeven ID bestaat in de database.

Je rendert een sjabloon genaamd student.html en geeft deze de opgehaalde student door.

Open dit nieuwe student.html-sjabloonbestand:

  1. nano templates/student.html

Typ het volgende code in dit nieuwe student.html bestand. Dit zal vergelijkbaar zijn met het index.html sjabloon, behalve dat het alleen een enkele student zal weergeven:

flask_app/templates/student.html
{% extends 'base.html' %}

{% block content %}
    <span class="title">
        <h1>{% block title %} {{ student.firstname }} {{ student.lastname }}{% endblock %}</h1>
    </span>
    <div class="content">
            <div class="student">
                <p><b>#{{ student.id }}</b></p>
                <b>
                    <p class="name">{{ student.firstname }} {{ student.lastname }}</p>
                </b>
                <p>{{ student.email }}</p>
                <p>{{ student.age }} years old.</p>
                <p>Joined: {{ student.created_at }}</p>
                <div class="bio">
                    <h4>Bio</h4>
                    <p>{{ student.bio }}</p>
                </div>
            </div>
    </div>
{% endblock %}

Bewaar en sluit het bestand.

In dit bestand breid je het basissjabloon uit, waarbij je de volledige naam van de student instelt als titel voor de pagina. Je toont de student-ID, de voornaam en achternaam van de student, e-mail, leeftijd, de datum van de creatie van het record en hun bio.

Gebruik je browser om naar de URL voor de tweede student te navigeren:

http://127.0.0.1:5000/2

Je zult een pagina zien die vergelijkbaar is met de volgende:

Nu bewerk je index.html om elke studentennaam te laten linken naar hun pagina:

  1. nano templates/index.html

Bewerk de for loop zodat deze er als volgt uitziet:

flask_app/templates/index.html
{% for student in students %}
    <div class="student">
        <p><b>#{{ student.id }}</b></p>
        <b>
            <p class="name">
                <a href="{{ url_for('student', student_id=student.id)}}">
                    {{ student.firstname }} {{ student.lastname }}
                </a>
            </p>
        </b>
        <p>{{ student.email }}</p>
        <p>{{ student.age }} years old.</p>
        <p>Joined: {{ student.created_at }}</p>
        <div class="bio">
            <h4>Bio</h4>
            <p>{{ student.bio }}</p>
        </div>
    </div>
{% endfor %}

Bewaar en sluit het bestand.

Je hebt een <a> tag toegevoegd aan de volledige naam van de student die linkt naar de studentpagina met behulp van de url_for() functie, waarbij de student-ID die is opgeslagen in student.id wordt doorgegeven aan de student() view functie.

Navigeer naar je indexpagina of vernieuw deze:

http://127.0.0.1:5000/

Je zult nu zien dat elke studentennaam linkt naar de juiste studentpagina.

Na het maken van een pagina voor individuele studenten, voeg je vervolgens een pagina toe voor het toevoegen van nieuwe studenten aan de database.

Stap 5 — Het maken van een nieuw record

In deze stap voeg je een nieuwe route toe aan je applicatie voor het toevoegen van nieuwe studenten aan de database met behulp van webformulieren.

Je rendert een pagina met een webformulier waar gebruikers de gegevens van de student invoeren. Vervolgens verwerk je de formulierinzending, maak je een object aan voor de nieuwe student met behulp van het Student-model, voeg je het toe aan de sessie en commit je de transactie, vergelijkbaar met hoe je studentenvermeldingen hebt toegevoegd in Stap 2.

Laat de ontwikkelingsserver draaien en open een nieuw terminalvenster.

Open eerst je app.py-bestand:

  1. nano app.py

Voeg de volgende route toe aan het einde van het app.py-bestand:

flask_app/app.py
# ...


@app.route('/create/', methods=('GET', 'POST'))
def create():
    return render_template('create.html')

Sla het bestand op en sluit het.

In deze route geef je de tupel ('GET', 'POST') door aan de methods-parameter om zowel GET- als POST-verzoeken toe te staan. GET-verzoeken worden gebruikt om gegevens van de server op te halen. POST-verzoeken worden gebruikt om gegevens naar een specifieke route te verzenden. Standaard zijn alleen GET-verzoeken toegestaan. Wanneer de gebruiker voor het eerst de /create-route opvraagt met een GET-verzoek, wordt een sjabloonbestand genaamd create.html weergegeven. Je zult deze route later bewerken om POST-verzoeken af te handelen wanneer gebruikers het webformulier invullen en verzenden om nieuwe studenten toe te voegen.

Open het nieuwe sjabloonbestand create.html:

  1. nano templates/create.html

Voeg de volgende code eraan toe:

{% extends 'base.html' %}

{% block content %}
    <h1 style="width: 100%">{% block title %} Add a New Student {% endblock %}</h1>
    <form method="post">
        <p>
            <label for="firstname">First Name</label>
            <input type="text" name="firstname"
                   placeholder="First name">
            </input>
        </p>

        <p>
            <label for="lastname">Last Name</label>
            <input type="text" name="lastname"
                   placeholder="Last name">
            </input>
        </p>

        <p>
            <label for="email">Email</label>
            <input type="email" name="email"
                   placeholder="Student email">
            </input>
        </p>

        <p>
            <label for="age">Age</label>
            <input type="number" name="age"
                   placeholder="Age">
            </input>
        </p>

        <p>
        <label for="bio">Bio</label>
        <br>
        <textarea name="bio"
                  placeholder="Bio"
                  rows="15"
                  cols="60"
                  ></textarea>
        </p>
        <p>
            <button type="submit">Submit</button>
        </p>
    </form>
{% endblock %}

Sla het bestand op en sluit het.

U breidt het basissjabloon uit, stelt een kop in als titel en gebruikt een <form>-tag met het attribuut method ingesteld op post om aan te geven dat het formulier een POST-verzoek zal verzenden.

U heeft twee tekstvelden met de namen voornaam en achternaam. U zult deze namen gebruiken om later toegang te krijgen tot de formuliergegevens die de gebruiker indient in uw weergavefunctie.

U heeft een e-mailveld met de naam e-mail, een nummerveld voor de leeftijd van de student, en een tekstgebied voor de biografie van de student.

Tenslotte heeft u een Verzenden-knop aan het einde van het formulier.

Nu, met de ontwikkelingsserver actief, navigeert u met uw browser naar de /create-route:

http://127.0.0.1:5000/create

U ziet een pagina Een nieuwe student toevoegen met een webformulier en een Verzenden-knop zoals hieronder:

Als u het formulier invult en verzendt, waarbij u een POST-verzoek naar de server stuurt, gebeurt er niets omdat u geen POST-verzoeken heeft afgehandeld op de /create-route.

Open app.py om het POST-verzoek te behandelen dat de gebruiker indient:

  1. nano app.py

Bewerk de /create-route zodat deze er als volgt uitziet:

flask_app/app.py

@app.route('/create/', methods=('GET', 'POST'))
def create():
    if request.method == 'POST':
        firstname = request.form['firstname']
        lastname = request.form['lastname']
        email = request.form['email']
        age = int(request.form['age'])
        bio = request.form['bio']
        student = Student(firstname=firstname,
                          lastname=lastname,
                          email=email,
                          age=age,
                          bio=bio)
        db.session.add(student)
        db.session.commit()

        return redirect(url_for('index'))

    return render_template('create.html')

Sla het bestand op en sluit het.

Je verwerkt POST-verzoeken binnen de if request.method == 'POST'-voorwaarde. Je haalt de voornaam, achternaam, e-mail, leeftijd en biografie van de gebruiker op uit het request.form-object. Je converteert de leeftijd die als een string wordt doorgegeven naar een integer met behulp van de int()-Python-functie. Je construeert een student-object met behulp van het Student-model. Je voegt het studentobject toe aan de database sessie en commit de transactie.

Ten slotte stuur je de gebruiker door naar de indexpagina waar ze de nieuw toegevoegde student onder de bestaande studenten kunnen zien.

Met de ontwikkelingsserver actief, gebruik je browser om naar de /create-route te navigeren:

http://127.0.0.1:5000/create

Vul het formulier in met enkele gegevens en verzend het.

Je wordt doorgestuurd naar de indexpagina waar je de nieuw toegevoegde student zult zien.

Nu je de functionaliteit hebt om nieuwe studenten toe te voegen, moet je een link toevoegen naar de Create-pagina in de navigatiebalk. Open base.html:

  1. nano templates/base.html

Bewerk de <body>-tag door de waarde van het href-attribuut voor de Create-link aan te passen:

flask_app/templates/base.html
<body>
    <nav>
        <a href="{{ url_for('index') }}">FlaskApp</a>
        <a href="{{ url_for('create') }}">Create</a>
        <a href="#">About</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>

Sla het bestand op en sluit het.

Vernieuw je indexpagina en je zult merken dat de Create-link in de navigatiebalk nu functioneel is.

U heeft nu een pagina met een webformulier om nieuwe studenten toe te voegen. Voor meer informatie over webformulieren, zie Hoe webformulieren te gebruiken in een Flask-toepassing. Voor een geavanceerdere en veiligere methode om webformulieren te beheren, zie Hoe webformulieren te gebruiken en te valideren met Flask-WTF. Vervolgens zult u een pagina toevoegen voor het bewerken van de gegevens van bestaande studenten.

Stap 6 — Een Record Bewerken

In deze stap zult u een nieuwe pagina toevoegen aan uw applicatie voor het bewerken van bestaande studentengegevens. U zult een nieuwe /ID/edit/-route toevoegen om de gegevens van studenten te bewerken op basis van hun ID.

Open app.py:

  1. nano app.py

Voeg de volgende route toe aan het einde van het bestand. Dit haalt de studenteninvoer op die u wilt bewerken met behulp van de ID. Het haalt de nieuwe studentgegevens op die zijn ingediend via een webformulier dat u later zult maken. Vervolgens bewerkt het de studentgegevens en leidt het de gebruiker door naar de indexpagina:

flask_app/app.py
# ...


@app.route('/<int:student_id>/edit/', methods=('GET', 'POST'))
def edit(student_id):
    student = Student.query.get_or_404(student_id)

    if request.method == 'POST':
        firstname = request.form['firstname']
        lastname = request.form['lastname']
        email = request.form['email']
        age = int(request.form['age'])
        bio = request.form['bio']

        student.firstname = firstname
        student.lastname = lastname
        student.email = email
        student.age = age
        student.bio = bio

        db.session.add(student)
        db.session.commit()

        return redirect(url_for('index'))

    return render_template('edit.html', student=student)

Sla het bestand op en sluit het.

Hier heeft u de route /<int:student_id>/edit/ die zowel POST- als GET-methoden accepteert, met student_id als een URL-variabele die de ID doorgeeft aan de edit() weergavefunctie.

Je gebruikt de get_or_404() querymethode op het Student-model om de student op te halen die is gekoppeld aan de opgegeven student-ID. Dit zal reageren met een 404 Not Found-fout als er geen student met de opgegeven ID bestaat in de database.

Als de opgegeven ID een student eraan heeft gekoppeld, wordt de code uitgevoerd naar de voorwaarde if request.method == 'POST'. Als het verzoek een GET-verzoek was, wat betekent dat de gebruiker geen formulier heeft verzonden, dan is deze voorwaarde onwaar, en de code erin wordt overgeslagen naar de regel return render_template('edit.html', student=student). Dit rendert een edit.html-sjabloon, waarbij het de studentobject doorgeeft die je uit de database hebt gehaald, waardoor je het webformulier van de student kunt invullen met de huidige studentgegevens. Je zult dit edit.html-sjabloon later aanmaken.

Wanneer een gebruiker studentgegevens bewerkt en het formulier indient, wordt de code binnen de if request.method == 'POST' uitgevoerd. Je haalt de ingediende studentgegevens uit het request.form-object in overeenkomstige variabelen. Je stelt elke eigenschap van het student-object in op de nieuw ingediende gegevens om kolomwaarden te wijzigen zoals je hebt gedaan in Stap 2. Als er geen wijziging is aangebracht op een veld in het webformulier, blijft de waarde van die kolom hetzelfde in de database.

Nadat je de studentgegevens hebt ingesteld op de nieuw ingediende gegevens, voeg je het student-object toe aan de databasesessie, vervolgens bevestig je de wijzigingen. Ten slotte stuur je de gebruiker door naar de indexpagina.

Hierna moet je een pagina maken waar gebruikers de bewerking kunnen uitvoeren. Open een nieuw edit.html-sjabloon:

  1. nano templates/edit.html

Dit nieuwe bestand zal een webformulier hebben dat lijkt op dat in het create.html-bestand met de huidige studentgegevens als standaardwaarden voor de velden. Voeg de volgende code erin toe:

flask_app/templates/edit.html

{% extends 'base.html' %}

{% block content %}
    <h1 style="width: 100%">
        {% block title %} Edit {{ student.firstname }}
                               {{ student.lastname }}'s Details
        {% endblock %}
    </h1>
    <form method="post">
        <p>
            <label for="firstname">First Name</label>
            <input type="text" name="firstname"
                   value={{ student.firstname }}
                   placeholder="First name">
            </input>
        </p>

        <p>
            <label for="lastname">Last Name</label>
            <input type="text" name="lastname"
                   value={{ student.lastname }}
                   placeholder="Last name">
            </input>
        </p>

        <p>
            <label for="email">Email</label>
            <input type="email" name="email"
                   value={{ student.email }}
                   placeholder="Student email">
            </input>
        </p>

        <p>
            <label for="age">Age</label>
            <input type="number" name="age"
                   value={{ student.age }}
                   placeholder="Age">
            </input>
        </p>

        <p>
        <label for="bio">Bio</label>
        <br>
        <textarea name="bio"
                  placeholder="Bio"
                  rows="15"
                  cols="60"
                  >{{ student.bio }}</textarea>
        </p>
        <p>
            <button type="submit">Submit</button>
        </p>
    </form>
{% endblock %}

Sla het bestand op en sluit het.

De titel heeft de voornaam en achternaam van de student. De value-attribuut van elk invoerveld en de waarde van het biogedeelte worden ingesteld op de overeenkomstige waarde in het student-object dat je hebt doorgegeven van de edit()-weergavefunctie naar het edit.html-sjabloon.

Navigeer nu naar de volgende URL om de gegevens van de eerste student te bewerken:

http://127.0.0.1:5000/1/edit

Je ziet een pagina die lijkt op de volgende:

Bewerk de gegevens van de student en verzend het formulier. Je wordt doorgestuurd naar de indexpagina en de informatie van de student wordt bijgewerkt.

Vervolgens voeg je onder elke student op de indexpagina een Bewerken-knop toe om naar hun bewerkingspagina te linken. Open het index.html-sjabloonbestand:

  1. nano templates/index.html

Bewerk de for-lus in dit index.html-bestand zodat deze er precies uitziet als volgt:

flask_app/templates/index.html

{% for student in students %}
    <div class="student">
        <p><b>#{{ student.id }}</b></p>
        <b>
            <p class="name">
                <a href="{{ url_for('student', student_id=student.id)}}">
                    {{ student.firstname }} {{ student.lastname }}
                </a>
            </p>
        </b>
        <p>{{ student.email }}</p>
        <p>{{ student.age }} years old.</p>
        <p>Joined: {{ student.created_at }}</p>
        <div class="bio">
            <h4>Bio</h4>
            <p>{{ student.bio }}</p>
        </div>
        <a href="{{ url_for('edit', student_id=student.id) }}">Edit</a>
    </div>
{% endfor %}

Sla het bestand op en sluit het.

Hier voeg je een <a>-tag toe om naar de edit()-weergavefunctie te linken, waarbij de student.id-waarde wordt doorgegeven om naar de bewerkingspagina van elke student te linken met een Bewerken-link.

Je hebt nu een pagina voor het bewerken van bestaande studenten. Hierna voeg je een Verwijderen-knop toe om studenten uit de database te verwijderen.

Stap 7 — Een record verwijderen

In deze stap voeg je een nieuwe route en een Verwijderen knop toe om bestaande studenten te verwijderen.

Eerst voeg je een nieuwe /id/delete route toe die POST-verzoeken accepteert. Je nieuwe delete() view-functie zal het ID van de student ontvangen die je wilt verwijderen, het ID doorgeven aan de get_or_404() querymethode op het Student model om het te krijgen als het bestaat, of reageren met een 404 Niet gevonden pagina als er geen student met het opgegeven ID is gevonden in de database.

Open app.py voor bewerking:

  1. nano app.py

Voeg de volgende route toe aan het einde van het bestand:

flask_app/app.py

# ...

@app.post('/<int:student_id>/delete/')
def delete(student_id):
    student = Student.query.get_or_404(student_id)
    db.session.delete(student)
    db.session.commit()
    return redirect(url_for('index'))

Sla het bestand op en sluit het.

Hier, in plaats van de gebruikelijke app.route decorator, gebruik je de app.post decorator geïntroduceerd in Flask versie 2.0.0, die shortcuts toevoegde voor veelvoorkomende HTTP-methoden. Bijvoorbeeld, @app.post("/login") is een shortcut voor @app.route("/login", methods=["POST"]). Dit betekent dat deze view-functie alleen POST-verzoeken accepteert, en naar de /ID/delete route navigeren in je browser zal een 405 Methode Niet Toegestaan fout opleveren, omdat webbrowsers standaard GET-verzoeken gebruiken. Om een student te verwijderen, klikt de gebruiker op een knop die een POST-verzoek naar deze route stuurt.

Deze delete() view-functie ontvangt het ID van de te verwijderen student via de student_id URL-variabele. Je gebruikt de get_or_404() methode om een student te krijgen en deze op te slaan in een student variabele, of te reageren met een 404 Niet Gevonden als de student niet bestaat. Je gebruikt de delete() methode op de databasesessie in de regel db.session.delete(student), waarbij je het studentobject doorgeeft. Dit stelt de sessie in om de student te verwijderen wanneer de transactie wordt uitgevoerd. Omdat je geen andere wijzigingen hoeft aan te brengen, commit je de transactie direct met db.session.commit(). Ten slotte stuur je de gebruiker door naar de indexpagina.

Vervolgens bewerk je het index.html sjabloon om een Verwijder Student knop toe te voegen:

  1. nano templates/index.html

Bewerk de for loop door direct onder de Bewerk link een nieuwe <form>-tag toe te voegen:

flask_app/templates/index.html

{% for student in students %}
    <div class="student">
        <p><b>#{{ student.id }}</b></p>
        <b>
            <p class="name">
                <a href="{{ url_for('student', student_id=student.id)}}">
                    {{ student.firstname }} {{ student.lastname }}
                </a>
            </p>
        </b>
        <p>{{ student.email }}</p>
        <p>{{ student.age }} years old.</p>
        <p>Joined: {{ student.created_at }}</p>
        <div class="bio">
            <h4>Bio</h4>
            <p>{{ student.bio }}</p>
        </div>
        <a href="{{ url_for('edit', student_id=student.id) }}">Edit</a>

        <hr>
        <form method="POST"
                action="{{ url_for('delete', student_id=student.id) }}">
            <input type="submit" value="Delete Student"
                onclick="return confirm('Are you sure you want to delete this entry?')">
        </form>

    </div>
{% endfor %}

Sla het bestand op en sluit het.

Hier heb je een webformulier dat een POST-verzoek indient naar de delete()-weergavefunctie. Je geeft student.id door als argument voor de student_id-parameter om de te verwijderen studentinvoer te specificeren. Je gebruikt de confirm()-methode die beschikbaar is in webbrowsers om een bevestigingsbericht weer te geven voordat het verzoek wordt ingediend.

Vernieuw nu je indexpagina.

Je ziet een Student verwijderen-knop onder elke studentinvoer. Klik erop en bevestig de verwijdering. Je wordt doorgestuurd naar de indexpagina en de student zal daar niet langer zijn.

Je hebt nu een manier om studenten uit de database te verwijderen in je studentenbeheerapplicatie.

Conclusie

Je hebt een kleine Flask-webapplicatie gebouwd voor het beheren van studenten met behulp van Flask en Flask-SQLAlchemy met een SQLite-database. Je hebt geleerd hoe je verbinding maakt met je database, database-modellen opzet die je tabellen vertegenwoordigen, items aan je database toevoegt, je tabel doorzoekt en gegevens in de database wijzigt.

Het gebruik van SQLAlchemy in uw toepassing stelt u in staat om Python-klassen en objecten te gebruiken om uw SQL-database te beheren. In plaats van SQLite kunt u een andere database-engine gebruiken, en afgezien van de SQLALCHEMY_DATABASE_URI-configuratie die verantwoordelijk is voor de verbinding, hoeft u niets te veranderen in uw kernapplicatiecode. Dat stelt u in staat om met minimale codeaanpassing over te stappen van de ene SQL-database-engine naar de andere. Zie de Flask-SQLAlchemy-documentatie voor meer informatie.

Als u meer wilt lezen over Flask, bekijk dan de andere tutorials in de Hoe webtoepassingen te bouwen met Flask serie.

Source:
https://www.digitalocean.com/community/tutorials/how-to-use-flask-sqlalchemy-to-interact-with-databases-in-a-flask-application