MySQLdb wrapper

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
fs111
User
Beiträge: 170
Registriert: Samstag 15. November 2003, 11:42
Kontaktdaten:

Nur eine kleine Anregung, Strings braucht man nicht mit + zusammenkleben, wenn sie über mehrere Zeilen gehen, das ist eh furchtbar langsam, einfach """"""-Multiline-Strings benutzen.

fs111
Pydoc-Integration in vim - Feedback willkommen: http://www.vim.org/scripts/script.php?script_id=910
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

fs111 hat geschrieben:""""""-Multiline-Strings benutzen.
Das ist eigentlich eine schöne Geschichte in Python... Nur hat man entweder doofen Source-Code oder einige Leerzeilen drin :(

Da benutze ich lieber +=

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

Ich finde beides hässlich. ``+=`` führt unnötige Operationen durch und bei Multiline-Zeichenketten muss man sie entweder an den linken Rand "kleben" oder führende Leerzeichen in jeder Zeile in Kauf nehmen oder beseitigen. Ich benutze immer Klammern und den Umstand, das Zeichenketten, die nur durch Whitespace voneinander getrennt sind, beim laden/übersetzen zu einer Zeichenkette werden:

Code: Alles auswählen

a = '''Hallo
Welt!'''
b = 'Hallo\n'
b += 'Welt!'
c = ('Hallo\n'
     'Welt!')
a == b == c
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Ob das besser ist lässt sich streiten, aber immerhin:

Code: Alles auswählen

#!/usr/bin/env python
# -*- encoding: latin-1 -*-

import textwrap

def testdef():
    t = """
    Ein Text. Erste Ebene.
    Noch eine Ebene. Sollte nicht eingerückt werden.
        Letzte Ebene. Sollte eingerückt werden"""
    print t
    t = textwrap.dedent(t)
    print t

testdef()
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Erhlich gesagt, kann ich mich mit beiden nich so richtig anfreuden :(

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Ja, das verhalten Pythons ist in diesem Fall echt etwas blöd. :evil:
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Clython
User
Beiträge: 151
Registriert: Samstag 21. August 2004, 13:58
Wohnort: Schweiz, BE-2500

Hallo Jens

vielen Dank erst mal für deine exzellenten Module. Die ersparen mir eine Tonne Programmiercode. Jetzt hätte ich da aber eine kleine Frage zum MySQL Wrapper:

Code: Alles auswählen

def __init__( self, *args, **kwargs ):
        self.db             = MySQLdb.connect( *args, **kwargs )
        self.cursor         = self.db.cursor()
        self.tableprefix    = ""
        self.debug          = False
Wofür stehen *args und **kwargs?
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Damit werden die Parameter die an die db()-Klasse übergeben werden, dem MySQLdb.connect() weiter gegeben...

Schau mal auf http://www.python.org/peps/pep-0249.html ganz unten in den "Footnotes" bei Punkt [1]:
As a guideline the connection constructor parameters should be implemented as keyword parameters for more intuitive use and follow this order of parameters:

dsn Data source name as string
user User name as string (optional)
password Password as string (optional)
host Hostname (optional)
database Database name (optional)

E.g. a connect could look like this:

connect(dsn='myhost:MYDB',user='guido',password='234$')
Zur genaueren erklärung von *args und **kwargs hab ich nur das gefunden:
http://www.python.org/doc/faq/programmi ... to-another

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Neue Version:
v0.0.9
- in update() wird nun auch die where-value SQL-Escaped
v0.0.8
- bei select() werden nun auch die select-values mit der SQLdb escaped
- methode _make_values() gelöscht und einfach durch tuple() erstetzt ;)

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: UTF-8 -*-

# by jensdiemer.de (steht unter GPL-License)

"""
MySQLdb wrapper

Allgemeine Routinen für eine einfachere SQL Benutzung

Benötigt MySQLdb download unter:
http://sourceforge.net/projects/mysql-python/


Information
-----------
Generell wird keine Tracebacks abgefangen, das muß immer im eigentlichen
Programm erledigt werden!

Wie man die Klasse benutzt, kann man unten sehen ;)



ToDo
----
    * Es wird immer das paramstyle 'format' benutzt. Also mit %s escaped
"""

__version__="0.0.9"

__history__="""
v0.0.9
    - in update() wird nun auch die where-value SQL-Escaped
v0.0.8
    - bei select() werden nun auch die select-values mit der SQLdb escaped
    - methode _make_values() gelöscht und einfach durch tuple() erstetzt ;)
v0.0.7
    - Statt query_fetch_row() wird der Cursor jetzt mit MySQLdb.cursors.DictCursor erstellt.
        Somit liefern alle Abfragen ein dict zurück! Das ganze funktioniert auch mit der uralten
        MySQLdb v0.9.1
    - DEL: query_fetch_row()
    - NEU: fetchall()
v0.0.6
    - NEU: query_fetch_row() und exist_table_name()
v0.0.5
    - Stellt über self.conn das Connection-Objekt zur verfügung
v0.0.4
    - Bugfixes
    - Debugfunktion eingefügt
    - Beispiel hinzugefügt
    - SQL "*"-select verbessert.
v0.0.3
    - Allgemeine SQL insert und update Funktion eingefügt
    - SQL-where-Parameter kann nun auch meherere Bedingungen haben
v0.0.2
    - Allgemeine select-SQL-Anweisung
    - Fehlerausgabe bei fehlerhaften SQL-Anfrage
v0.0.1
    - erste Release
"""



try:
    import MySQLdb
except ImportError, e:
    print "Content-type: text/html\n"
    print "<h1>Error</h1>"
    print "<h3>MySQLdb import error! Modul 'python-mysqldb' not installed???</h3>"
    print "<p>Error Msg.:<br/>%s</p>" % e
    print '<a href="http://sourceforge.net/projects/mysql-python/">MySQLdb project page</a>'
    import sys
    sys.exit(0)




class mySQL:
    """
    Klasse, die nur allgemeine SQL-Funktionen beinhaltet
    """
    def __init__( self, *args, **kwargs ):
        self.conn           = MySQLdb.connect( *args, **kwargs )
        self.cursor         = self.conn.cursor( MySQLdb.cursors.DictCursor )
        self.tableprefix    = ""

        # Bei debug=True werden die SQL-Befehle aufgegeben
        self.debug          = False

    def get( self, SQLcommand, SQL_values = () ):
        """kombiniert execute und fetchall mit Tabellennamenplatzhalter"""
        self.cursor.execute(
                SQLcommand.replace("$tableprefix$", self.tableprefix),
                SQL_values
            )
        return self.cursor.fetchall()

    def fetchall( self, SQLcommand, SQL_values = () ):
        """ kombiniert execute und fetchall """
        self.cursor.execute( SQLcommand, SQL_values )
        return self.cursor.fetchall()

    def insert( self, table, data ):
        """
        Vereinfachter Insert, per dict
        data ist ein Dict, wobei die SQL-Felder den Key-Namen im Dict entsprechen muß!
        """
        items   = data.keys()
        values = tuple( data.values() )

        SQLcommand = "INSERT INTO %(prefix)s%(table)s ( %(items)s ) VALUES ( %(values)s );" % {
                "prefix"        : self.tableprefix,
                "table"         : table,
                "items"         : ",".join( items ),
                "values"        : ",".join( ["%s"]*len(values) ) # Platzhalter für SQLdb-escape
            }

        if self.debug:
            print "-"*80
            print "db.insert - Debug:"
            print "SQLcommand.:",SQLcommand
            print "values.....:",values
            print "-"*80

        self.cursor.execute( SQLcommand, values )

    def update( self, table, data, where, limit=False ):
        """
        Vereinfachte SQL-update Funktion
        """
        data_keys   = data.keys()

        values      = data.values()
        values.append( where[1] )
        values      = tuple( values )

        if limit:
            limit = "LIMIT %s" % limit
        else:
            limit = ""

        SQLcommand = "UPDATE %(prefix)s%(table)s SET %(set)s WHERE %(where)s %(limit)s;" % {
                "prefix"    : self.tableprefix,
                "table"     : table,
                "set"       : ",".join( [str(i)+"=%s" for i in data_keys] ),
                "where"     : where[0] + "=%s",
                "limit"     : limit
            }

        if self.debug:
            print "-"*80
            print "db.update - Debug:"
            print "SQLcommand.:",SQLcommand
            print "values.....:",values
            print "-"*80

        self.cursor.execute( SQLcommand, values )

    def select( self, select_items, from_table, where=None, order=None, limit=None, maxrows=0, how=1 ):
        """
        Allgemeine SQL-SELECT Anweisung
        where, order und limit sind optional

        where
        -----
        Die where Klausel ist ein wenig special.

        einfache where Klausel:
        where=("parent",0) ===> WHERE `parent`="0"

        mehrfache where Klausel:
        where=[("parent",0),("id",0)] ===> WHERE `parent`="0" and `id`="0"

        maxrows - Anzahl der zurückgegebenen Datensätze, =0 alle Datensätze
        how     - Form der zurückgegebenen Daten. =1 -> als Dict, =0 als Tuple
        """

        SQLcommand = "SELECT " + ",".join( select_items )
        SQLcommand += " FROM %s%s" % ( self.tableprefix, from_table )

        SQL_parameters_values = []

        if where != None:
            if type( where[0] ) == str:
                # es ist nur eine where-Regel vorhanden.
                # Damit die folgenden Anweisungen auch gehen
                where = [ where ]

            where_string = []
            for item in where:
                where_string.append( item[0] + "=%s" )
                SQL_parameters_values.append( item[1] )

            SQLcommand += ' WHERE %s' % " and ".join( where_string )

        if order != None:
            SQLcommand += " ORDER BY %s %s" % order

        if limit != None:
            SQLcommand += " LIMIT %s,%s" % limit

        if self.debug:
            print "-"*80
            print "db.select - Debug:"
            print "SQLcommand:", SQLcommand

        self.cursor.execute( SQLcommand, tuple( SQL_parameters_values ) )
        return self.cursor.fetchall()

    def exist_table_name( self, table_name ):
        """ Überprüft die existens eines Tabellen-Namens """
        self.cursor.execute( "SHOW TABLES" )
        for line in self.cursor.fetchall():
            if line[0] == table_name:
                return True
        return False

    def dump_select_result( self, result ):
        print "*** dumb select result ***"
        for i in xrange( len(result) ):
            print "%s - %s" % (i, result[i])

    def close( self ):
        "Connection schließen"
        self.conn.close()




if __name__ == "__main__":
    db = mySQL(
            host    = "localhost",
            user    = "SQL-DB-Username",
            passwd  = "SQL-DB-Password",
            db      = "SQL-DB-Name"
        )

    # Prefix for all SQL-commands:
    db.tableprefix = "test_"

    # Prints all SQL-command:
    db.debug = True

    SQLcommand  = "CREATE TABLE %sTestTable (" % db.tableprefix
    SQLcommand += "id INT( 11 ) NOT NULL AUTO_INCREMENT,"
    SQLcommand += "data1 VARCHAR( 50 ) NOT NULL,"
    SQLcommand += "data2 VARCHAR( 50 ) NOT NULL,"
    SQLcommand += "PRIMARY KEY ( id )"
    SQLcommand += ") COMMENT = '%s - temporary test table';" % __file__

    print "\n\nCreat a temporary test table - execute SQL-command directly."
    try:
        db.cursor.execute( SQLcommand )
    except Exception, e:
        print "Can't create table: '%s'" % e


    print "\n\nSQL-insert Function:"
    db.insert(
            table = "TestTable",
            data  = { "data1" : "Value A 1", "data2" : "Value A 2" }
        )

    print "\n\nadds a new value:"
    db.insert(
            table = "TestTable",
            data  = { "data1" : "Value B 1", "data2" : "Value B 2" }
        )

    print "\n\nSQL-select Function (db.select):"
    result = db.select(
            select_items    = ["id","data1","data2"],
            from_table      = "TestTable",
            #~ where           = ("parent",0)#,debug=1
        )
    db.dump_select_result( result )


    print "\n\nUpdate an item (db.update)."
    data = { "data1" : "NewValue1!"}
    db.update(
            table   = "TestTable",
            data    = data,
            where   = ("id",1),
            limit   = 1
        )


    print "\n\nSee the new value (db.select):"
    result = db.select(
            select_items    = ["data1"],
            from_table      = "TestTable",
            where           = ("id",1)
        )
    db.dump_select_result( result )


    print "\n\nSee all values via SQL '*'-select:"
    result = db.select(
            select_items    = "*",
            from_table      = "TestTable",
            #~ where           = ("id",1)
        )
    db.dump_select_result( result )


    print "\n\nDelete the temporary test Table."
    db.cursor.execute( "DROP TABLE %sTestTable" % db.tableprefix )


    print "\n\nClose SQL-connection."
    db.close()
Ausgaben:
Creat a temporary test table - execute SQL-command directly.


SQL-insert Function:
--------------------------------------------------------------------------------
db.insert - Debug:
SQLcommand.: INSERT INTO test_TestTable ( data1,data2 ) VALUES ( %s,%s );
values.....: ('Value A 1', 'Value A 2')
--------------------------------------------------------------------------------


adds a new value:
--------------------------------------------------------------------------------
db.insert - Debug:
SQLcommand.: INSERT INTO test_TestTable ( data1,data2 ) VALUES ( %s,%s );
values.....: ('Value B 1', 'Value B 2')
--------------------------------------------------------------------------------


SQL-select Function (db.select):
--------------------------------------------------------------------------------
db.select - Debug:
SQLcommand: SELECT id,data1,data2 FROM test_TestTable
*** dumb select result ***
0 - {'data1': 'Value A 1', 'id': 1L, 'data2': 'Value A 2'}
1 - {'data1': 'Value B 1', 'id': 2L, 'data2': 'Value B 2'}
2 - {'data1': 'Value A 1', 'id': 3L, 'data2': 'Value A 2'}
3 - {'data1': 'Value B 1', 'id': 4L, 'data2': 'Value B 2'}


Update an item (db.update).
--------------------------------------------------------------------------------
db.update - Debug:
SQLcommand.: UPDATE test_TestTable SET data1=%s WHERE id=%s LIMIT 1;
values.....: ('NewValue1!', 1)
--------------------------------------------------------------------------------


See the new value (db.select):
--------------------------------------------------------------------------------
db.select - Debug:
SQLcommand: SELECT data1 FROM test_TestTable WHERE id=%s
*** dumb select result ***
0 - {'data1': 'NewValue1!'}


See all values via SQL '*'-select:
--------------------------------------------------------------------------------
db.select - Debug:
SQLcommand: SELECT * FROM test_TestTable
*** dumb select result ***
0 - {'data1': 'NewValue1!', 'id': 1L, 'data2': 'Value A 2'}
1 - {'data1': 'Value B 1', 'id': 2L, 'data2': 'Value B 2'}
2 - {'data1': 'Value A 1', 'id': 3L, 'data2': 'Value A 2'}
3 - {'data1': 'Value B 1', 'id': 4L, 'data2': 'Value B 2'}


Delete the temporary test Table.


Close SQL-connection.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Antworten