Flask besser coden (Code-Dopplungen)

Django, Flask, Bottle, WSGI, CGI…
Antworten
Karlirex
User
Beiträge: 126
Registriert: Dienstag 18. August 2020, 18:27

Hallo zusammen,

ich arbeite aktuell an einer Flask-App und brauche in verschiedenen Routen die ähnlichen Funktionen, wie löschen, bearbeiten etc..
Wie vermeide ich solche Dopplungen? Da man ja sagt, code best practice ist es so etwas zu vermeiden.

Beispiel:

Code: Alles auswählen

@app.route("/customers", methods=['GET', 'POST'])
@login_required
def customers():
    if request.method == 'POST':
        if not request.form['name'] or not request.form['email'] or not request.form['bank_account']:
            flash('Alle Felder beachten.', 'error')
        else:
            customer = Customers(name = request.form['name'], address = request.form['address'], email = request.form['email'], phone = request.form['phone'],
                                 bank_account = request.form['bank_account'])
            db.session.add(customer)
            db.session.commit()
            flash('Kunde erfolgreich hinzugefügt.')
            return redirect(url_for('home'))
    return render_template("HTML/customers.html", title='Customers')

Code: Alles auswählen

@app.route("/employees", methods=['GET', 'POST'])
@login_required
def employees():
    if request.method == 'POST':
        if not request.form['name'] or not request.form['email']:
            flash('Alle Felder beachten.', 'error')
        else:
            employee = Employees(name = request.form['name'], address = request.form['address'], email = request.form['email'], phone = request.form['phone'],
                                 group = request.form['group'])
            db.session.add(employee)
            db.session.commit()
            flash('Mitarbeiter erfolgreich hinzugefügt.')
            return redirect(url_for('home'))
    if request.method == 'GET':
        employees = Employees.query.all()
    return render_template("HTML/employees.html", title='Employees', data=employees)
und fürs Löschen und co sehen diese Routen eben nochmals ähnlich aus. Für mich handelt es sich dabei um eine Dopplung im größten Sinne. In einem anderen Framework (Django) sieht dies ja ähnlich aus :/

Gibt es da eine Möglichketi dies "schöner" zu machen?

Grüße
Karlirex
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Karlirex: Zieh halt die Gemeinsamkeiten in eine Funktion heraus der die Unterschiede als Argumente übergeben werden.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Karlirex
User
Beiträge: 126
Registriert: Dienstag 18. August 2020, 18:27

@_blackjack_: nunja das geht gilt aber ja nicht wirklich als Gemeinsamkeit, da die Klassenparameter(Datenbank-Spalten) jenach Tabelle unterschiedlicher Anzahl sind. Somit würde immer nur die ersten 2 ifs und das commit "gleichbleibend" sein. Der Rest vom Code ist aber ja eben trotzdem sehr ähnlich aber nicht gemeinsam... oder ist meine Vorstellungskraft grad falsch?
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Karlirex: Ich würde sagen ja, denn *alles* was man an einen Namen binden kann, ist ein Objekt/Wert. Auch Klassen.

Edit: Quick'n'Dirty und ungetestet:

Code: Alles auswählen

def generic_add(
    mandatory_fields,
    model_type,
    field_names,
    model_descriptive_name,
    template,
    title,
    query_data=False,
):
    if request.method == "POST":
        if not all(request.form[name] for name in mandatory_fields):
            flash("Alle Felder beachten.", "error")
        else:
            db.session.add(
                model_type(
                    **{name: request.form[name] for name in field_names}
                )
            )
            db.session.commit()
            flash(f"{model_descriptive_name} erfolgreich hinzugefügt.")
            return redirect(url_for("home"))

    return render_template(
        template,
        title=title,
        data=model_type.query.all() if query_data else None,
    )


@app.route("/customers", methods=["GET", "POST"])
@login_required
def customers():
    return generic_add(
        ["name", "email", "bank_account"],
        Customer,
        ["name", "address", "email", "phone", "bank_account"],
        "Kunde",
        "HTML/customers.html",
        "Customers",
    )


@app.route("/employees", methods=["GET", "POST"])
@login_required
def employees():
    return generic_add(
        ["name", "email"],
        Employee,
        ["name", "address", "email", "phone", "group"],
        "Mitarbeiter",
        "HTML/employees.html",
        "Employees",
        True,
    )
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Karlirex
User
Beiträge: 126
Registriert: Dienstag 18. August 2020, 18:27

@_blackjack_: Oh wow. Okay, dass hab ich so null gesehen. Wahnsinn. Ich merke mal wieder, wie wenig Programmiererfahrung bzgl Stil und co ich doch habe.
Danke :)
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Karlirex: Man könnte die Dopplung von Feldnamen aus den beiden Listen noch entfernen weil die `mandatory_fields` ja immer in den `field_names` enthalten sind. Und man könnte das wahrscheinlich auch durch Code ersetzen der diese Informationen aus dem Model holt, denn man kann da ja die Spaltenmetainformationen ja auch abfragen und alles was ``nullable=False`` ist, ist ja „mandatory“. Ausserdem könnte man den Beschreibenden Namen auch als Attribut auf den Model-Klassen setzen, dann braucht man den nicht übergeben.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten