Store Gtk.Textbuffer in SQL database. Encoding troubles

纵饮孤独 提交于 2021-02-08 11:51:34

问题


I'm working on a note taking app using python2/Gtk3/Glade.

The notes are stored in a MySQL Database and displayed in a TextView widget. I can load/store/display plain text fine. However I want the ability to add images to the note page, and store them in the Database.so the data has to be serialised and I'm having some trouble figuring out how to encode/decode the serialised data going in and out of the Database. I'm getting unicode start byte errors. If was working with files I could just open the file in binary mode, but I'm storing as a string in a Database. I've tried encoding/decoding as UTF-8 and ASCII using bytes() and string.encode()[see the sample code below] and a few other ways but none work.

I am using this function to add the image to the textview buffer:

def _AddImagetoNode(self,oWidget):
    filenm = None
    seliter = self.GetTreeSelection(self.treeview)
    filenm = self.FileOpenDiag("Select an Image To Insert.","Image","*.png,*.jpg,*.bmp")
    if filenm == None:
        return()

    #filenm =  "/home/drift/Pictures/a.png"
    buf = self.dataview.get_buffer()
    pixbuf = GdkPixbuf.Pixbuf.new_from_file(filenm)
    #pixbuf.scale_simple(dest_width, dest_height, gtk.gdk.INTERP_BILINEAR)
    buf.insert_pixbuf(buf.get_end_iter(), pixbuf) 
    self.dataview.set_buffer(buf)
    self.dataview.show()

This is the function that stores the textview buffer:

def SaveDataView(self):
    global DataViewNode
    global DataViewIsImage

    if len(self.GetProjectName()) == 0:
        return()
    buf = self.dataview.get_buffer()

    format = buf.register_serialize_tagset()
    data2 = buf.serialize(buf, format, buf.get_start_iter(), buf.get_end_iter())

    #convert bytes(data) to string
    data = data2.decode(encoding='UTF-8') #<< i think my problem is here
    print("save b4 decode >>>>>>:%s"%data2)

    sql = "UPDATE " + self.GetProjectName() + " SET tDataPath=%s  WHERE tNodeID=%s"
    val = (data, DataViewNode)

    self.cursor.execute(sql,val)
    self.mariadb_connection.commit()

This is the function that loads the Buffer:

def UpdateDataView(self, nodeid):
    global DataViewNode
    #global DataViewIsFile
    DataViewNode=nodeid


    if self.GetProjectName() != None and DataViewNode != None:
        self.dataview.set_sensitive(True)
    else:
        self.dataview.set_sensitive(False)
        self.dataview.show()
        return()

    buf = self.dataview.get_buffer()
    buf.set_text('')
    enc = self.DbGetNodeData(nodeid)



    #convert string(enc) to bytes
    data = enc.encode(encoding='UTF-8')#<<< i think my problem is here
    print("update after decode >>>>>>>>>: %s"%data)
    ########### load
    format = buf.register_deserialize_tagset()
    buf.deserialize(buf, format, buf.get_end_iter(),data) 


    #buf.set_text(enc)
    self.dataview.set_buffer(buf)
    self.dataview.show()

I'm using mysql.connector to connect to a mariadb. This is the sql connection string:

self.mariadb_connection = mariadb.connect(user='box', password='box', host='localhost', database='Boxer',charset='utf8')

This is the error im getting.

Traceback (most recent call last): File "Boxer.py", line 402, in _TreeSelectionChanged self.SaveDataView() File "Boxer.py", line 334, in SaveDataView data = data2.decode(encoding='UTF-8') UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb4 in position 174: invalid start byte Traceback (most recent call last): File "Boxer.py", line 398, in _DataViewLostFocus self.SaveDataView() File "Boxer.py", line 334, in SaveDataView data = data2.decode(encoding='UTF-8') UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb4 in position 174: invalid start byte

With this code I can add/edit plain text in the text view and successfully save/load it but as soon as I add the image, I'm get the encoding errors. Any help would be appreciated.


回答1:


Here is a more complete example:

def example (self):

        #retrieve info from first textview
        buf = self.builder.get_object('textbuffer1')
        format = buf.register_serialize_tagset()
        data = buf.serialize(buf, format, buf.get_start_iter(), buf.get_end_iter())

        #run db update to prove it can be inserted into a database
        db = psycopg2.connect(database= 'silrep_restore3', host='192.168.0.101', 
                                        user='postgres', password = 'true', 
                                        port = '5432')
        c = db.cursor()
        c.execute("UPDATE products SET byt = %s WHERE id = 1", (psycopg2.Binary(data),))

        #append info to second treeview as a proof of concept
        c.execute("SELECT byt FROM products WHERE id = 1")
        data = c.fetchone()[0]

        buf = self.builder.get_object('textbuffer2')
        format = buf.register_deserialize_tagset()
        buf.deserialize(buf, format, buf.get_end_iter(), data)

Since you are using MySQL, I recommend reading this article about inserting and retrieving data like you are.

For my example I used a bytea column. In MySQL this is may be a BLOB or BINARY type.

P.S. Sorry for not having a complete MySQL example in my answer. I would have posted a comment, but comments are pathetic for proper formatting.




回答2:


Got it workings. thanks to theGtknerd your answer was the key. for anyone else having trouble with this i ended up using the BLOB type for the MySQL field type for the column im working with. I tried BINARY[it returnd malformed serialize data] AND VARBINARY [wouldnt even allow me to create the table] so i ended up using the LONGBLOB type. here is the working code for anyone that needs it.

def UpdateDataView(self, nodeid):
    global DataViewNode
    #global DataViewIsFile
    DataViewNode=nodeid


    if self.GetProjectName() != None and DataViewNode != None:
        self.dataview.set_sensitive(True)
    else:
        self.dataview.set_sensitive(False)
        self.dataview.show()
        return()

    buf = self.dataview.get_buffer()
    buf.set_text('')
    data = self.DbGetNodeData(nodeid)
    if data =='':
        return()


    format = buf.register_deserialize_tagset()
    buf.deserialize(buf, format, buf.get_end_iter(),data)       

    self.dataview.set_buffer(buf)
    self.dataview.show() 


def SaveDataView(self):
    global DataViewNode
    global DataViewIsImage

    if len(self.GetProjectName()) == 0:
        return()
    buf = self.dataview.get_buffer()
    enc = buf.get_text(buf.get_start_iter(),buf.get_end_iter(),False)
    self.AddData2Db(DataViewNode,enc)

    format = buf.register_serialize_tagset()
    data = buf.serialize(buf, format, buf.get_start_iter(), buf.get_end_iter())

    sql = "UPDATE " + self.GetProjectName() + " SET tDataPath=%s  WHERE tNodeID=%s"
    val = (data, DataViewNode)

    self.cursor.execute(sql,val)
    self.mariadb_connection.commit()

and im using this to create the table

sql = "CREATE TABLE %s (tParentNodeID TEXT,tNodeTxt TEXT,tNodeID TEXT,tDataPath LONGBLOB)" %pName
    self.cursor.execute(sql)
    self.mariadb_connection.commit()


来源:https://stackoverflow.com/questions/53290926/store-gtk-textbuffer-in-sql-database-encoding-troubles

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!