I'm trying to get back into Python and I'm once again stuck with this problem I've had before of making objects accessible to one another. In this simple example I am displaying a panel with a button and a text box. Clicking on the text box calls a function which queries a database and returns a cursor with the retrieved data. I need to make it so that either the LookupSQL function or the ShowClientData function can write this output, in a loop, to the Text box. The TextBox (outputBox) is unknown to any other functions currently. How do I make it so that the other functions know what it is?
import wx
import pypyodbc
conn = pypyodbc.connect(driver='{SQL Server}', server='.', database='TheDB', uid='sa', pwd='Pass')
class Audit(wx.Frame):
def __init__(self, *args, **kwargs):
super(Example, self).__init__(*args, **kwargs)
self.InitUI()
def InitUI(self):
panel = wx.Panel(self)
hbox = wx.BoxSizer()
sizer = wx.GridSizer(6,1,2,2)
btn1 = wx.Button(panel, label='Clients')
outputBox = wx.TextCtrl(panel, -1, style = wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL)
sizer.AddMany([btn1, btn2, btn3, btn4, btn5, btn6])
hbox.Add(sizer, 0, wx.ALL, 15)
hbox.Add(outputBox, 1, wx.EXPAND)
panel.SetSizer(hbox)
btn1.Bind(wx.EVT_BUTTON, self.ShowClientData)
self.SetSize((800, 600))
self.SetTitle('Audit View')
self.Centre()
self.Show(True)
def ShowClientData(self, event):
SQL = 'select * from V_UpdatedClient'
recursor = lookupSQL(SQL)
for row in recursor:
rChange = row[0]
rItemType = row[1]
rPK = row[2]
rItemCode = row[3]
rFieldName = row[4]
rOldValue = row[5]
rNewValue = row[6]
rUpdateDate = row[7]
rUserName = row[8]
print('%s %s %s %s %s %s %s %s %s' % (rChange, rItemType, rPK, rItemCode, rFieldName, rOldValue, rNewValue, rUpdateDate, rUserName))
def lookupSQL(SQLString):
cursor = conn.cursor()
cursor.execute(SQLString)
return cursor
cursor.close()
def main():
ex = wx.App()
Audit(None)
ex.MainLoop()
if __name__ == '__main__':
main()
What you are looking for is called data attributes.
self.outputBox = wx.TextCtrl(panel, -1, style = wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL)
And then within ShowClientData you can write
self.outputBox.AppendText("some text")
As long as you have that self reference, you can access its attributes.
Edit:
When you do the above change, you can't refer to the text box by just outputBox anymore, you should instead access it via self:
hbox.Add(self.outputBox, 1, wx.EXPAND)
Declaring it as globally is very bad!
Related
I have a Django 3.2, python 3.6 website. I am having issues uploading multiple files to a model that also has a M2M field. I get an error in the save_related method at the indicated line:
ValueError: "<Image: title>" needs to have a value for field "image_id" before this many-to-many relationship can be used.
I have used this same method to upload multiple files to models without an M2M field, so I am not sure where I am going wrong.
models.py
class Tags(models.Model):
tag_id = models.AutoField(primary_key=True)
tag_name = models.CharField(max_length=255)
class Image(models.Model):
image_id = models.AutoField(primary_key=True)
title = models.CharField(max_length=255)
description = models.TextField()
original_image = models.ImageField('original_image', upload_to=settings.ORIGINAL_IMAGE_PATH,)
exif_data = models.JSONField(default=dict)
computed_sha256 = models.CharField(editable=False, max_length=64, default="foobar")
tags = models.ManyToManyField(Tags, blank=True)
admin.py
class ImageForm(forms.ModelForm):
original_image = forms.ImageField(widget=forms.FileInput(attrs={'multiple': True}))
class ImageAdmin(admin.ModelAdmin):
form = ImageForm
class Meta:
model = Image
fields = '__all__'
def save_related(self, request, form, *args, **kwargs):
tags = form.cleaned_data.pop('tags', ())
image = form.instance
for tag in tags:
image.tags.add(tag) # error occurs here
super(ImageAdmin, self).save_related(request, form, *args, **kwargs)
def save_model(self, request, obj, form, change):
if form.is_valid():
if not change:
# Uploading one or more images))
files = request.FILES.getlist('original_image')
for f in files:
image = Image()
if "Title" not in form.cleaned_data:
form.cleaned_data['Title'] = clean_title(f.name)
image.computed_sha256 = image_processing_utils.compute_sha256(f)
image.original_image = f
image.description = form.cleaned_data['description']
image.exif_data = image_processing_utils.read_exif_data(f)
image.save()
else:
pass
I could not find a way to upload multiple files to a model with a M2M field, so I punted and took the M2M field out of the model.
models.py
class Image(models.Model):
image_id = models.AutoField(primary_key=True)
title = models.CharField(max_length=255, blank=True)
description = models.TextField()
original_image = models.FileField('original_image', upload_to=settings.ORIGINAL_IMAGE_PATH,)
exif_data = models.JSONField(default=dict)
computed_sha256 = models.CharField(editable=False, max_length=64, default="foobar")
def __str__(self):
return self.title
class Meta:
db_table = 'Image'
class ImageTags(models.Model):
image_id = models.ForeignKey(Image, on_delete=models.CASCADE)
tag_id = models.ForeignKey(Tags, on_delete=models.CASCADE)
class Meta:
db_table = 'ImageTags'
admin.py
class ImageAdminForm(forms.ModelForm):
original_image = forms.ImageField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
def __init__(self, *args, **kwargs):
super(ImageAdminForm, self).__init__(*args, **kwargs)
tag_choices = Tags.objects.values_list('tag_id', 'tag_name')
self.fields['tags'] = forms.MultipleChoiceField(choices=tag_choices, widget=forms.SelectMultiple, required=False)
class ImageAdmin(admin.ModelAdmin):
list_display = ('image_id', 'title', 'description', 'views', 'original_image', 'get_tags', 'exif_data', 'created', 'updated')
readonly_fields = ('thumb_image', 'album_image', 'display_image', 'exif_data', 'views', )
form = ImageAdminForm
class Meta:
model = Image
fields = '__all__'
fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('title', 'description', 'original_image',)
}),
)
def get_form(self, request, obj=None, **kwargs):
# https://stackoverflow.com/questions/1057252/how-do-i-access-the-request-object-or-any-other-variable-in-a-forms-clean-met
logger.debug("get_form START")
kwargs['fields'] = flatten_fieldsets(self.fieldsets)
form = super(ImageAdmin, self).get_form(request, obj, **kwargs)
form.request_obj = request
logger.debug("get_form END")
return form
def get_fieldsets(self, request, obj=None):
logger.debug("get_fieldsets START")
import copy
fieldsets = copy.deepcopy(super(ImageAdmin, self).get_fieldsets(request, obj))
logger.debug("1 fieldsets=%s" % fieldsets)
change_page_fieldset = list(fieldsets[0][1]['fields'])
logger.debug("1 change_page_fieldset=%s" % change_page_fieldset)
#if obj:
if 'tags' not in change_page_fieldset:
change_page_fieldset.append('tags')
logger.debug('2 change_page_fieldset=%s' % change_page_fieldset)
fieldsets[0][1]['fields'] = tuple(change_page_fieldset)
logger.debug('2 fieldsets=%s' % fieldsets)
return fieldsets
def get_tags(self, obj):
tag_ids = list(ImageTags.objects.filter(image_id=obj).values_list("tag_id", flat=True))
tag_names = list(Tags.objects.filter(tag_id__in=tag_ids).values_list('tag_name', flat=True))
return ", ".join([t for t in tag_names])
def save_model(self, request, obj, form, change):
logger.debug("save_model START")
logger.debug("obj=%s, change=%s, valid=%s" % (obj, change, form.is_valid()))
logger.debug("changed fields=%s" % form.changed_data)
logger.debug("obj.original_image=%s" % obj.original_image)
if utils.is_celery_working():
if form.is_valid():
if not change:
# Uploading one or more images
logger.debug("\tvalid form")
logger.debug("form.cleaned_data=%s",form.cleaned_data)
logger.debug("files=%s" % request.FILES.getlist('original_image'))
files = request.FILES.getlist('original_image')
for f in files:
image = Image()
if not form.cleaned_data['title']:
image.title = clean_title(f.name)
else:
image.title = form.cleaned_data['title']
logger.debug("form.cleaned_data['title']=%s" % form.cleaned_data['title'])
logger.debug("f=%s" % f)
image.original_image = f
image.description = form.cleaned_data['description']
image.save()
# save the tags
tags = form.cleaned_data['tags']
for tag in tags:
ImageTags.objects.create(tag_id_id=int(tag), image_id_id=image.pk)
#super().save_model(request, obj, form, change)
else:
# processing a change form, so redo all the fields
pass
#super().save_model(request, obj, form, change)
else:
# error - form is invalid
pass
else:
# error - celery not working
pass
logger.debug("save_model END")
Could you please help me in solving this issue as i am a python PyQt beginner ...i have created a simple application with python PyQt4 for a simple math calculations and having the result in textEdit2 and textEdit3 every thing went fine when i click on calculate push button, values appear in the above textedits...what i want is to save the results on the same text edits so that next time when i open the application and open the data file i find every thing in place. I created the save and open actions...but it saves all the results in the same text edit..
i am attaching my code and also the main window with results that needed to be saved and another shot after saving and opening the application and having all the results in one textedit
enter code here
import sys
from PyQt4 import QtCore, QtGui, uic
import os #os used to interface with windows
import datetime as dt
import pickle
qtCreatorFile = "save.ui" # Enter ui file here
Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile)
class MyApp(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self):
super (MyApp,self).__init__()
Ui_MainWindow.__init__(self)
self.setupUi(self)
self.initUI()
self.calc.clicked.connect(self.Bss)
def Bss (self):
x = float(self.textEdit.toPlainText())
y = float(self.textEdit1.toPlainText())
z= x+y
w= x**2
z_string = str(z) #convert z value to a string then add this string to textEdit and set as Text
self.textEdit2.setText(z_string)
w_string = str(w)
self.textEdit3.setText(w_string)
def initUI(self): #QAction class insert New,action save in the main menue bar
newAction = QtGui.QAction('New', self)
newAction.setShortcut('Ctrl+N')
newAction.setStatusTip('Create new file')
newAction.triggered.connect(self.newFile)
saveAction = QtGui.QAction('Save as', self)
saveAction.setShortcut('Ctrl+S')
saveAction.setStatusTip('Save current file')
saveAction.triggered.connect(self.saveFile)
openAction = QtGui.QAction('Open', self)
openAction.setShortcut('Ctrl+O')
openAction.setStatusTip('Open a file')
openAction.triggered.connect(self.openFile)
closeAction = QtGui.QAction('Close', self)
closeAction.setShortcut('Ctrl+Q')
closeAction.setStatusTip('Close Notepad')
closeAction.triggered.connect(self.close)
menubar = self.menuBar()
fileMenu = menubar.addMenu('&File')
fileMenu.addAction(newAction)
fileMenu.addAction(saveAction)
fileMenu.addAction(openAction)
fileMenu.addAction(closeAction)
self.show()
self.statusBar()
def newFile(self): #create a new function and remove all values in the QTEXTedit
self.textEdit.clear()
self.textEdit1.clear()
self.textEdit2.clear()
self.textEdit3.clear()
def openFile(self):
self.text = QtGui.QTextEdit(self)
filename = QtGui.QFileDialog.getOpenFileName(self, 'Open File', os.getenv('HOME'))
f = open(filename, 'r')
filedata = f.read()
self.textEdit1.setText(filedata)
self.textEdit2.setText(filedata)
self.textEdit3.setText(filedata)
f.close()
self.show()
def saveFile(self): # saving argument values in a filedata
self.text = QtGui.QTextEdit(self)
filename = QtGui.QFileDialog.getSaveFileName(self, 'Save File', os.getenv('HOME'))
f = open(filename, 'w')
filedata = self.textEdit1.toPlainText()
f.write(filedata)
filedata = self.textEdit2.toPlainText()
f.write(filedata)
filedata = self.textEdit3.toPlainText()
f.write(filedata)
f.close()
def closeEvent(self, event):
reply = QtGui.QMessageBox.question(self, 'Message',
"Are you sure to quit?", QtGui.QMessageBox.Yes |
QtGui.QMessageBox.No, QtGui.QMessageBox.No)
if reply == QtGui.QMessageBox.Yes:
event.accept()
else:
event.ignore()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MyApp()
window.show()
sys.exit(app.exec_())
if I understand your question properly, since you are writing textEdit values to a file in order, you'll need to read that values line by line when opening the file, instead of reading the whole file content using read() method. so the openFile() method should be something like this:
def openFile(self):
self.text = QtGui.QTextEdit(self)
filename = QtGui.QFileDialog.getOpenFileName(self, 'Open File', os.getenv('HOME'))
count = 0
with open(filename,'r') as f:
for line in f:
count = count + 1
if count == 1 : self.textEdit1.setText(line)
elif count == 2 : self.textEdit2.setText(line)
elif count == 3 : self.textEdit3.setText(line)
else: break
self.show()
hope it helps!
UPDATE:
also change saveFile() method like below:
def saveFile(self): # saving argument values in a filedata
self.text = QtGui.QTextEdit(self)
filename = QtGui.QFileDialog.getSaveFileName(self, 'Save File', os.getenv('HOME'))
f = open(filename, 'w')
filedata = self.textEdit1.toPlainText()
filedata = str(filedata)+"\n"
f.write(filedata)
filedata = self.textEdit2.toPlainText()
filedata = str(filedata)+"\n"
f.write(filedata)
filedata = self.textEdit3.toPlainText()
filedata = str(filedata)+"\n"
f.write(filedata)
f.close()
I just started with wxPython and have problems with the binding.
Usually the examples I find to bind a button event are done withself.Bind(wx.EVT_BUTTON, self.OnWhatEverFunction, button). I have a frame with a panel inside and a button and what ever I tried, the outcome is always a flashing frame that appears in a split second and that's it. Since the code isn't that much I attach it here and hope one of you can show me the way out of my little problem.
Thanks in advance,
Thomas
#!/usr/bin/python
import wx
class CPFSFrame(wx.Frame):
def __init__(self, parent, title):
super(CPFSFrame, self).__init__(parent, title=title,
style = wx.BORDER | wx.CAPTION | wx.SYSTEM_MENU | wx.CLOSE_BOX,
size=(350, 200))
panel = wx.Panel(self, -1)
pNumberLabel = wx.StaticText(panel, -1, 'Project number: ')
pNumberText = wx.TextCtrl(panel, -1, '', size=(175, -1))
pNumberText.SetInsertionPoint(0)
pNameLabel = wx.StaticText(panel, -1, 'Project name: ')
pNameText = wx.TextCtrl(panel, -1, '', size=(175, -1))
pNameText.SetInsertionPoint(0)
pButton = wx.Button(panel, label='Create')
pButton.Bind(wx.EVT_BUTTON, self.OnCreate)
sizer = wx.FlexGridSizer(cols=2, hgap=6, vgap=6)
sizer.AddMany([pNumberLabel, pNumberText, pNameLabel, pNameText, pButton])
panel.SetSizer(sizer)
statusBar = self.CreateStatusBar()
def OnCreate(self, evt):
self.Close(True)
self.Centre()
self.Show()
if __name__ == '__main__':
app = wx.App()
CPFSFrame(None, title='Create New Project Folder Structure')
app.MainLoop()
You need to put the "self.Show()" method in the init section of the code. At first I thought OnCreate() was running and if it was, then it would just close the frame immediately so you wouldn't see anything. I would call it OnClose instead. Here's a working example:
import wx
class CPFSFrame(wx.Frame):
def __init__(self, parent, title):
super(CPFSFrame, self).__init__(parent, title=title,
style = wx.BORDER | wx.CAPTION | wx.SYSTEM_MENU | wx.CLOSE_BOX,
size=(350, 200))
panel = wx.Panel(self, -1)
pNumberLabel = wx.StaticText(panel, -1, 'Project number: ')
pNumberText = wx.TextCtrl(panel, -1, '', size=(175, -1))
pNumberText.SetInsertionPoint(0)
pNameLabel = wx.StaticText(panel, -1, 'Project name: ')
pNameText = wx.TextCtrl(panel, -1, '', size=(175, -1))
pNameText.SetInsertionPoint(0)
pButton = wx.Button(panel, label='Create')
pButton.Bind(wx.EVT_BUTTON, self.OnClose)
sizer = wx.FlexGridSizer(cols=2, hgap=6, vgap=6)
sizer.AddMany([pNumberLabel, pNumberText, pNameLabel, pNameText, pButton])
panel.SetSizer(sizer)
statusBar = self.CreateStatusBar()
self.Show()
def OnClose(self, evt):
self.Close(True)
if __name__ == '__main__':
app = wx.App()
CPFSFrame(None, title='Create New Project Folder Structure')
app.MainLoop()
I have 2 functions in Lua which create a dictionary table and allow to check if a word exists:
local dictTable = {}
local dictTableSize = 0
function buildDictionary()
local path = system.pathForFile("wordlist.txt")
local file = io.open( path, "r")
if file then
for line in file:lines() do
dictTable[line] = true
dictTableSize = dictTableSize + 1
end
io.close(file)
end
end
function checkWord(word)
if dictTable[word] then
return(true)
else
return(false)
end
end
Now I want to be able to generate a couple of random words. But since the words are the keys, how can I pick some, given the dictTableSize.
Thanks
Just add a numerical index for each word to the dictionary while loading it:
function buildDictionary()
local path = system.pathForFile("wordlist.txt")
local file = io.open( path, "r")
if file then
local index = 1
for line in file:lines() do
dictTable[line] = true
dictTable[index] = line
index = index + 1
end
io.close(file)
end
end
Now you can get a random word like this:
function randomWord()
return dictTable[math.random(1,#dictTable)]
end
Side note: nil evaluates to false in Lua conditionals, so you could write checkWord like this:
function checkWord(word)
return dictTable[word]
end
Another side note, you'll get less polution of the global namespace if you wrap the dictionary functionality into an object:
local dictionary = { words = {} }
function dictionary:load()
local path = system.pathForFile('wordlist.txt')
local file = io.open( path, 'r')
if file then
local index = 1
for line in file:lines() do
self.words[line] = true
self.words[index] = line
index = index + 1
end
io.close(file)
end
end
function dictionary:checkWord(word)
return self.words[word]
end
function dictionary:randomWord()
return self.words[math.random(1,#self.words)]
end
Then you can say:
dictionary:load()
dictionary:checkWord('foobar')
dictionary:randomWord()
Probably two ways: you can keep the array with words and just do words[math.random(#words)] when you need to pick a random word (just make sure that the second one is different from the first).
The other way is to use next the number of times you need:
function findNth(t, n)
local val = next(t)
for i = 2, n do val = next(t, val) end
return val
end
This will return b for findNth({a = true, b = true, c = true}, 3) (the order is undefined).
You can avoid repetitive scanning by memoizing the results (at this point you will be better off using the first way).
this is a trade off that you have for using the word table the way you are. i would invert the word table once you load it, so that you can get references to words by index as well if you have to. something like this:
-- mimic your dictionary structure
local t = {
["asdf"] = true, ["wer"] = true, ["iweir"] = true, ["erer"] = true
}
-- function to invert your word table
function invert(tbl)
local t = {}
for k,_ in pairs(tbl) do
table.insert(t, k)
end
return t
end
-- now the code to grab random words
local idx1, idx2 = math.random(dictTableSize), math.random(dictTableSize)
local new_t = invert(t)
local word1, word2 = new_t[idx1], new_t[idx2]
-- word1 and word2 now have random words from your 'dictTable'
select
b.security_type,
b.symbol,
b.security_description,
b.trade_date_qty as 'axys_qty',
c.trade_date_qty as 'fidelity_qty',
c.trade_date_qty - b.trade_date_qty as 'qty_diff',
b.cost_basis as 'axys_cost',
c.cost_basis as 'fidelity_cost',
c.cost_basis - b.cost_basis as 'cost_diff'
from
account a
inner join advent_position b on a.fixed_account_number = b.account_number
inner join fidelity_position c on a.fixed_account_number = c.account_number and b.symbol = c.symbol
where
b.account_number = '636296651'
Basically, I have the ff. domains: Account, AdventPosition, FidelityPosition. I haven't set the relationship yet. I'm just wondering if there's a way to replicate the logic above using Criteria or HQL. Forgive me, I'm still new to Grails.
Thank you for any leads on this.
It'd be something close to this:
String hql = '''
select
b.securityType,
b.symbol,
b.securityDescription,
b.tradeDateQty,
c.tradeDateQty,
c.tradeDateQty - b.tradeDateQty,
b.costBasis,
c.costBasis,
c.costBasis - b.costBasis
from
Account a, AdventPosition b, FidelityPosition c
where
a.fixedAccountNumber = b.accountNumber
and a.fixedAccountNumber = c.accountNumber
and b.symbol = c.symbol
and b.accountNumber = :accountNumber
'''
def accountNumber = '636296651'
def results = Account.executeQuery(hql, [accountNumber: accountNumber])
The results will be an ArrayList of Object[], so you can iterate it with something like
for (row in results) {
def securityType = row[0]
def symbol = row[1]
def securityDescription = row[2]
def axys_qty = row[3]
def fidelity_qty = row[4]
def qty_diff = row[5]
def axys_cost = row[6]
def fidelity_cost = row[7]
def cost_diff = row[8]
}
I replaced the hard-coded account number with a named parameter; you can use regular ? like in SQL if you prefer and run 'def results = Account.executeQuery(hql, [accountNumber])', and of course if you intented it to be hard-coded then restore that and don't pass in the 2nd parameter, just run 'def results = Account.executeQuery(hql)'
just sharing the solution that I came up (while waiting for an answer :P) but note that the previous answer is way much better and faster:
def acc = Account.findByFixedAccountNumber('636296651')
List advPos = AdventPosition.findAllByAccountNumber('636296651')
List fidPos = advPos.collect {
FidelityPosition.findAllByAccountNumberAndSymbol('636296651', it.symbol)
}
def item = [:]
def res = []
def limit = advPos.size() - 1
for(i in 0..limit){
item.security_type = advPos[i].securityType
item.symbol = advPos[i].symbol
item.security_description = advPos[i].securityDescription
item.axys_qty = advPos[i].tradeDateQty
item.fidelity_qty = fidPos[i].tradeDateQty
item.qty_diff = item.fidelity_qty - item.axys_qty
item.axys_cost = advPos[i].costBasis
item.fidelity_cost = fidPos[i].costBasis
item.cost_diff = item.fidelity_cost - item.axys_cost
res.add(item)
}