Befehle aus Datenbank ausführen

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
Landario
User
Beiträge: 13
Registriert: Mittwoch 2. Dezember 2015, 20:26
Wohnort: Aalen
Kontaktdaten:

Servus,

Ich finde auch nach etlichen Stunden nicht wirklich etwas das mich weiterbringt, vielleicht hat ja jemand eine Dokumentation parat und kann mir helfen.

Durch Zufall sollen verscheidene definierte Befehle (Bewegungen an einem Modell) ausgeführt werden. Diese Befehle stehen in einer Datenbank. Über random wird eine Zahl generiert die der ID der zufälligen Bewegung entspricht.

Die Datenbank sieht im Prinzip so aus:

Code: Alles auswählen

id     |      name        |      code
1          eins                     Befehl1
2          zwei                    Befehl2
3          drei                     Befehl3



Minimalbeispiel meines Programmes soweit:

Code: Alles auswählen

import random
import time
import os, sys, sqlite3

connection = sqlite3.connect("database.db")
cursor = connection.cursor()

random.seed()

for x in range (99):

    x = random.randint(1,10)
    print (x)

    cursor.execute('SELECT * FROM movements WHERE id=?', (x,))
    for data in cursor:
        print(data[1])
        data[2] # Code der Ausgeführt werden soll
    print()
    time.sleep(2)

connection.close()
Zufällige Datensätze ausgeben über die Random-ID funktioniert tadellos. Nur wie wandel ich den Text aus der spalte code wieder in Phyton-Befehle um?


P.S.: Ich weiß das Befehle in ner Datenbank nicht das sicherste sind und Schindluder damnit getrieben werden kann. Aber für das Programm reicht das, und ist auch kein Sicherheitsrisiko.
Zuletzt geändert von Anonymous am Montag 21. Dezember 2015, 12:57, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Mit freundlichen Grüßen,
Landario
BlackJack

@Landario: Du solltest Dir trotzdem überlegen das *nicht* zu tun. Speicher die Bewegungen als Daten und interpretiere die dann. Das ist sicherer — in beiden Bedeutungen des Wortes: „safety“ und „security“. Und unabhängiger von Python ist es auch.

Wie sehen die möglichen ”Befehle” denn aus?

Anmerkungen zu Quelltext: `random.seed()` ist unnötig, kann sogar unter bestimmten Bedingungen zu weniger Zufall führen → weg damit.

`x` wird für mehrere Sachen verwendet. Wenn Du die Schleifenvariable nicht benötigst, dann könntest Du sie `_` nennen. Das ist eine übliche Konvention für Werte die nicht benötigt werden, denen man aus syntaktischen Gründen aber einen Namen geben muss.

Es ist nicht garantiert das IDs (Primärschlüssel) aufsteigende, lückenlose Werte haben. Ausserdem kann auch 0 oder negative Zahlen gültige IDs sein. Wenn Du IDs hast die grösser 10 sind, werden die Datensätze nicht mehr erfasst. Ich würde an der Stelle ja lieber alle IDs abfragen, oder falls die Daten nicht zu gross sind, gleich alle Datensätze, und dann mit `random.choose()` auswählen.

Wenn man einen Datensatz anhand seiner ID abfragt, dann braucht man nicht mit einer Schleife über die Ergebnisse iterieren sondern man holt sich genau diesen einen Datensatz mit `fetchone()`.
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

Hint: bei den Build-In Funktionen gibt es zwei, die für dein Vorhaben in Frage kommen könnten. Warum du das aber _nicht_ machen solltest hat BlackJack schon ausgrführt :-)

Gruß, noisefloor
BlackJack

@Landario: Die Importe `os` und `sys` werden nicht verwendet.

Bei Datenbankabfragen sollte man '*' vermeiden und besser alles das was man haben möchte explizit hinschreiben. Der Quelltext wird dann verständlicher und man bekommt keine Probleme wenn Tabellen erweitert werden oder Spalten umsortiert werden, oder bei der Abfrage mehr potentielle Spalten durch einen JOIN hinzukommen.

Das und die Bemerkungen vom letzten Beitrag führen dann zu (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf-8
from __future__ import absolute_import, division, print_function
import random
import sqlite3
import time
from contextlib import closing


def main():  
    with closing(sqlite3.connect('database.db')) as connection:
        cursor = connection.cursor()
        cursor.execute('SELECT name, code FROM movements')
        movements = cursor.fetchall()
    for _ in range(99):
        name, code = random.choice(movements)
        print(name, code)

        print()
        time.sleep(2)

if __name__ == '__main__':
    main()
Landario
User
Beiträge: 13
Registriert: Mittwoch 2. Dezember 2015, 20:26
Wohnort: Aalen
Kontaktdaten:

@BlackJack
Danke für die schnellen antworten, es handelt sich um Koordinaten die gesendet werden sollen.....langfristig sollen diese auch ohne Code in der Datenbank landen. Das mit den ID's ist mir bewusst, jedoch sind die Daten in dieser Tabelle alle statisch, also können nicht geändert, hinzugefügt, etc werden, somit ist die ID manuell vorgegeben und immer positiv von 1-soviel ich brauch. Es handelt sich bei dem Code nur um ein Minimalbeispiel Testprogramm....uneindeutige Variabeln werden noch ersetz. Aber ich räume mal etwas auf bevor ich nochmal was poste^^

In der Beta würde ich jedoch trotzdem gerne erstmal den Code direkt aus der Datrenbank laden und dies später beheben wenn ich mehr Zeit dafür habe (Bitte respektiert diese Entscheidung)

@noisefloor The evil eval? Hab durch Zufall den Befehl probiert da ich ihn aus PHP kenne und ich glaube der müsste es sein oder?
Mit freundlichen Grüßen,
Landario
Landario
User
Beiträge: 13
Registriert: Mittwoch 2. Dezember 2015, 20:26
Wohnort: Aalen
Kontaktdaten:

The evil eval war die gesuchte Funktion, sobald das Grundgerüst steht wird aber darauf verzichtet und die Daten aus der DB interpretiert.

Code: Alles auswählen

eval()
Danke an alle (:
Mit freundlichen Grüßen,
Landario
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@Landario: Du machst Dir lieber jetzt und später die doppelte Arbeit, als gleich ordentlich zu programmieren :evil: . Eine Funktion mit Parametern aus einer Datenbank aufzurufen ist definitiv weniger Aufwand als diese Funktion in die Datenbank zu schreiben und dann umständlich den Code aufzurufen.
BlackJack

@Landario: Erfahrungsgemäss werden Sachen die man wissentlich unsauber löst, mit dem Vorsatz das zu ändern wenn man mal Zeit hat, so gut wie nie tatsächlich noch mal sauber gelöst. So etwas bleibt in der Regel für die Ewigkeit.
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
Landario hat geschrieben: es handelt sich um Koordinaten die gesendet werden sollen
Aber dann macht `eval()` dort erst recht keinen Sinn. Lies' die Koordinaten aus und übergib' sie als Parameter an eine Funktionen. Dann ist es sauber. Und auch später wesentlich einfacher, von DB auf ein INI-File oder JSON oder so umzustellen.

Gruß, noisefloor
Landario
User
Beiträge: 13
Registriert: Mittwoch 2. Dezember 2015, 20:26
Wohnort: Aalen
Kontaktdaten:

Es war ja nur zum testen , habe jetzt alles umgestellt und die Datenbanken sind wieder sicher :)
Mit freundlichen Grüßen,
Landario
Antworten