How to display a selected field unique values from a selected layer as rows headers in QTableWidget using python for a QGIS plugin? - pyqt4

To build a form in Qt Designer for a QGIS plugin that does the following:
After the user has selected a layer and a field, from comboboxes, the unique values of this field to be displayed as rows headers in QTableWidget using python

def showdlg(self):
# show the dialog - ui file
self.dlg.show()
# Get the layers names
legendInterface = self.iface.legendInterface()
listLayerName = [i.name() for i in legendInterface.layers() if i.type() == QgsMapLayer.VectorLayer]
# Add all these layer names to the layer combobox
self.dlg.cmbLayer.addItems(listLayerName)
# When user selects a layer from the layer combobox
# insert the corresponding fields names to the field combobox
self.dlg.cmbLayer.currentIndexChanged[int].connect(self.FieldsNamestoFieldCombo)
# When user selects a field from the field combobox,
# insert the unique values of this field as the table' s rows names
self.dlg.cmbField.currentIndexChanged[int].connect(self.FieldUniqueValuestoTable)
def FieldsNamestoFieldCombo(self, index):
# get list of all vector layers in QGIS
legendInterface = self.iface.legendInterface()
listLayers = [layer for layer in legendInterface.layers() if layer.type() == QgsMapLayer.VectorLayer]
# get name of selected layer
provider = listLayers[index].dataProvider()
fields = provider.fields()
listFieldNames = [field.name() for field in fields]
# clear the combo box comboFieldList
self.dlg.cmbField.clear()
# add all these field names to combo box comboFieldList
self.dlg.cmbField.addItems(listFieldNames)
def FieldUniqueValuestoTable(self, index):
# Get the selected layer id
layer_id = getVectorLayerByName(self.dlg.cmbLayer.currentText())
# Get the selected field name and id
field = self.dlg.cmbField.currentText()
field_index = layer_id.fieldNameIndex(field)
#Get the unique values of the selected field
un_values = layer_id.uniqueValues(field_index)
# Count the number of unique values
un_values_length = len(un_values)
# Set the table to have as many rows as the number of unique values
# of the selected field
self.dlg.tableWidget.setRowCount(un_values_length)
# Make a new list that holds the unique values as strings
un_values_string_list = []
for i in range(un_values_length):
a = str(un_values[i])
un_values_string_list.append(a)
# Set the tables rows names to be the unique values
self.dlg.tableWidget.setVerticalHeaderLabels(un_values_string_list)

Related

How to use same django filter class(filters.py) in two different views

