bilder in eine mysql datenbank speichern

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Mittwoch 22. November 2006, 04:01

Hilft dir dieser Thread weiter? Du kannst mal abschauen, wie jens das gemacht hat.

Ansonsten wenn du mit SQL unter Python arbeitest, solltest du unbedingt die Seite [wiki]Parametrisierte SQL Queries[/wiki] lesen.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
jens
Moderator
Beiträge: 8482
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Mittwoch 22. November 2006, 11:03

Jup, sourcecode gibt es hier: http://pylucid.net/trac/browser/PyLucid ... Storage.py

Das wichstigste steckt in def insert() :)

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
JR
User
Beiträge: 286
Registriert: Montag 20. Februar 2006, 16:43
Wohnort: Berlin

Mittwoch 22. November 2006, 13:24

Hi Leonidas und Jens!

Danke für eure Antworten und danke für den Hinweis Leonidas.
Habe mir PyLucid und das Script FileStorage mal runtergeladen.

Ist das Speichern von Binärdaten Festplatte -> BLOB-Spalte komplizierter, so dass ich mich da in den Code einarbeiten muss?

Soweit ich weiß, kann man doch in MySQL direkt ein Statement absetzen, bei welchem man einen konkreten Dateipfad angibt, wenn man eine Datei in eine BLOB-Spalte schreiben möchte. Das ist doch bestimmt am einfachsten und auch am sichersten (was es Zeichensatzprobleme etc. angeht).

Auf den ersten Blick, habe ich in der Funktion "insert" nicht erkannt, was da passiert.
Aber vielelicht steige ich ja heute abend da durch...

Viele Grüße
Jamil
Benutzeravatar
jens
Moderator
Beiträge: 8482
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Mittwoch 22. November 2006, 13:40

Also im Grunde ist es ganz einfach:

Code: Alles auswählen

# Die Tabelle für die Daten sieht so aus:
"""CREATE TABLE TabellenName (
    id INT(11) NOT NULL auto_increment,
    data LONGBLOB,
    PRIMARY KEY (id)
);"""


# Ich hab festgestellt, das 4es ohne ein base64 encoding nicht geht, sollte
# es aber eigentlich
data = base64.encodestring(data)


# Daten eintragen
cursor.execute(
    "INSERT INTO TabellenName (data) VALUES (%s);",
    (data,)
)
Generell ist es allerdings nicht zu empfehlen Binärdaten in die DB zu packen. Bei meinem FileStorage mache ich da allerdings eine Ausnahme.

Einfach ist es allerdings ein Verz. zu erstellen, das Schreibrechte für alle zu geben und dann dorthin die Daten zu speichern. Ich mag es alledings nicht so gern, ein Verz. mit Schreibrechte für alle :)

Ansonsten erzähl mal, was du überhaupt vor hast!

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
JR
User
Beiträge: 286
Registriert: Montag 20. Februar 2006, 16:43
Wohnort: Berlin

Mittwoch 22. November 2006, 13:44

HI Jens!

Das "data" in der Klammer (Zeile 11). Wie ermittest du das?

Ich habe zum Beispiel eine Bilddatei "C:\Bild.jpg"


Und nun? so?

Code: Alles auswählen

f = file('C:\\Bild.jpg', 'r')
if f:
    data = f.read()
    f.close()
    data = base64.encodestring(data)


    # Daten eintragen
    cursor.execute(
        "INSERT INTO TabellenName (data) VALUES (%s);",
        (data,)
    )
Melde mich gegen 19 Uhr, da ich jetzt erst mal weg bin :-(

Grüße
Jamil
Benutzeravatar
jens
Moderator
Beiträge: 8482
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Mittwoch 22. November 2006, 13:47

Ja, genau, warum nicht... Wobei, das soll das "if f:" bringen? Wenn du einen fehler beim öffnen abfangen willst, solltest du das mit einem try-except um f=file() machen ;)

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Mittwoch 22. November 2006, 13:51

jens hat geschrieben:Einfach ist es allerdings ein Verz. zu erstellen, das Schreibrechte für alle zu geben und dann dorthin die Daten zu speichern. Ich mag es alledings nicht so gern, ein Verz. mit Schreibrechte für alle :)
Stimmt - man kann auch einfach das Schreibrecht nur für den User des Serverprozesses geben und damit ist das gelöst.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
jens
Moderator
Beiträge: 8482
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Mittwoch 22. November 2006, 14:00

Leonidas hat geschrieben:Stimmt - man kann auch einfach das Schreibrecht nur für den User des Serverprozesses geben und damit ist das gelöst.
Genau.

