Home » Beitrag verschlagwortet mit 'Web Development'

Schlagwort-Archive: Web Development

React JS – Einführung

Diese wunderbare Einführung in das React JS Gui Framework macht es völlig unnötig hier noch mehr zu schreiben.

Dass ich trotzdem noch etwas Schreibe ist mehr als Mittel gedacht für mich selbst einig Merkpunkte nochmals zu recapitulieren.

Building Blocks

Importieren von

import React from 'react';
import ReactDOM from 'react-dom';

GUI-Compoent-Modell

Nun können React Componenten als Klassen angelegt werden:

class Square extends React.Component {
  render() {
    return (
      <button className="square" onClick={function() { console.log('click'); }}>
        {this.props.value}
      </button>
    );
  }
}

class Board extends React.Component {
    renderSquare(i) {
        return (<Square value={this.props.squares[i]} onClick={() => this.props.onClick(i)} />);
    }

    render() {
        return (
            <div>
                <div className="board-row">
                    {this.renderSquare(0)}
                    {this.renderSquare(1)}
                    {this.renderSquare(2)}
                </div>
                <div className="board-row">
                    {this.renderSquare(3)}
                    {this.renderSquare(4)}
                    {this.renderSquare(5)}
                </div>
                <div className="board-row">
                    {this.renderSquare(6)}
                    {this.renderSquare(7)}
                    {this.renderSquare(8)}
                </div>
            </div>
        );
    }
}

Obiger Code zeigt die definition von zwei Componenten (Board und Square). Was durch diese Component im GUI angezeigt wird ist dadurch definiert, was ihre render Methode zurück gibt.
Dieses Rückgabe-Object wird auch React Element genannt.
Im obigen Beispiel wird das React Element mittels JSX Notation beschrieben, welche HTML imitiert.
Die Mitgabe von Sub-Elementen (-Componenten) and den Parser geschieht im Beispiel mit:

return (<Square value={this.props.squares[i]} onClick={() => this.props.onClick(i)} />);

Die Component-Sub-Klasse (im Beispiel ‚Square‘) wird also wie ein HTML-Tag referenziert!

Parameter-Übergabe und Modell-GUI-Synchronisation

Parameter-Übergabe

Wird eine Sub-Component z.B. so ins GUI einbezogen …