I have a filter class defined below.
filters.py
class CTAFilter(django_filters.FilterSet):
id = django_filters.NumberFilter(label="DSID")
class Meta:
model = CTA
fields = ['id', 'EmailID','id','Shift_timing']
Now I want to use this CTAFilter in normal template(table data)view and in download views.
I have observed that It is working fine for normal render view but when I am using it in my download views it is not working and I am getting all model data in the .xls file.
Please find the below questions which I have posted.
how to use Django filtered class data to 2 seperate view
I am not able to resolve this problem I have tried to check if I can define it globally so that the filter will work for all views(like RESTAPI).
Is there any way I can make my download view as a child view class of normal render view so that I will use the below code from the parent view(as it is working fine)?
cta_list = CTA.objects.all()
cta_filter = CTAFilter(request.GET, queryset=cta_list) allcta = cta_filter.qs
A>Normal View where the filter is working fine.
def retrievecta_view(request):
if request.method == 'GET':
allcta = CTA.objects.all()
allcta1 = allcta
allctagen = allcta1.filter(Shift_timing__exact='General')
allctamor = allcta1.filter(Shift_timing__exact='Morning')
allctseve = allcta1.filter(Shift_timing__exact='Evening')
allctatotal = allcta1.filter(Shift_timing__exact='Total')
# For filtering using 'django_filters',
cta_list = CTA.objects.all()
cta_filter = CTAFilter(request.GET, queryset=cta_list)
allcta = cta_filter.qs
paginator = Paginator(allcta, 50)
page_number = request.GET.get('page')
try:
allcts = paginator.page(page_number)
except PageNotAnInteger:
allcts = paginator.page(1)
except EmptyPage:
allcts = paginator.page(paginator.num_pages)
return render(request, 'abcd/cta.html', {'allcta': allcta, 'cta_filter': cta_filter, 'allcta1': allcta1,
'allctagen': allctagen, 'allctamor': allctamor,
'allctaeve': allctaeve,
'allctatotal': allctatotal})
b> Download view where I am trying to use the same filter but it is giving me all records.
def exportcts_data(request):
response = HttpResponse(content_type='application/ms-excel')
response['Content-Disposition'] = 'attachment; filename="CTA_ShiftTiming.xls"'
wb = xlwt.Workbook(encoding='utf-8')
ws = wb.add_sheet('CTS_ShiftChange Data') # this will make a sheet named Users Data
# Sheet header, first row
row_num = 0
font_style = xlwt.XFStyle()
font_style.font.bold = True
columns = ['id','idk','Shift_timing','EmailID','Vendor_Company','Project_name','SerialNumber','Reason','last_updated_time']
for col_num in range(len(columns)):
ws.write(row_num, col_num, columns[col_num], font_style) # at 0 row 0 column
# Sheet body, remaining rows
font_style = xlwt.XFStyle()
cts_list = CTA.objects.all()
cts_filter = CTAFilter(request.GET, queryset=cts_list)
allcts = cts_filter.qs
rows = allcts.values_list('id', 'idk', 'Shift_timing', 'EmailID', 'Vendor_Company', 'Project_name',
'SerialNumber', 'Reason', 'last_updated_time')
for row in rows:
row_num += 1
for col_num in range(len(row)):
ws.write(row_num, col_num, row[col_num], font_style)
wb.save(response)
return response
I'm not quite following why you want to have separate view for downloads which ultimately should be rendering the same data as the normal view if they are using the same filter. Maybe it is just my misunderstanding so I'm not sure if this will help you but let's see.
First off let me explain a little background. This is a task management application and in there I have an html page where the person logged in can view all of their completed tasks. (Nice and simple.) However the user may have tasks from many different projects so I have created a dropdown list that allows them to filter by a single project. They may also want to only see a specific period of tasks so I have allowed them to set a date range by providing a start and end date. (Nothing startling or earth shattering here.) Once the parameters are set, the user clicks a search button and the filtered results are displayed. The page also has an Export button which downloads the results of the filtered list to a .xls spreadsheet.
So how do I do this? Well first of all, I am using Django-Tables2 for rendering my tables. I simple predefine the table in tables.py and throw it the data I want from my views and it takes care of everything. Therefore my view code is minimal and very simple and looks like this.
from django_tables2.export.export import TableExport
from .tables import CompletedTable
def completedlist(request, page='0', name=''):
#Check to see if we have clicked a button inside the form
if request.method == 'POST':
return redirect ('tasks:tasklist')
else:
# Pre-filtering of user and Master = True etc is done in the MasterListFilter in filters.py
# Then we compile the list for Filtering by.
f = CompletedListFilter(request.GET, queryset=Task.objects.all(),request=request)
# Then we apply the complete list to the table, configure it and then render it.
completedtable = CompletedTable(f.qs)
rows = len(completedtable.rows)
if int(page) > 0:
RequestConfig(request, paginate={'page': page, 'per_page': 10}).configure(completedtable)
else:
RequestConfig(request, paginate={'page': 1, 'per_page': 10}).configure(completedtable)
export_format = request.GET.get('_export', None)
if TableExport.is_valid_format(export_format):
exporter = TableExport(export_format, completedtable)
return exporter.response('Completed Tasks.{}'.format(export_format))
return render (request,'tasks/completedlist.html',{'completedtable': completedtable, 'filter': f, 'rows': rows})
As you can see, every time the user hits either the search or export buttons, I am recompiling the queryset in variable f with the following line:
f = CompletedListFilter(request.GET, queryset=Task.objects.all(),request=request)
I have predefined the .xls format in the html page with this code:
<button class="btn btn-primary btn-xs" name="_export" value="xls" type="submit">Export</button>
So then I can test to see if the user clicked the Export button or not by getting the value of _export from the request like this:
export_format = request.GET.get('_export', None)
If the user did not click the export button, export_format will default to none. If they did, it will be .xls as defined in the html. Then I simply either export the data in line with the filters set by the user or I render the page with the same filtered list of data like this:
if TableExport.is_valid_format(export_format):
exporter = TableExport(export_format, completedtable)
return exporter.response('Completed Tasks.{}'.format(export_format))
return render (request,'tasks/completedlist.html',{'completedtable': completedtable, 'filter': f, 'rows': rows})
So there you have it. As you say your filter is working for the normal view I have not detailed my filter as that would seem to be unnecessary.
Maybe this solution is too simplistic for your requirements and yes, before I get shot down by other developers, there are several limitations, such as 'What if the user wants to use something other than .xls?' or 'What if they want to export more than one Project at a time?' Like everything, there is always room for improvement but when I'm bashing my head with an issue, I often find it helps to strip things back to basics and see what comes from that.

