Författare: Maria

  • Åtgärda Alembic-fel i Flask: En steg-för-steg-guide

    Åtgärda Alembic-fel i Flask: En steg-för-steg-guide

    Nu när jag nästan var klar med min nya hemsida, bara lite puts kvar så började plötsligt mina databasmigreringar att strula.

    Please edit configuration/connection/logging settings in 'C:\\Users\\maria\\Documents\\PyCharmProjects\\MittProjekt\\migrations\\alembic.ini' before proceeding.

    Detta är vad jag fann för att rätta till problemet:

    Varför visas felet ”Please edit configuration/connection/logging settings…”?

    Det meddelande som visas (”Please edit configuration/connection/logging settings in ’…/migrations/alembic.ini’ before proceeding.”) är Alembics generella uppmaning efter att man initierat en ny migrationsmiljö. Alembic påminner om att man måste ange vissa inställningar (framförallt databasens URL) i konfigurationsfilen alembic.ini innan man går vidare (alembic.sqlalchemy.org). Om man inte har justerat denna fil (eller på annat sätt försett Alembic med databasens anslutningssträng) kommer Alembic att varna om att standardinställningarna fortfarande är ogiltiga.

    I en Flask-applikation som följer application factory-mönstret (där appen skapas via en funktion create_app), definieras databasens URL oftast i app-konfigurationen (app.config['SQLALCHEMY_DATABASE_URI']). När man kör flask db init skapas en alembic.ini med en platshållar-URL (t.ex. driver://user:pass@localhost/dbname). Om denna inte ersätts eller överskrivs får man ovanstående meddelande. Felet orsakas alltså av att Alembic ännu inte vet vilken databas den ska koppla upp mot. I praktiken är det ingen kraschande bugg, utan en uppmaning att konfigurera Alembic korrekt. Om Flask-Migrate används korrekt kan man ofta ignorera meddelandet och fortsätta med t.ex. flask db migrate – Flask-Migrate kommer då att hämta databas-URL:en från Flask-appen automatiskt (stackoverflow.com). Men för att undvika förvirring bör man se till att Alembic-konfigurationen ställs in rätt.

    Anpassa alembic.ini och env.py för att fungera med create_app

    För att Alembic ska fungera ihop med en Flask-app som skapas dynamiskt via create_app behöver man justera både alembic.ini och migrations/env.py:

    • alembic.ini: Här kan man ange databasens URL direkt under sektionen [alembic] med nyckeln sqlalchemy.url. Till exempel för MySQL:
    sqlalchemy.url = mysql+pymysql://<user>:<password>@<host>/<databasename>

    Detta hårdkodar anslutningssträngen. Alternativt kan man låta denna rad vara en dummy (eller använda en miljövariabelsreferens) och istället sätta URL:en via env.py – vilket är vanligare när man använder Flask-Migrate för att hämta appens konfiguration i stället för att duplicera den i alembic.ini.
    Övriga viktiga rader i alembic.ini är normalt: script_location (som ska peka på migrationskatalogen, t.ex. migrations) och eventuellt inställningar för loggning. Standardvärdena som genererats av flask db init brukar redan vara korrekta för dessa, men bekräfta att script_location = migrations matchar din projektstruktur. För MySQL kan man även försäkra sig om att uppsättningar som encoding (t.ex. utf8mb4) är korrekta om de förekommer.

    • migrations/env.py: Denna fil körs vid varje migrationskommando och här behöver vi koppla in Flask-applikationen så att Alembic får tillgång till appens konfiguration (databas-URL) och modeller. I en application factory-arkitektur måste env.py antingen:

    Använda Flask CLI:s app-kontekst (current_app): Om man kör kommandona via flask db ... och har talat om för Flask hur appen ska skapas (t.ex. genom att sätta miljövariabeln FLASK_APP till "app:create_app"), då kommer Flask att skapa appen och pusha en app context åt Alembic. I env.py kan man då nå appen via flask.current_app. Exempelvis:

    from flask import current_app
    config.set_main_option('sqlalchemy.url', current_app.config.get('SQLALCHEMY_DATABASE_URI'))
    target_metadata = current_app.extensions['migrate'].db.metadata

    Här hämtar vi databasens URL från appens konfiguration och sätter den i Alembics config, samt tar ut target_metadata (d.v.s. metadata för alla modeller) från SQLAlchemy-objektet som Flask-Migrate registreratstackoverflow.com. Flask-Migrate extension ser till att current_app.extensions['migrate'].db hänvisar till din SQLAlchemy-instans. (Notera: om din databas-URL innehåller procenttecken % kan du behöva ersätta dem med %% för att configparser inte ska misstolka dem (stackoverflow.com, stackoverflow.com.)

    Skapa appen manuellt: Om current_app inte är tillgänglig (t.ex. om man kör Alembic direkt utan Flask CLI), kan man importera och initiera applikationen inom env.py. Då anropar man create_app() själv, och pushar en app context manuellt. På så vis får Alembic samma konfiguration som din applikation. Du måste också importera dina modeller så att de registreras i metadata. Exempel på de relevanta delarna i ett env.py anpassat för application factory:

    from alembic import context
    from logging.config import fileConfig
    import logging

    # Konfiguration från alembic.ini
    config = context.config
    fileConfig(config.config_file_name)
    logger = logging.getLogger('alembic.env')

    # Importera appen och dess databas
    from app import create_app, db
    flask_app = create_app() # skapa applikationen
    flask_app.app_context().push() # pusha app context för att få current_app

    # Importera modelldefinitionerna så att de registreras i metadata
    import app.models

    # Sätt databaskoppling (URL) dynamiskt från appens config
    db_url = flask_app.config['SQLALCHEMY_DATABASE_URI']
    config.set_main_option('sqlalchemy.url', db_url)

    # Hämta SQLAlchemy-metadata som beskriver modellerna
    target_metadata = db.Model.metadata # alternativt db.metadata

    def run_migrations_offline():
    """Kör migrationer utan att koppla upp (offline-läge)."""
    url = config.get_main_option("sqlalchemy.url")
    context.configure(
    url=url,
    target_metadata=target_metadata,
    literal_binds=True
    )
    with context.begin_transaction():
    context.run_migrations()

    def run_migrations_online():
    """Kör migrationer i online-läge, med databaskoppling."""
    connectable = db.engine
    with connectable.connect() as connection:
    context.configure(
    connection=connection,
    target_metadata=target_metadata,
    process_revision_directives=... # ev. utelämnat eller anpassat
    )
    with context.begin_transaction():
    context.run_migrations()

    # Avgör läge
    if context.is_offline_mode():
    run_migrations_offline()
    else:
    run_migrations_online()

    I koden ovan skapas appen via factory-funktionen och appens konfiguration (inklusive databas-URL) läses in i Alembic. Vi hämtar target_metadata från vår SQLAlchemy-instans (här antas att db = SQLAlchemy() i app/init.py, och att modellerna är definierade som subklasser av db.Model i app/models.py). Det är viktigt att importera modulpaketet app.models efter att app-context har skapats – detta säkerställer att alla modelldefinitioner faktiskt laddas och registreras. Om man missar att importera modellerna kan Alembic tro att det inte finns några ändringar, eftersom target_metadata då är tomt (innehåller inga tabeller) trots att de finns definierade i koden.

    Säkerställ att rätt databas-URL och modeller används

    För att verifiera att Alembic/Flask-Migrate verkligen använder korrekt databas och inkluderar modellerna kan man göra följande:

    • Kontrollera databas-URL: Kör en migrationskommando (t.ex. flask db migrate eller alembic revision --autogenerate) med debug/info-loggning på. I terminalens output bör du se att Alembic kopplar upp mot MySQL och inte t.ex. SQLite. Alembic loggar vilken ”Context impl” som används. För MySQL skulle det stå något i stil med ”Context impl MySQLImpl” (för SQLite står det SQLiteImplblog.miguelgrinberg.com). Om du ser MySQL nämnas vet du att den använder rätt driver/databas. Dessutom, om anslutningen misslyckas eller URL:en är felaktig, kommer Alembic att kasta ett fel direkt – då behöver du dubbelkolla SQLALCHEMY_DATABASE_URI i appen eller i alembic.ini.
    • Kontrollera att modellerna laddas: Efter att ha kört flask db migrate (autogenerering), öppna den genererade revisionsfilen under migrations/versions/. Där bör du se skapandet av tabeller och kolumner som matchar dina modellklasser. Om Alembic rapporterar ”No changes in schema detected.” trots att du har oaplicerade modeller, tyder det på att env.py inte lyckades ladda in modelldefinitionerna eller att den jämför mot fel databasblog.miguelgrinberg.com. Säkerställ då att du importerat rätt moduler och att target_metadata faktiskt refererar till all metadata (t.ex. via db.Model.metadata). I vårt exempel importerar vi app.models manuellt i env.py för att undvika detta problem.
    • Testa migrationerna: Kör flask db upgrade för att applicera migrationerna på databasen. Om allt är rätt konfigurerat ska dina tabeller nu skapas/uppdateras i MySQL utan fel. Du kan även köra flask db current för att se aktuell migrationsversion i databasen, vilket bekräftar att Alembic kan kommunicera med databasen.

    Rekommenderat arbetssätt med Flask-Migrate och Alembic

    • Initiera migrationsrepositoryt: För en ny app gör man normalt flask db init en gång (det verkar användaren redan ha gjort, vilket skapade mappen migrations/ i projektroten och en alembic.ini). Se till att FLASK_APP är korrekt satt till din factory (t.ex. export FLASK_APP="app:create_app" i Unix, eller motsvarande i Windows) innan du kör init, så att Flask vet hur appen ska skapas vid migrationskommandon.
    • Skapa migrations (autogenerera): När du har definierat eller ändrat dina modeller, kör flask db migrate -m "Beskrivning av ändring" för att låta Alembic jämföra target_metadata (dina modeller) med databasen och generera en ny migrationsfil. Tack vare konfigurationen ovan kommer Alembic att använda appens MySQL-URL och inkludera alla modeller i jämförelsen. (Observera att första gången i ett projekt med befintlig databas kan Alembic tro att inget behöver göras om databasen redan har dessa tabeller. I så fall kan man behöva använda flask db stamp head för att markera databasen som uppdaterad, eller köra migrationskommandot mot en tom databaskopiablog.miguelgrinberg.comblog.miguelgrinberg.com.)
    • Applicera migrationer: Använd flask db upgrade för att köra migrationerna och uppdatera databasschemat till senaste version. Detta kommando kommer under huven att anropa Alembic och köra env.py med online-läget. Återigen används create_app-funktionen i vår konfiguration för att koppla upp mot rätt databas.
    • Använd Flask-Migrate i utvecklingsflödet: I och med att du har integrerat Alembic med Flask via Flask-Migrate, bör du fortsättningsvis använda flask db ...-kommandona (snarare än att köra alembic direkt) för att hantera migrationerna. Flask-Migrate sköter kopplingen till appen och kontexten åt dig. Som påpekats av utvecklare är Flask-Migrate enklare att använda i Flask-projekt eftersom det automatiserar mycket av konfigurationenstackoverflow.com. Se till att extensions initieras korrekt i create_app (d.v.s. db.init_app(app) och Migrate(app, db) om du inte redan gjort det).

    Relaterade bilder:

  • Skapa Databasmigreringar med Alembic i Python

    Skapa Databasmigreringar med Alembic i Python

    Jag går en kurs i Python, programmeringsspråket. En av de sista uppgifterna är att skapa en hemsida, egentligen en portfolio med program jag skapat och länkar till Github med flera ställen där jag har något jag vill visa upp. I kursen använde vi SQLite som databas men eftersom jag använd MySql mycket i mina andra projekt så ville jag göra det här med. Plus att det blev en liten utmaning att göra om databaskopplingar.

    För att på ett enkelt sätt kunna göra databasmigreringar när jag uppgraderar mitt program hittade jag Alembic som fungerar bra för det. Sökvägarna behöver rättas utifrån varje projekt, förstås men gången är denna:


    1. Installera Alembic

    Om du inte redan har det:

    pip install alembic

    2. Initiera Alembic

    I roten av ditt projekt (där din app/-mapp och run.py eller liknande ligger):

    alembic init migrations

    Det skapar en migrations/-mapp och en alembic.ini-fil.


    3. Konfigurera alembic.ini

    Öppna alembic.ini och ändra denna rad:

    sqlalchemy.url = driver://user:pass@localhost/dbname

    Byt ut den mot din databas-url, t.ex.:

    sqlalchemy.url = mysql+pymysql://root:password@localhost/portfolio-db

    Eller om du använder en .env-fil – då ändrar vi detta i steg 5 istället via Python.


    4. Peka Alembic till din SQLAlchemy-modell

    Öppna migrations/env.py och leta upp detta block:

    from logging.config import fileConfig
    from sqlalchemy import engine_from_config, pool
    from alembic import context

    Lägg till din models.py-import (efter importerna ovan):

    import sys
    import os
    sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
    from app.models import db # Lägg till detta

    Byt ut denna rad:

    target_metadata = None

    mot:

    target_metadata = db.metadata

    5. (Valfritt) Använd din DATABASE_URL från .env

    Om du vill använda os.getenv("DATABASE_URL"):

    Byt ut i migrations/env.py (under config = context.config):

    from dotenv import load_dotenv
    load_dotenv()
    from sqlalchemy.engine.url import URL
    config.set_main_option("sqlalchemy.url", os.getenv("DATABASE_URL"))

    6. Skapa en migrering

    När du ändrar en modell (t.ex. la till description i PortfolioItem), kör:

    alembic revision --autogenerate -m "Add description to portfolio item"

    Det skapar en versionsfil i migrations/versions/.


    7. Kör migreringen

    alembic upgrade head

    Nu har kolumnen description skapats i databasen utan att radera något!


    alembic.ini

    Byt ut din befintliga alembic.ini med denna:

    [alembic]
    script_location = migrations
    sqlalchemy.url = mysql+pymysql://root:password@localhost/portfolio-db

    [loggers]
    keys = root,sqlalchemy,alembic

    [handlers]
    keys = console

    [formatters]
    keys = generic

    [logger_root]
    level = WARN
    handlers = console

    [logger_sqlalchemy]
    level = WARN
    handlers =
    qualname = sqlalchemy.engine

    [logger_alembic]
    level = INFO
    handlers =
    qualname = alembic

    [handler_console]
    class = StreamHandler
    args = (sys.stdout,)
    level = NOTSET
    formatter = generic

    [formatter_generic]
    format = %(levelname)-5.5s [%(name)s] %(message)s

    Byt root:password om du har en annan användare eller databas.


    migrations/env.py

    Byt ut hela innehållet i migrations/env.py med detta:

    from __future__ import with_statement

    import sys
    import os
    from logging.config import fileConfig
    from sqlalchemy import engine_from_config, pool
    from alembic import context

    # Lägg till appens rot till sys.path
    sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

    # Importera extensions och modeller
    from app.extensions import db
    from app.models import *

    # Load environment variables
    from dotenv import load_dotenv
    load_dotenv()

    # Alembic Config
    config = context.config

    # Sätt databas-URL från .env
    config.set_main_option('sqlalchemy.url', os.getenv("DATABASE_URL"))

    # Loggkonfiguration
    fileConfig(config.config_file_name)

    # Metadata från modellerna
    target_metadata = db.metadata

    def run_migrations_offline():
    """Kör migreringar utan en DB-anslutning."""
    url = config.get_main_option("sqlalchemy.url")
    context.configure(
    url=url,
    target_metadata=target_metadata,
    literal_binds=True,
    dialect_opts={"paramstyle": "named"},
    )

    with context.begin_transaction():
    context.run_migrations()

    def run_migrations_online():
    """Kör migreringar med en DB-anslutning."""
    connectable = engine_from_config(
    config.get_section(config.config_ini_section),
    prefix="sqlalchemy.",
    poolclass=pool.NullPool,
    )

    with connectable.connect() as connection:
    context.configure(
    connection=connection,
    target_metadata=target_metadata
    )

    with context.begin_transaction():
    context.run_migrations()

    if context.is_offline_mode():
    run_migrations_offline()
    else:
    run_migrations_online()

    Klar att köra:

    Nu kan du köra:

    alembic revision --autogenerate -m "Add description field"
    alembic upgrade head

    Relaterade bilder:

  • Tips från IT-supporten

    Tips från IT-supporten

    Bakgrund

    Jag närde en dröm om att skriva ner dagliga strävanden i anonymiserad form redan när jag jobbade som barnmorska. När en jobbar med människor hamnar en då och då i dråpliga situationer, missförstånd och annat som ibland bara är roliga och ibland är så jobbiga att en bara vill ta ett jobb i kassan på ICA. Så kommer insikten att där om någonstans är det direktkontakt med alla möjliga människor och då kanske det är ganska OK det jobb en har redan ändå. Det tog så mycket kraft att arbeta som barnmorska att jag inte orkade ta tag i det. Kanske blir det en sådan avdelning också så småningom.

    IT-support

    Nu har jag i alla fall tagit tag i att skriva ner mina äventyr i IT-supporten. Jag försöker att skriva generellt utan att ange namn, tid eller plats så att ingen ska känna sig träffad och det är garanterat inget som hände igår eller senaste halvåret. Jag tror dock att det finns ganska många som kan känna sig träffade eftersom

    Kommentera gärna!

    Jobbar du i support? Har du haft några roliga, spännande eller andra upplevelser som du vill dela med dig av?

    ← Tillbaka

    Tack för din respons. ✨

    Relaterade bilder:

  • Internationella kvinnodagen 2025

    Internationella kvinnodagen 2025

    Idag är det internationella kvinnodagen.

    En av mina kvinnliga förebilder är Dolly Parton. Hon är lite som jag, bara oändligt mer framgångsrik: uppväxt på landet med många förmågor. I hennes fall handlar det om att hon är en fantastisk sångerska, historieberättare, skådespelare och företagsledare (du har hört talas om Dollywood?).

    På vilket sätt uppmärksammar du dagen?

    Relaterade bilder:

  • Årets första sådd 2025

    Årets första sådd 2025

    Jag hade tänkt börja så i januari, vissa fröer behöver lite längre tid på sig men det dröjde till idag. Nu har jag stått chili, vinterportlak, pitahaya, eukalyptus, lavendel, rosenstänk.

    Relaterade bilder:

  • Ska börja med släktforskning igen

    Ska börja med släktforskning igen

    Det är över tio år sedan jag började fösta gången. Jag fick ihop ett släktträd med anor födda på 1500-talet med barn och allt. Så skulle jag göra en uppgradering av programvaran men missade att göra backup på databasen. Det blev en enda röra som inte gick att rädda genom att gå tillbaka i versioner, det hade på något sätt blivit korrupt på vägen. Jag har gjort några försök att fixa till det men inte orkat. Så nu gör jag ett nytt försök.

    Jag har skapat en lokal server hemma där jag började med att installera Ubuntu/linux. Med Windows11 är det enkelt att installera Linux, tillexempel Ubuntu, bara att följa instruktionen som finns på sidan Ubuntu WSL Documentation. För att starta en hemsida behövs en databas också, så jag installerade MySQL som vi använt som databas länge på både webbhotell och hemma, How to Install MySQL on Ubuntu var ganska enkel att följa.

    När servern var igång installerade jag senaste versionen av WordPress: Install and Configure WordPress har en bra steg-för-steg-genomgång som är lätt att följa

    Sedan blev det lite krångligare. Jag valde TNG som släktforskningsprogram, dels har jag använt det förut (det var det som kraschade), dels så är det webbaserat och läggs upp som en webbsida. Fördelen med det är att det går att komma åt även från mobilen om jag är på hemmanätverket om jag skulle surfa och hitta något jag vill spara till släktforskningen som text. länkar, bilder eller annat.

    TNG hade ju strulat förut. Nu skulle jag återinstallera en version som jag köpte för ett par år sedan, TNG 13.1.1. Till att börja med är det en del pyssel att kopiera ner zip-filen från nätet till datorn och sedan över till servern för att packa upp. Jag hoppar över den biten så länge. Installationen sedan var inte heller självgående utan jag fick lov att ändra behörighet till filer och mappar manuellt. Själva databasen likaså. När jag skulle skapa tabellerna kon jag av någon mystisk anledning inte längre än till tabellnamn som började på m. Det spelade ingen roll hur mycket jag sökte på felsökte. Någonstans hittade jag ett tips om att version 13.1 inte klarade av för ny mysql. Det slutade med att jag bestämde mig för att prova att köpa en ny version av TNG. Den senaste versionen är TNG 14.0.6. Med den flöt installationen som smort. Ja, bortsett från att det fortfarande var en del manuellt arbete med behörigheter till mappar och lite sådant. Manualen för installationen är ändå riktigt bra så om en läser instruktionen på Installing TNG steg för steg så är det inga problem.

    Relaterade bilder:

  • Från oss alla…

    Från oss alla…

    Önskas er alla en riktigt god jul!

    Relaterade bilder:

  • Virkat laptopfodral

    Virkat laptopfodral

    Nu har jag kommit igång att virka ordentligt. På detta fodral har jag virkat in fickor för kablar eller annat smått och fog men det finns inte plats för några större saker. Samma mönster som de senaste kreationerna myren med lite annan färgkombination och med små virkade spetsar som lock till fickorna.

    Jag är riktigt nöjd.

    Relaterade bilder:

  • Virkat fodral till tangentbord

    Virkat fodral till tangentbord

    På jobbet har vi ett så kallar aktivitetsbasetat kontor. Det innebär att skrivborden är tomma när en kommer på morgonen och då tar en med sig sina saker till ett ledigt bord. Det finns inga fasta platser. Det finns skåp till var och en men jag är inte så sällan och för det mesta kan jag låna från servicedesk-rummet men jag brukar ta med mig ett eget lite mindre så jag är säker på att ha ett, det är så knöligt att skriva på laptopen och titta på stora skärmen.

    Had vill ha något fint att bättra tangentbordet och musen så jag har börjat virka en påse med samma mönster som min lilla hobbypåse men med lite andra färger.

    Relaterade bilder:

  • Virkat en liten hobbypåse

    Virkat en liten hobbypåse

    Jag hittade själva mönstret och färgschemat på Drops, det är mitt favoritmönster för att det går att alternera med olika färger och få helt olika känsla. Själva påsen virkade jag utifrån eget huvud och behov, sedan sydde jag fickor på ett tyg som jag använde som foder så påsen har fickor för virkkrokar, synålar och säkerhetsnålar..

    Relaterade bilder: