Найти - Пользователи
Полная версия: wx.Python PyGridTableBase Как запихать в него данные?
Начало » Базы данных » wx.Python PyGridTableBase Как запихать в него данные?
1 2 3 4
FoxPython
О! Я заставил таки данные в гриде изменяться под действием пользователя!
Данные из cu.fetchall() пришлось превратить из кортежа в список списков или кортеж списков (запутался я с ними).
Вот так:

# -*- coding: utf-8 -*-
import wx, wx.grid, sqlite3 as db

class MainFrame(wx.Frame):
def __init__(self, parent, title, pos, size):
wx.Frame.__init__(self, parent, -1, title, pos=pos, size=size)
mypanel=self.mypanel=wx.Panel(self, -1)
c=db.connect(database='bigbase.sqlite3')
cu=c.cursor()
cu.execute('SELECT fam, im, ot, age FROM one')

mygrid=wx.grid.Grid(mypanel, size=(400,400))

#—-вот таким страшным способом————
cuu=
for i in cu.fetchall():
tmp=
for ii in i:
tmp.append(ii)
cuu.append(tmp)
#—-делается список списков, который уже можно изменять
#—-обращаясь к нему как к массиву по индексам: cuu='новое значение'
#—-ОПУПЕТЬ! Почему создатели питона не хотят сделать обычный tuple изменяемым?????
#—-чтоб не приходилось так извращаться!
table=MyTable(cuu)
mygrid.SetTable(table, True)

class MyTable(wx.grid.PyGridTableBase):
def __init__(self, dannie):
wx.grid.PyGridTableBase.__init__(self)
self.dannie=dannie
def GetNumberRows(self):
return len(self.dannie)
pass
def GetNumberCols(self):
return len(self.dannie)
pass
def IsEmptyCell(self, row, col):
return self.dannie is not None
pass
def GetValue(self, row, col):
value = self.dannie
if value is not None:
return value
else:
return ''
pass
def SetValue(self, row, col, value):
self.dannie=value
pass

====================================
Кстати, ПроДива, в твоём примере, вновь занесённые данные в сетку, каждый раз ЗАНОВО добавляются к уже существующим в базе. А мне надо, чтобы в базу возвращались изменённые пользователем данные. Т.е. сменил пользователь в сетке кому-нибудь фамилию с “Пупкин” на “Губкин” и в базе этот конкретный “Пупкин” должен измениться на “Губкин”.
Вот как это сделать? Как узнать какое значение в сетке соответствует значению в базе sqlite? Чтобы можно было изменить его. Наверное, у записей в базе есть (да обязаны быть!) уникальные номера и следить нужно за ними. Как до них добраться? Без таких номеров, невозможно будет проконтролировать какую запись изменил пользователь. Я ведь могу в сетку выдать и отсортированный результат запроса, так что не факт, что данные в сетке расположатся в том же порядке, что и в базе.

Ламерский вопрос: какая sql-команда позволяет изменить какую-либо конкретную запись?

———————–
В твоём примере некорректно printится номер (столбца и строки) ячейки, если перед тем как щёлкнуть какую-нибудь ячейку воспользоваться бегунком прокрутки. Только повторный щёлк заставит появиться правильный номер.
———————–
Почему в гриде не работают клавиши end и home?

БОЛЬШОЕ СПАСИБО заранее.
pyuser
строка:
cuu=
выполнит то же преобразование что и Ваш код (да и выглядит не очень страшно)

#—-вот таким страшным способом————
cuu=
for i in cu.fetchall():
tmp=
for ii in i:
tmp.append(ii)
cuu.append(tmp)
#—-делается список списков, который уже можно изменять

FoxPython
… Как узнать какое значение в сетке соответствует значению в базе sqlite? Чтобы можно было изменить его. Наверное, у записей в базе есть (да обязаны быть!) уникальные номера и следить нужно за ними. Как до них добраться? Без таких номеров, невозможно будет проконтролировать какую запись изменил пользователь. Я ведь могу в сетку выдать и отсортированный результат запроса, так что не факт, что данные в сетке расположатся в том же порядке, что и в базе.

Ламерский вопрос: какая sql-команда позволяет изменить какую-либо конкретную запись?
в идеале у каждой таблицы должно быть ключевое поле (primary, unique …)
тогда обновление очень просто:

