iommirocks / iommi

Your first pick for a django power cord
http://iommi.rocks
BSD 3-Clause "New" or "Revised" License
658 stars 45 forks source link

is there a way to add dynamic columns to a table? #542

Closed ivkus closed 2 weeks ago

ivkus commented 2 weeks ago

I want generate some colume dynamic, and the code I wrote as follows.

def dynamic_columns(row, **_):
    return {
        "square" : Column(
            cell__value=3,
        )
    }

class ProductPage(BasePage):
    product_table = Table(
        auto__model=models.Product,
        page_size=10,
        columns__name__cell__url=lambda row, **_: row.get_absolute_url(),
        columns__name__filter__include=True,
        columns__code__filter__include=True,
        columns__select__include=True,
        bulk__actions__delete__include=True,
    )
    class Meta:
        title = "Products"
        parts__product_table__columns=dynamic_columns,

Iommi rais some errors:

Traceback (most recent call last):
  File "/home/bbbla/code/python/.venv/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
  File "/home/bbbla/code/python/.venv/lib/python3.10/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/bbbla/code/python/.venv/lib/python3.10/site-packages/iommi/base.py", line 47, in view_wrapper
    view_wrapper.__iommi_target__ = view_wrapper.__iommi_target__.refine_done()
  File "/home/bbbla/code/python/.venv/lib/python3.10/site-packages/iommi/refinable.py", line 263, in refine_done
    result.on_refine_done()
  File "/home/bbbla/code/python/.venv/lib/python3.10/site-packages/iommi/page.py", line 97, in on_refine_done
    refine_done_members(
  File "/home/bbbla/code/python/.venv/lib/python3.10/site-packages/iommi/member.py", line 155, in refine_done_members
    member_by_name[key] = item.refine_done(parent=container)
  File "/home/bbbla/code/python/.venv/lib/python3.10/site-packages/iommi/refinable.py", line 263, in refine_done
    result.on_refine_done()
  File "/home/bbbla/code/python/.venv/lib/python3.10/site-packages/iommi/table.py", line 1883, in on_refine_done
    refine_done_members(
  File "/home/bbbla/code/python/.venv/lib/python3.10/site-packages/iommi/member.py", line 79, in refine_done_members
    set(keys(members_from_declared or {})) | set(keys(members_from_namespace or {}))
  File "/home/bbbla/code/python/.venv/lib/python3.10/site-packages/iommi/base.py", line 76, in keys
    return type(container).keys(container)
AttributeError: type object 'tuple' has no attribute 'keys'

Does iommi support this kind of usage?

boxed commented 2 weeks ago
parts__product_table__columns=dynamic_columns,

you have a comma at the end

boxed commented 2 weeks ago

Hmm. on second thought, that was just the first problem.

Is the set of columns truly dynamic? Or do you just want to show/hide some columns based on logic?

ivkus commented 2 weeks ago

sorry, the trace as below after fix comma problem

Traceback (most recent call last):
  File "/home/bbbla/code/python/.venv/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
  File "/home/bbbla/code/python/.venv/lib/python3.10/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/bbbla/code/python/.venv/lib/python3.10/site-packages/iommi/base.py", line 47, in view_wrapper
    view_wrapper.__iommi_target__ = view_wrapper.__iommi_target__.refine_done()
  File "/home/bbbla/code/python/.venv/lib/python3.10/site-packages/iommi/refinable.py", line 263, in refine_done
    result.on_refine_done()
  File "/home/bbbla/code/python/.venv/lib/python3.10/site-packages/iommi/page.py", line 97, in on_refine_done
    refine_done_members(
  File "/home/bbbla/code/python/.venv/lib/python3.10/site-packages/iommi/member.py", line 155, in refine_done_members
    member_by_name[key] = item.refine_done(parent=container)
  File "/home/bbbla/code/python/.venv/lib/python3.10/site-packages/iommi/refinable.py", line 263, in refine_done
    result.on_refine_done()
  File "/home/bbbla/code/python/.venv/lib/python3.10/site-packages/iommi/table.py", line 1883, in on_refine_done
    refine_done_members(
  File "/home/bbbla/code/python/.venv/lib/python3.10/site-packages/iommi/member.py", line 123, in refine_done_members
    assert (
AssertionError: I got <class 'function'> when creating a Column.call_target, but I was expecting Traversable or dict
ivkus commented 2 weeks ago
I'm writing a rental management app. The columns in the front is some basic info about a product. The following columns I want put the avaliable for rent by date. For example ID Name 20240703 20240704 20240705 20240706
1 Book One 10 3 6 3

So the date's are generated dynamic

boxed commented 2 weeks ago

I think this situation calls for creating the entire Table at runtime.

ivkus commented 2 weeks ago

thank you for your suggestion. I write the following code, and it works!

MyTable = type('MyTable', (Table,), { f'column_{i}' : Column(cell__value=f'value@{i}') for i in range(10)})
boxed commented 2 weeks ago

Ah, it's even better than that. You can do:

my_table = Table(**{ f'column_{i}' : Column(cell__value=f'value@{i}') for i in range(10)})

In iommi all the classes are made to be used both in a class based style AND programmatically. This is documented here: https://docs.iommi.rocks/en/latest/equivalency.html

I often don't make new classes when defining views, instead I can just do path('', Table(auto__model=Foo).as_view()) for example.

ivkus commented 2 weeks ago

Ah, it's even better than that. You can do:

my_table = Table(**{ f'column_{i}' : Column(cell__value=f'value@{i}') for i in range(10)})

In iommi all the classes are made to be used both in a class based style AND programmatically. This is documented here: https://docs.iommi.rocks/en/latest/equivalency.html

I often don't make new classes when defining views, instead I can just do path('', Table(auto__model=Foo).as_view()) for example.

it should be my_table = Table(**{ f'columns__column_{i}' : Column(cell__value=f'value@{i}') for i in range(10)}) the prefix columns__ is mandatory.

boxed commented 2 weeks ago

Ah, my bad.