Allerdings laufen CGI Skripte im SharedWebhosting i.d.R. als User nobody Group nobody... Man muß also ein wenig aufpassen ;)

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
JR
User
Beiträge: 286
Registriert: Montag 20. Februar 2006, 16:43
Wohnort: Berlin

Mittwoch 22. November 2006, 20:45

Hi ihr beiden!

Also ich bekomme es nicht hin :-(
Langsam komme ich mir so vor, als wenn ich mich zu dumm anstelle...

Also ich habe mal ein Beispiel gemacht, in dem ich es so versuche, wie jens es mir geschildert hat.
Interessant sind Zeilen 60-67

Code: Alles auswählen

# -*- coding: iso-8859-1 -*-
# File: test.py
import wx
import MySQLdb
import base64

HOST = 'localhost'
PORT = 3306
USER = 'FPK'
PASSW = 'kmmanager'
DB = 'afv'

"""
CREATE TABLE test (
  `test_id` int(10) unsigned NOT NULL auto_increment,
  `test_blob` blob,
  PRIMARY KEY  (`test_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
"""
#------------------------------------------------------------------------         
class MyFrame(wx.Dialog):
    def __init__(self, parent, title):
        wx.Dialog.__init__(self, parent, -1, title,
                          pos=(150, 150), size=(300, 350))
        
        self.ConnectToDB()
        panel = wx.Panel(self, -1)
       
        self.emptyBmp = wx.EmptyBitmap(width=400, height=400)        
        self.pic = wx.StaticBitmap(panel, -1, self.emptyBmp)
        
        self.btn_Load = wx.Button(panel, -1, 'Lade und speichere Bild')
        self.btn_Load.Bind(wx.EVT_BUTTON, self.LoadPic)
        self.btn_Remove = wx.Button(panel, -1, 'Entferne Bild')
        self.btn_Remove.Bind(wx.EVT_BUTTON, self.RemovePic)
        self.btn_Remove.Disable()
        
        btn_sizer = wx.BoxSizer(wx.HORIZONTAL)
        btn_sizer.Add(self.btn_Load, 0, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 15)
        btn_sizer.Add(self.btn_Remove, 0, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 15)   
        
        main_sizer = wx.BoxSizer(wx.VERTICAL)
        main_sizer.Add(self.pic, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 15)
        main_sizer.Add(btn_sizer, 0, wx.ALL|wx.ALIGN_CENTER|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 15)

        panel.SetSizer(main_sizer)
        main_sizer.Fit(self)
        
        self.main_sizer = main_sizer
        
        self.Bind(wx.EVT_CLOSE, self.OnClose)
    #------------------------------------------------------------------------ 
    def LoadPic(self, event):
        wildcard = "Alle Bilddateien|*.bmp;*.jpg;*.png;*.jpeg;*.gif"
        dlg = wx.FileDialog(
            self, message='Wähle eine Bilddatei', defaultDir=wx.StandardPaths.Get().GetUserConfigDir(), 
            defaultFile="", wildcard=wildcard, style=wx.OPEN | wx.FILE_MUST_EXIST 
            ) 
        if dlg.ShowModal() == wx.ID_OK:
            file_path = dlg.GetPaths()[0]
            image = wx.Image(file_path, wx.BITMAP_TYPE_ANY)
            self.SetPictureImage(image) 
            f = file(file_path, 'r')
            data = f.read()
            data = base64.encodestring(data)
            self.SQL('INSERT INTO test SET test_blob=' + data + ';')
                
            f.close()
            self.btn_Remove.Enable()
        
        if event:
            event.Skip()
    #-------------------------------------------------  
    def SetPictureImage(self, image):
        w, h = float(image.GetWidth()), float(image.GetHeight())
        targetSize = 400.0
        if h != targetSize:
            scale = h / targetSize
            image = image.Scale(w / scale, h / scale)          
        bmp = wx.BitmapFromImage(image)

        self.pic.SetSize((bmp.GetWidth(), bmp.GetHeight()))
        self.pic.SetBitmap(bmp)
        self.main_sizer.Layout()
    #------------------------------------------------------------------------     
    def RemovePic(self, event):
        self.pic.SetBitmap(self.emptyBmp)
        self.btn_Remove.Disable()
    #------------------------------------------------------------------------ 
    def ConnectToDB(self):
        self.Con = MySQLdb.Connect(host = HOST, 
                                   port = PORT, 
                                   user = USER, 
                                   passwd = PASSW, 
                                   db = DB)        
    #------------------------------------------------------------------------ 
    def SQL(self, statement):
        Cursor = self.Con.cursor()
        Cursor.execute(statement) 
        result = Cursor.fetchall()
        self.Con.commit()
        return result
    #------------------------------------------------------------------------     
    def OnClose(self, event):   
        self.Con.close()
        self.Destroy()
#------------------------------------------------------------------------ 
class MyApp(wx.App):
    def OnInit(self):
        dialog = MyFrame(None, 'Bild in Blob speichern')
        if dialog.ShowModal() == wx.ID_OK:
            print dialog.object.GetDate() 
        return True
        
app = MyApp(0)
app.MainLoop()

Wenn ihr wxPython nicht installiert habt, könnt ihr anhand der Methode LoadPic sehen, was ich da tue.
Es klappt so nicht. Ich bekomme einen Fehler von MySQL zurück.

Code: Alles auswählen

_mysql_exceptions.ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '/9j/4AAQSkZJRgABAgEASABIAAD/4Q8cRXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEAAAE=' at line 1")
Kurze Erklärung, warum ich Bilder in der DB speichern will.
Für unseren Flugverein entwickle ich an einem Programm. Jeder bekommt einen Client, DB-Server ist im Netz. Im Personenverzeichnis will ich jedem Mitglied anbieten, ein kleines Bild von sich hochzuladen. Damit die anderen es auch gleich zu Hause sehen können, muss es in der DB liegen.

Viele Grüße
Jamil
Zuletzt geändert von JR am Mittwoch 22. November 2006, 21:28, insgesamt 1-mal geändert.
Benutzeravatar
Whitie
User
Beiträge: 111
Registriert: Sonntag 4. Juni 2006, 12:39
Wohnort: Schulzendorf

Mittwoch 22. November 2006, 21:22

Hi JR,
ich bin mir nicht sicher, aber überlass das Einfügen des Wertes mal dem SQL Modul.

So sollte es funktionieren:

Code: Alles auswählen

...
f = file(file_path, 'r')
data = f.read()
f.close()
data = base64.encodestring(data)
self.SQL('INSERT INTO test SET test_blob=%s', (data,))
...
def SQL(self, statement, vals):
        Cursor = self.Con.cursor()
        if vals:
            # Wenn Werte in vals sind
            Cursor.execute(statement, vals)
       else:
            # Wenn leerer Tupel übergeben wurde
            Cursor.execute(statement)
        result = Cursor.fetchall()
        Con.commit()
        return result
Gruß, Whitie
JR
User
Beiträge: 286
Registriert: Montag 20. Februar 2006, 16:43
Wohnort: Berlin

Mittwoch 22. November 2006, 21:28

Hi Whitie!

Habe das probiert, MySQl liefert zwar keinen Fehler mehr, doch wenn ich mir den Spaltenwert über dem MySQL-Query Browser ansehe, erkennt er nicht, dass es ein Bild ist. Das geht sonst immer. Er speichert irgendwas ab, aber es ist zerhauen.

Blöd, dass es so schwierig ist
Jamil
Benutzeravatar
Whitie
User
Beiträge: 111
Registriert: Sonntag 4. Juni 2006, 12:39
Wohnort: Schulzendorf

Mittwoch 22. November 2006, 21:35

Hi JR,
ich kenn den Query-Browser nicht, aber wie soll er wissen, dass der base64 kodierte String mal ein Bild war. Ich denke die fehlende Anzeige liegt an der Kodierung.

Gruß, Whitie
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Mittwoch 22. November 2006, 22:37

Hi

Benutzt doch beim Dateiöffnen den modus 'rb' und nicht nur 'r' (unter Windows kann das zu Problemen führen)

Gruss
BlackJack

Mittwoch 22. November 2006, 23:45

Kann man Blobs überhaupt mit normalen literalen SQL-Inserts einfügen? Das sind doch Binärdaten, da dürfte doch alles möglich vorkommen was ausserhalb von ASCII-Text liegt. Ich würde das auch dem DB-Modul überlassen.
JR
User
Beiträge: 286
Registriert: Montag 20. Februar 2006, 16:43
Wohnort: Berlin

Donnerstag 23. November 2006, 08:19

Hi rayo und BlckJack!

Zunächst zum Modus, wie ich die Datei lese. In meinem Python-GEPACKT Buch zu Python 2.4 wurde dieser Modus gar nicht erwähnt. Was für eine Enttäuschung.
So hat es geklappt.
Das Bild ist in der DB gelandet.

Schwere Geburt. Vielen vielen Dank für eure Hilfe.

Hier ist der funktionierende Code:

Code: Alles auswählen

# -*- coding: iso-8859-1 -*-
# File: test.py
import wx
import MySQLdb
import base64

HOST = 'localhost'
PORT = 3306
USER = 'FPK'
PASSW = 'kmmanager'
DB = 'afv'

"""
CREATE TABLE test (
  `test_id` int(10) unsigned NOT NULL auto_increment,
  `test_blob` blob,
  PRIMARY KEY  (`test_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
"""
#------------------------------------------------------------------------         
class MyFrame(wx.Dialog):
    def __init__(self, parent, title):
        wx.Dialog.__init__(self, parent, -1, title,
                          pos=(150, 150), size=(300, 350))
        
        self.ConnectToDB()
        panel = wx.Panel(self, -1)
       
        self.emptyBmp = wx.EmptyBitmap(width=400, height=400)        
        self.pic = wx.StaticBitmap(panel, -1, self.emptyBmp)
        
        self.btn_Load = wx.Button(panel, -1, 'Lade und speichere Bild')
        self.btn_Load.Bind(wx.EVT_BUTTON, self.LoadPic)
        self.btn_Remove = wx.Button(panel, -1, 'Entferne Bild')
        self.btn_Remove.Bind(wx.EVT_BUTTON, self.RemovePic)
        self.btn_Remove.Disable()
        
        btn_sizer = wx.BoxSizer(wx.HORIZONTAL)
        btn_sizer.Add(self.btn_Load, 0, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 15)
        btn_sizer.Add(self.btn_Remove, 0, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 15)   
        
        main_sizer = wx.BoxSizer(wx.VERTICAL)
        main_sizer.Add(self.pic, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 15)
        main_sizer.Add(btn_sizer, 0, wx.ALL|wx.ALIGN_CENTER|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 15)

        panel.SetSizer(main_sizer)
        main_sizer.Fit(self)
        
        self.main_sizer = main_sizer
        
        self.Bind(wx.EVT_CLOSE, self.OnClose)
    #------------------------------------------------------------------------ 
    def LoadPic(self, event):
        wildcard = "Alle Bilddateien|*.bmp;*.jpg;*.png;*.jpeg;*.gif"
        dlg = wx.FileDialog(
            self, message='Wähle eine Bilddatei', defaultDir=wx.StandardPaths.Get().GetUserConfigDir(), 
            defaultFile="", wildcard=wildcard, style=wx.OPEN | wx.FILE_MUST_EXIST 
            ) 
        if dlg.ShowModal() == wx.ID_OK:
            file_path = dlg.GetPaths()[0]
            image = wx.Image(file_path, wx.BITMAP_TYPE_ANY)
            self.SetPictureImage(image) 
            f = file(file_path, 'rb')
            data = f.read()
#            data = base64.encodestring(data)
            f.close()
            self.SQL('INSERT INTO test SET test_blob=%s', [data,])
            f.close()
            self.btn_Remove.Enable()
        
        if event:
            event.Skip()
    #-------------------------------------------------  
    def SetPictureImage(self, image):
        w, h = float(image.GetWidth()), float(image.GetHeight())
        targetSize = 400.0
        if h != targetSize:
            scale = h / targetSize
            image = image.Scale(w / scale, h / scale)          
        bmp = wx.BitmapFromImage(image)

        self.pic.SetSize((bmp.GetWidth(), bmp.GetHeight()))
        self.pic.SetBitmap(bmp)
        self.main_sizer.Layout()
    #------------------------------------------------------------------------     
    def RemovePic(self, event):
        self.pic.SetBitmap(self.emptyBmp)
        self.btn_Remove.Disable()
    #------------------------------------------------------------------------ 
    def ConnectToDB(self):
        self.Con = MySQLdb.Connect(host = HOST, 
                                   port = PORT, 
                                   user = USER, 
                                   passwd = PASSW, 
                                   db = DB)        
    #------------------------------------------------------------------------ 
    def SQL(self, statement, parameters=None):
        Cursor = self.Con.cursor()
        Cursor.execute(statement, parameters) 
        result = Cursor.fetchall()
        self.Con.commit()
        return result
    #------------------------------------------------------------------------     
    def OnClose(self, event):   
        self.Con.close()
        self.Destroy()
#------------------------------------------------------------------------ 
class MyApp(wx.App):
    def OnInit(self):
        dialog = MyFrame(None, 'Bild in Blob speichern')
        if dialog.ShowModal() == wx.ID_OK:
            print dialog.object.GetDate() 
        return True
        
app = MyApp(0)
app.MainLoop()
Viele Grüße
Jamil
Antworten