update table_name set field_name=new_value, … where (key_field=key_value)
… - все обновляемые поля

если ключевые поля не предусмотрены то немного сложнее:

update table_name set field_name=new_value, … where ((field_name=old_value) and …))
первое … - все обновляемые поля,
а второе (после ключевого слова where) … - все поля таблицы
FoxPython
Как же я привык к фокспро (рыдающий смайл)…
Но всё равно спасибо, будем продолжать пытаться…

—————-
Давит грузом неопределённости питон 3000. Сейчас изучу питон 2.5.1, а он больше не поддерживается и не развивается! Потом все программы перелопачивать на питон 3000?
FoxPython
А, вообще, как ещё, кроме моего способа, можно сунуть данные из базы в таблицу PyGridTableBase? Неужели только моим способом? Что-то не верится…
PooH
Ну вот вам еще один вариант

# -*- coding: utf-8 -*-
import wx
import wx.grid
from sqlite3 import dbapi2 as db

class BaseTable(wx.grid.PyGridTableBase):
def __init__(self, connection):
super(BaseTable, self).__init__()
self.connection = connection
self.refresh()

def field_list(self):
ls =
ls.extend()
return ls

def refresh(self):
cur = self.connection.cursor()
cur.execute(“select %s from %s;” % (','.join(self.field_list()), self.table))
self.data =
cur.close()

def save_value(self, row, col):
if self.data:
cur = self.connection.cursor()
cur.execute(“update %s set %s = ‘%s’ where %s = %s;” % (self.table,
self.columns.name, self.data, self.primary_key, self.data))
self.connection.commit()
cur.close()

def GetNumberRows(self):
return len(self.data)

def GetNumberCols(self):
return len(self.columns)

def GetColLabelValue(self, col):
return self.columns.title

def GetRowLabelValue(self, row):
return str(row)

def IsEmptyCell(self, row, col):
return self.data is not None

def GetValue(self, row, col):
return self.data

def SetValue(self, row, col, value):
if self.data != value:
self.data = value
self.save_value(row, col)

def InsertRows(self, pos=1, numRows=1):
cur = self.connection.cursor()
for n in range(pos, pos+numRows):
cur.execute(“insert into %s(%s) values(%s);” % (self.table, ‘,’.join(),
‘,’.join()))
ls =
ls.extend()
self.data.insert(n, ls)
self.connection.commit()
cur.close()
msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_ROWS_INSERTED, pos, numRows)
self.GetView().ProcessTableMessage(msg)
return True

def DeleteRows(self, pos=0, numRows=1):
cur = self.connection.cursor()
for n in range(pos, pos+numRows):
cur.execute(“delete from %s where %s = %s;” % (self.table, self.primary_key, self.data))
self.connection.commit()
del self.data
cur.close()
msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_ROWS_DELETED, pos, numRows)
self.GetView().ProcessTableMessage(msg)
return True


class Column(object):

def __init__(self, name, title, default=None):
self.name = name
self.title = title
self.default = default

class TestTable(BaseTable):
table = ‘test’
primary_key = ‘id’
columns = (
Column('numb', u'Табельный\nномер'),
Column('fio', u'ФИО', u'Иванов Иван Иваныч'),
Column('dolzh', u'Должность',u'Стрелочник'),
)

class SimpleGrid(wx.grid.Grid):

def __init__(self, parent, model):
super(SimpleGrid, self).__init__(parent, -1)
self.SetTable(model)
for col in range(0, self.GetNumberCols()):
self.AutoSizeColumn(col, setAsMin=True)
self.Bind(wx.EVT_KEY_DOWN, self.on_key_down)

def on_key_down(self, event):
if event.ControlDown() and event.KeyCode == wx.WXK_DELETE:
self.on_delete(event)
elif event.KeyCode == wx.WXK_INSERT:
self.on_insert(event)
event.Skip()

def on_insert(self, event):
print “on_insert”
self.InsertRows(self.GetGridCursorRow())

def on_delete(self, event):
print “on_delete”
self.DeleteRows(self.GetGridCursorRow())