return (<Square meinWert={myVar}>

dann kann sie nachher in der Sqare-Component so ausgelesen werden:

this.parms.meinWert

Status und Modell-GUI-Synchronisation

Status Definition

Der von React verwaltete State muss im Constructor definiert werden:

class Game extends React.Component {
    constructor(props){
        super(props);
        this.state = {
            meineVar: 'Mein Wert' 
        };
    }

Beachte:

  • super(props) ist zu programmieren!
  • Der State einer Component ist privat!
Status Update

Mittels this.setState() wird der State in der render Methode vom Programmierer nachgeführt. React führt automatisch die States der Unter-Komponenten nach.

this.setState({meineVar: 'Hallo Welt'});

Flask DB Migrations

Links

Flask-Migrate ist die Library um DB-Modell-Änderungen, die mit SQLAlchemy ausgedrückt sind zu kontrollieren. Es benutzt dazu die Library Alembic.

Schritte

Aufsetzen Flask Migrate Tool

Steps:

pip3 install Flask-Migrate

Projekt bezüglich Migrations-Handling aufsetzen

flask db init

Das setzt verschiedene Migrations-Script-Folders und Tools im SW-Projekt bereit.


Output:

C:\tmp\Python_Workspace1\task-app>flask db init
Creating directory C:\tmp\Python_Workspace1\task-app\migrations ...  done
Creating directory C:\tmp\Python_Workspace1\task-app\migrations\versions ...  done
Generating C:\tmp\Python_Workspace1\task-app\migrations\alembic.ini ...  done
Generating C:\tmp\Python_Workspace1\task-app\migrations\env.py ...  done
Generating C:\tmp\Python_Workspace1\task-app\migrations\README ...  done
Generating C:\tmp\Python_Workspace1\task-app\migrations\script.py.mako ...  done
Please edit configuration/connection/logging settings in 'C:\\tmp\\Python_Workspace1\\task-app\\migrations\\alembic.ini' before proceeding.

Funktioniert das Kommando nicht, weil die DB noch nicht gestartet ist, dann etwa folgendes absetzen:

pg_ctl -D "C:\Program Files\PostgreSQL\13\data" start

DB-Migrationen durchführen

flask db migrate

Erkennt die Anforderungen an das DB-Modell aus den Python-Scripts (aus den SQLAlchemy Model-Objekt-Definitionen) heraus und erstellt eine Migration (DDL Statements um das erforderliche DB-Model zu erstellen).
Ich gehe schwer davon aus, das dazu FLASK_APP auf das Python-Script mit den Entitätsdefinitionen zeigen muss.

Bsp. einer SQLAlchemy Model-Objekt-Definition im *.py:

class Todo(db.Model):
    __tablename__ = 'todos'
    id = db.Column(db.Integer, primary_key=True)
    description = db.Column(db.String(), nullable=False)

Falls das erzeugte Script das ganze DB-Modell von Grund auf neu erzeugen soll, dann darf die DB diese Entitäten nicht schon enthalten. Das kann man zum Bsp. erreichen durch:

dropdb --username=postgres todoDB
createdb --username=postgres todoDB

!Stelle sicher, dass das Pyton-Script, nicht schon selbst die DB-Objekte erstellt (Z.B. Kommando db.create_all() darf nicht auch schon im Python-Code enthalten sein).

Durchführung:

C:\tmp\Python_Workspace1\task-app>flask db migrate

INFO  [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO  [alembic.runtime.migration] Will assume transactional DDL.
INFO  [alembic.autogenerate.compare] Detected added table 'todos'
Generating C:\tmp\Python_Workspace1\task-app\migrations\versions\70ee48c313e4_.py ...  done

C:\tmp\Python_Workspace1\task-app>

Ein Migrations-File wurde erstellt: task-app/migrations/versions/70ee48c313e4_.py:

"""empty message

Revision ID: 70ee48c313e4
Revises: 
Create Date: 2021-07-22 15:15:43.733091

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '70ee48c313e4'
down_revision = None
branch_labels = None
depends_on = None


def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table('todos',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('description', sa.String(), nullable=False),
    sa.PrimaryKeyConstraint('id')
    )
    # ### end Alembic commands ###


def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_table('todos')
    # ### end Alembic commands ###

Migration auf die DB spielen:

C:\tmp\Python_Workspace1\task-app>flask db upgrade
INFO  [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO  [alembic.runtime.migration] Will assume transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade  -> 70ee48c313e4, empty message

Migration rückgängig machen wäre:

flask db downgrade

Prüfung, ob DB-Migrationen auf DB angekommen sind:

C:\tmp\Python_Workspace1\task-app>psql --username=postgres todoDB
Passwort für Benutzer postgres:
todoDB=# \dt
              Liste der Relationen
 Schema |      Name       |   Typ   | Eigent³mer
--------+-----------------+---------+------------
 public | alembic_version | Tabelle | postgres
 public | todos           | Tabelle | postgres
(2 Zeilen)


todoDB=#

Beachte die alembic_version Tabelle! Beinhaltet die Migrationsinfo. Prinzipiell nicht durch den Programmierer zu verändern.

Wenn nun Änderungen am DB-Modell innerhalb des Python-Scripts gemacht werden (z.B. wird hier das boolean Feld ‚completed‘ neu hinzu gefügt),

class Todo(db.Model):
    __tablename__ = 'todos'
    id = db.Column(db.Integer, primary_key=True)
    description = db.Column(db.String(), nullable=False)
    completed = db.Column(db.Boolean(), nullable=False, default=False)

…, dann wird mit flask db migrate ein neues Update-Script erstellt und mit flask db update dieser Update auf die DB gespielt.

Beheben der Problematik des Hinzufügens von NOT-NULL Feldern:
Das Migrations-Script folgendermassen anpassen:

from alembic import op

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.add_column('todos', sa.Column('completed', sa.Boolean(), nullable=True))
    op.execute('update todos set completed=False where completed is null')
    op.alter_column('todos', 'completed', nullable=False)
    # ### end Alembic commands ###

Flask WebApp Request handling

Request-Typen und ihr Handling

Request-TypHandling (Python)
URL parameter:
/foo?field1=value
value1 = request.args.get(field1)
Form inputun = reqest.form.get(‚username‘)
pw = request.form.get(‚password‘)
application/jsondata_string = request.data
data_dictionary = json.loads(data_string)

Web Programming – Dom-Manipulation – Lernjournal

Im Broser: Developer Console öffnen: Ctrl + Shift + I
$0: Ist das Object, das zur Zeit in im Fokus steht. Abfragen wie z.B.: $0.children möglich.
Etwas loggen:
>console.log($0.id)

Zugriff auf Elemente: Z.B.:
>document.body

Mozilla Developer Network: https://developer.mozilla.org/en-US/docs/Web/API#interfaces

Wichtige Interfaces:
Document
Node
Element