Python3 - Openpyxl - For loop to search through Column - Gather information Based on position of first cell location

UPDATE!
My goal is to modify an existing Workbook ( example - master_v2.xlsm ) and produce a new workbook (Newclient4) based on the updates made to master_v2.
I'm using a single sheet within master_v2 to collect all the data which will be determining what the new workbook will be.
Currently using multiple if statements to find the value of the cells in this "repository" sheet. Based on specific cells, I'm creating and adding values to copies of an existing sheet called "PANDAS".
My goal right now is to create a dict based on two columns. The loop through
the keys so that every time I get a hit on a cell, I will gather values from specific keys.
That's listed below:
from openpyxl import load_workbook
# Start by opening the spreadsheet and selecting the main sheet
workbook = load_workbook(filename="master_v2.xlsm",read_only=False, keep_vba=True)
DATASOURCE = workbook['repository']
DATASOURCE["A:H"]
cell100 = DATASOURCE["F6"].value
CREATION = cell100
cell101 = DATASOURCE["F135"].value
CREATION2 = cell101
cell107 = DATASOURCE["F780"].value
CREATION7 = cell107
if CREATION.isnumeric():
source = workbook['PANDAS']
target = workbook.copy_worksheet(source)
ss_sheet = target
ss_sheet.title = DATASOURCE['H4'].value[0:12]+' PANDAS'
if CREATION2.isnumeric():
source = workbook['PANDAS']
target = workbook.copy_worksheet(source)
ss_sheet = target
ss_sheet.title = DATASOURCE['H133'].value[0:12]+' PANDAS'
if CREATION3.isnumeric():
source = workbook['PANDAS']
target = workbook.copy_worksheet(source)
ss_sheet = target
ss_sheet.title = DATASOURCE['H262'].value[0:12]+' PANDAS'
else:
print ("no")
workbook.save(filename="NewClient4.xlsm")
Instead of the many if statements I was hoping to be able to loop through the column as explained above,
once I found my value, gather data and copy it over to a copy of sheet which is then filled out by other cells. Each time the loop comples, I want to do repeat on the next match of the string.. but I'm only this far and it's not quite working.
Anyone have a way to get this working?
( trying to replace the many one to one mappings and if statements )
for i in range(1,3000):
if DATASOURCE.cell(row=i,column=5).value == "Customer:":
source = workbook['Design details']
target = workbook.copy_worksheet(source)
ss_sheet = target
ss_sheet.title = DATASOURCE['H4'].value[0:12]+' Design details'
else:
print ("no")
Thank you guys in advanced

How do you iterate through a table and edit information with pptx in python?