def create_db(name):
con = db.connect(name)
cur = con.cursor()
try:
cur.execute(“”“
create table test (
id integer primary key autoincrement,
numb integer,
fio varchar(200),
dolzh varchar(200));
”“”)
for x in xrange(0, 500):
cur.execute(u“insert into test(numb, fio, dolzh) values(%d, ‘Сотрудник %d’, ‘Должность %d’)” % (x,x,x))
except db.DatabaseError, x:
print “Не могу создать базу!”, x
print “База создана!”
con.commit()
return con


class TestFrame(wx.Frame):

def __init__(self, parent):
wx.Frame.__init__(self, parent, -1, “A Grid”, size=(500, 400))
grid = SimpleGrid(self, TestTable(create_db('test.db')))


if __name__ == ‘__main__’:
app = wx.PySimpleApp()
frame = TestFrame(None)
frame.Show(True)
app.MainLoop()


Только что набросал на коленке, но базовые моменты думаю будут понятны
FoxPython
Спасибо за пример. Счас буду по полочкам раскладывать.

———————————————————————-
Если, вдруг, кому охота ответить:

class Myclass():
a=1
b=2
——————————————–
class Myclass():
def __init__(self, tralivali):
self.a=1
self.b=2

Это что, получается, что метод __init__ не являются целиком и полностью принадлежностью класса Myclass? Ведь метод __init__ описан в самом этом классе. Логично же, что он относится ИМЕННО к нему. Зачем же иниту передавать self?

———————————————————————-

П.С. У Вас у всех в примерах после того как программа выдаст “не могу создать базу”, вдобавок напишет и “база создана”. Так низя! Дезинформация, понимашь!
Viper
FoxPython
Это что, получается, что метод __init__ не являются целиком и полностью принадлежностью класса Myclass? Ведь метод __init__ описан в самом этом классе. Логично же, что он относится ИМЕННО к нему. Зачем же иниту передавать self?
__init__ является целиком и полностью принадлежностью класса, а self указывает на обьект этого класса. :)
PooH
FoxPython
П.С. У Вас у всех в примерах после того как программа выдаст “не могу создать базу”, вдобавок напишет и “база создана”. Так низя! Дезинформация, понимашь!
Ну а что ты хотел для простого примера?! Я просто взял код создания базы из предыдущего примера. В серьезных приложениях база обычно создается при установке.

По поводу того примера что постил я:

1. Лучше для работы с базой воспользоваться каким-нибудь готовым ОРМ, например SQLObject или SQLAlchemy. Тогда код BaseTable упрощается до безобразия
2. У меня изменения в базу постятся при изменении ячейки, лучше, наверно, постить на переходе на другую строку, как принято в фоксе и прочих делфи
3. Для большого набора данных лучше использовать буфер и прокручивать набор через него
4. Интересно так же расширить интерфейс BaseTable методами для поиска, фильтрации и т.д. и написать обобщенный грид для всего этого дела
5. TestTable, наследуемый от BaseTable, содержит только описание конкретного набора данных, интересно добавить в это описание валидаторы и рендеры.
6. В обработчике on_key_down, лучше не вызывать напрямую on_insert и on_delete, а создать для этого свои события и инициировать их

Если найду время накатаю более идеологически грамотный пример ;)
pythonwin
PooH, спасибо за последовательность действий и за код :)
PooH
1. Лучше для работы с базой воспользоваться каким-нибудь готовым ОРМ, например SQLObject или SQLAlchemy. Тогда код BaseTable упрощается до безобразия
согласен это очень хороший вариант, но только если не критична эффективность кода и данных не много (в основном ячеек). Если же таблицы большие или в записи есть большое поле, то лучше делать запросы на более низком уровне (например на sqlbuilder или да просто запросы на sql)
PooH
3. Для большого набора данных лучше использовать буфер и прокручивать набор через него
для экономии ОЗУ можно использовать временные файлы :)
PooH
pythonwin
Если же таблицы большие или в записи есть большое поле, то лучше делать запросы на более низком уровне (например на sqlbuilder или да просто запросы на sql)
А здесь поможет lazy loading в ОРМ для больших полей.
pythonwin
PooH
3. Для большого набора данных лучше использовать буфер и прокручивать набор через него
для экономии ОЗУ можно использовать временные файлы :)
Здесь речь не столько об экономии ОЗУ, сколько об экономии сетевого трафика :) Обычно никто не будет прокручивать в гриде набор из 1000 и более записей, а воспользуется поиском или фильтром. Так зачем это тянуть на клиента?!
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB