I have a working form which exports all data to xls using Resource and Fields from the django-import-export package. But now I need to go a bit further and make it a bit more advanced. I need to export all data to an existing Excel template, assigning each field to a specific column, as in, for instance: Field 1 needs to be filled in B3, Field 2 in C4 etc. etc.
I'm thinking after_export() can be used here but the docs dont go into detail how to use this method. Does anyone have some experience with this package?
I'm not using the admin integration.
after_export() is a method you can override to modify data before it is returned.
It does nothing by default. However, it supplies the data object, which is a Dataset instance. If you access the dict property, then you will have a list of OrderedDict instances corresponding to each row which is returned by your queryset. Therefore, you can construct an entirely new Dataset (list of dicts) which match up with the format you need.
For example, if you wanted the first column of the first row to appear in cell B3, you could do it like this:
def after_export(self, queryset, data, *args, **kwargs):
newdata = tablib.Dataset()
cell1_val = data.dict[0].get("col1", "")
for i, row in enumerate(data):
if i == 1:
newrow = list(row)
# cell b3
newrow[2] = cell1_val
row = newrow
newdata.append(row)
data.dict = newdata.dict
However, you'll note that this approach is not easy to read and is quite unwieldy. Therefore if you don't need any other features of django-import-export then using a library like openpyxl is probably a better approach.
Related
I have switched from connection.execute to session.execute. I am not able to get usable data from it. The results seem to contain references to models instead of actual row data.
with Session(engine) as s:
q = select(WarrantyRequest)
res = s.execute(q)
keys = res.keys()
data_list = res.all()
print(keys) # should print list of column names
print(data_list) # should print list of lists with row data
dict_list = s.execute(q).mappings().all()
print(dict_list) # should print list of dicts with column names as keys
It prints
RMKeyView(['WarrantyRequest'])
[(<models.mock.WarrantyRequest object at 0x7f4d065d3df0>,), ...]
[{'WarrantyRequest': <models.mock.WarrantyRequest object at 0x7f002b464df0>}, ... ]
When doing the same with connection.execute, I got the expected results.
What am I missing?
There is this paragraph in the docs which kind of describes the behaviour, but I am not able to tell what I am supposed to do to get data out of it.
It’s important to note that while methods of Query such as Query.all() and Query.one() will return instances of ORM mapped objects directly in the case that only a single complete entity were requested, the Result object returned by Session.execute() will always deliver rows (named tuples) by default; this is so that results against single or multiple ORM objects, columns, tables, etc. may all be handled identically.
If only one ORM entity was queried, the rows returned will have exactly one column, consisting of the ORM-mapped object instance for each row. To convert these rows into object instances without the tuples, the Result.scalars() method is used to first apply a “scalars” filter to the result; then the Result can be iterated or deliver rows via standard methods such as Result.all(), Result.first(), etc.
Querying a model
q = select(WarrantyRequest)
returns rows that consist of individual model instances. To get rows of raw data instead, query the model's __table__ attribute:
q = select(WarrantyRequest.__table__)
SQLAlchemy's ORM layer presents database tables and rows in an object-oriented way, on the assumption that the programmer wants to work with objects and their attributes rather than raw data.
The task I have at hand is to parse a large text (several 100K rows) file and accumulate some statistics based which will be then visualized in plots. Each row contains results of some prior analysis.
I wrote a custom class to define the objects that are to be accumulated. The class contains 2 string fields, 3 sets and 2 integer counters. As such there is an __init__(self, name) which initializes a new object with name and empty fields, and a method called addRow() which adds information into the object. The sets accumulate data to be associated with this object and the counters keep track of a couple of conditions.
My original idea was to iterate over the rows of the file and call a method like parseRow() in main
reader = csv.reader(f)
acc = {} # or set()
for row in reader:
parseRow(row,acc)
which would look something like:
parseRow(row, acc):
if row[id] is not in acc: # row[id] is the column where the object names/ids are
a = MyObj(row[id])
else:
a = acc.get(row[id]) # or equivalent
a.addRow(...)
The issue here is that the accumulating collection acc cannot be a set since sets are apparently not indexable in Python. Edit: for clarification, by indexable I didn't mean getting the nth element but rather being able to retrieve a specific element.
One workaround would be to have a dict that has {obj_name : obj} mapping but it feels like an ugly solution. Considering the elegance of the language otherwise, I guess there is a better solution to this. It's surely not a particularly rare situation...
Any suggestions?
You could also try an ordered-set. Which is a set AND ordered.
I have a model where each object is conceptually a cell of a table - two ForeignKeys, F and G determine its position on the table (i.e., each tuple (f,g) is linked to one cell). That is, something like that:
class Cell(models.Model):
f = models.ForeignKey(F)
g = models.ForeignKey(G)
value = models.IntegerField()
When I create an admin page for that model using:
admin.site.register(Cell)
I get a page where each cell must be entered by linking to a foo, a bar and setting its val individually. For huge cells, that becomes cumbersome. It would be much more convenient to edit that information like so:
Where F_ and G_ are objects of the F and G models, respectively.
Is it possible to get this interface on Django?
Take a look at django-tables2. I haven't used it but read the docs whilst looking for other functionality and I think it might help you.
Also remembered this video which explains how you can make django work like a spreadsheet which may also be usful to you.
https://www.youtube.com/watch?v=jORuhbJq79M
I want to read data from one file, load it to two Orange.data.Tables and change column names in one of these tables. Here's the code:
import Orange
data = Orange.data.Table("sample_data.tab")
data2 = Orange.data.Table(data)
data2.domain = Orange.data.Domain(data.domain)
for inst in data2.domain:
data2.domain[inst].name = '__' + data2.domain[inst].name
but, for some reason, column names change in both tables. How to change column names in only one of the tables?
Orange reuses column descriptors. This is needed so that if you load data from two files and use one for fitting a model, you can use the other file to testing it. Generally, if the column has the same name and type, it will also have the same descriptor.
You can avoid this by adding createNewOn=0 when loading the data.
d1 = Orange.data.Table("iris")
d2 = Orange.data.Table("iris", createNewOn=0)
The whole story is described here: http://docs.orange.biolab.si/reference/rst/Orange.data.table.html and here: http://docs.orange.biolab.si/reference/rst/Orange.feature.descriptor.html#variable-descriptor-reuse.
There is an error in documentation: create_new_on should be createNewOn. (My example above is correct.)
If the data is already loaded, like in your case, changing the descriptors for one table without losing the data is more complicated. If you really need it, I can show you how, but I guess you don't. If you do so, you'd get two completely unrelated tables.
I don't understand how the gtk.Treeview() list model works:
From what I understand I have to wrap the lismodel in a gtk.TreeModelSort() but when I do that, I can't access the listmodel methods anymore..
lm = gtk.ListStore(object)
listmodel = gtk.TreeModelSort(lm)
for f in files:
listmodel.append([f])
return listmodel
AttributeError: 'gtk.TreeModelSort' object has no attribute 'append'
I'm working with this example (source): how would one make the table sortable on every column?
The gtk.TreeModelSort is just a model (interface for access), it does not actually store anything. In fact, you don't need to invoke it yourself to make your table sortable. The simplest way is to let GTK do the sorting for you, which means that you have to store C data and not Python objects in your table. So, change your make_list() method to
listmodel = gtk.ListStore(str)
instead of object. Then you just have to tell the gtk.TreeView that clicking on the first column header should sort according to the first column in the gtk.ListStore by putting
self.tvcolumn[0].set_sort_column_id(0)
into your constructor. To sort by file size you'd add an extra colum consisting of int in the list store and use that as sort column id etc.
Edit: Ok let me spell the last thing out:
listmodel = gtk.ListStore(str, int)
for f in files:
file_size = os.stat(os.path.join(self.dirname, f)).st_size
listmodel.append([f, file_size])
puts the file size in the second column of the store. Then, to sort by file size you can just add
self.tvcolumn[1].set_sort_column_id(1)
In general, I would recommend to restructure your code that everything is stored in the ListStore once at the beginning. That way, you can code the cell rendering much easier by just tying each view column to a store column.