How do you iterate through a table and find and replace text? I'm able to go through text boxes as below but need to be able to access and edit information in a table:
for slide in prs.slides:
for shape in slide.shapes:
if shape.has_text_frame:
j = 0
k = 0
for i in searchList:
#find the search term from the searchList
searchString = searchList[j]
j+=1
#replace the search term from the dataframe
dfIndexName = dfIndex.keys()[k]
k+=1
replaceString = df.at[0, dfIndexName]
if (shape.text.find(searchString))!=1:
text_frame = shape.text_frame
cur_text = text_frame.paragraphs[0].runs[0].text
new_text = cur_text.replace(searchString, str(replaceString))
text_frame.paragraphs[0].runs[0].text = new_text
Thanks!
I'm not sure what you want to do with searchList, but this is how you can access cells in a table.
for slide in prs.slides:
for shape in slide.shapes:
if shape.has_table:
table = shape.table
for cell in table.iter_cells():
# here you can access the text in cell by using
# cell.text
# just remember that the shape object refers to the table in this context not the cell

Data table in kivy

I have created application in kivy using kivymd , when I used its data_table code I couldn't select multi rows to delete them one time, I tried to create a list and append each selected_id in this list but it returns an empty list.
this is the function which returns a selected_id :
def select_row(self, checkbox, checked, **kwargs):
if not self.is_all_checked:
for index, cell in enumerate(self.children):
if isinstance(cell, ItemCheckbox) and checked:
if cell.id != checkbox.id:
self.selected_id = checkbox.id
cell.active = False
elif self.is_all_checked and not checked:
self.select_all(False)
if not checked:
self.selected_id = ""
All what I need is to make a list of rows with checkboxes that allow to be check many of them at once to let user delete it! Could you help me do this?

End edition signal of a QLineEdit in a QTableView

I've been facing a problem for several days now. I'm using a QTableView to display data from a model. I activated the complete line selection when the user click on a cell, to make the interface user friendly:
self.tableau.selectRow(element.row())
But, when the user presses F2, I would like to edit only the column 1. So, the expected behavior is:
if I selected the column 4, this one is not editable
if I press F2 when column 4 is selected, the column 1 is edited
But with the complete row selection, F2 can not know which cell is selected. So, I re-implemented the event handler:
def keyPressEvent(self, e):
"""It reimplements event management in this method """
# TODO: find a way to re-select the cell after editing
# We get the name of current file
nom_courant = self.tableau.model().index(self.row_selected, 1).data()
print(nom_courant)
if e.key() == QtCore.Qt.Key_F2:
try:
# We edit the cell name of the selected line
#http://stackoverflow.com/questions/8157688/specifying-an-index-in-qtableview-with-pyqt
self.tableau.edit(self.tableau.model().index(self.row_selected, 1))
except:
print("Pas de cell sélectionnée")
pass
# It retrieves the new file name. CAN NOT do in the
# if the model is not updated yet.
nouveau_nom = self.tableau.model().index(self.row_selected, 1).data()
print(nouveau_nom)
# Call the fct renaming only if the name has changed
if nom_courant != nouveau_nom:
#liste.renameFile(self.current_video, self.tableau.model().index(self.row_selected, 1).data())
print("entropie")
The matter now is this line:
self.tableau.edit(self.tableau.model().index(self.row_selected, 1))
I have no way to detect the end of the edition of the QLineEdit generated, and I need it to perform actions on the new content of the cell edited, because nouveau_nom is not updated if no keyboard event occurs.
Do you have an idea about how to get the end edition signal ?
(Please forgive my english, I'm french...)
First, you don't need to actually intercept and change the cell selection to a row selection. You can just set the behavior on the view:
self.tableau.setSelectionBehavior(self.tableau.SelectRows)
This will automatically select rows.
When you use a custom QLineEdit widgets in your table, then you need to connect QLineEdit.editingFinished() to whatever handler you want. Most likely you want it to call dataChanged on your model.

Resources