ferrosoft.apps.ferrobase.tables package

Submodules

ferrosoft.apps.ferrobase.tables.columns module

Reusable django-tables2 column classes for Ferrosoft tables.

The columns add rendering for domain-specific values (currency, units, dates, arrays, inline-edit widgets) as well as layout helpers (fixed-width classes, summing footers, action links) on top of django-tables2’s base Column.

class ferrosoft.apps.ferrobase.tables.columns.ActionColumn(href=None, label=None, attributes=None, font_icon=None, *args, **kwargs)[source]

Bases: Column

Display a action in the column, in the form of a link. The link can have arbitrary attributes, allowing for HTMX interactivity.

render(*args, **kwargs)[source]

Pipe value through each mixin’s render and return the result.

class ferrosoft.apps.ferrobase.tables.columns.ArrayColumn(fixed_width=None, mixins=None, *args, **kwargs)[source]

Bases: Column

Render array values (of PostgreSQL array columns)

render(value, *args, **kwargs)[source]

Join array elements with a comma and space.

class ferrosoft.apps.ferrobase.tables.columns.Column(fixed_width=None, mixins=None, *args, **kwargs)[source]

Bases: Column

Base column adding fixed-width sizing and stackable render mixins.

All Ferrosoft columns inherit from this class so they share the same fixed_width (CSS cw-{n} class) shortcut and mixin pipeline.

render(value, *args, **kwargs)[source]

Pipe value through each mixin’s render and return the result.

Pipe footer rendering through each mixin’s render_footer.

class ferrosoft.apps.ferrobase.tables.columns.DateTimeColumn(format_string=None, *args, **kwargs)[source]

Bases: Column

Render a datetime in the requesting user’s timezone.

render(value, *args, **kwargs)[source]

Format value in the user’s timezone.

Requires the table instance (with attached request) to be passed via kwargs['table'] so the user’s preferred timezone can be resolved on the first call and cached on the column.

class ferrosoft.apps.ferrobase.tables.columns.DefaultValue(default_value, *args, **kwargs)[source]

Bases: Column

Column that substitutes a configured default when the value is None.

render(value, *args, **kwargs)[source]

Return value or default_value when value is None.

class ferrosoft.apps.ferrobase.tables.columns.EmptyExpandColumn(*args, **kwargs)[source]

Bases: Column

Empty placeholder column that stretches to fill remaining width.

render(value, *args, **kwargs)[source]

Always render as an empty string.

class ferrosoft.apps.ferrobase.tables.columns.InlineEditColumn(input_name='', input_attrs=None, number_display=False, quantize=None, options=None, form_name=None, read_only=False, *args, **kwargs)[source]

Bases: Column

Column rendering a read-only value alongside an editable input/select.

The template emits both a view-mode anchor and a form control so the cell can switch between display and edit modes client-side.

classmethod input_name_with_pk(base_name)[source]

Create input names with record’s pk as subscript.

Example: If base_name is foo and a record’s pk is 1234, the resulting input name is foo[1234].

Parameters:

base_name (str) – the part of input name before subscript

Returns: lambda that’s suitable for input_name attribute.

render(record, value, **kwargs)[source]

Pipe value through each mixin’s render and return the result.

static step_attr(step='0.001')[source]

Return an input_attrs dict setting the HTML step attribute.

class ferrosoft.apps.ferrobase.tables.columns.MonthColumn(fixed_width=None, mixins=None, *args, **kwargs)[source]

Bases: Column

Render a 1-12 month number as its localised month name.

render(value, *args, **kwargs)[source]

Map value to a localised name, falling back to the raw value.

class ferrosoft.apps.ferrobase.tables.columns.NewlineToHTMLBreak(fixed_width=None, mixins=None, *args, **kwargs)[source]

Bases: Column

Mixin column converting embedded newlines to <br> while HTML-escaping.

render(rendered_value, *args, **kwargs)[source]

Escape rendered_value then replace \n with <br>.

class ferrosoft.apps.ferrobase.tables.columns.NumberColumn(with_symbol=False, quantize=None, transform=None, transform_value=None, *args, **kwargs)[source]

Bases: Column

Right-aligned number column with optional unit symbol and transforms.

render(value, **kwargs)[source]

Pipe value through each mixin’s render and return the result.

class ferrosoft.apps.ferrobase.tables.columns.SummingColumn(*args, **kwargs)[source]

Bases: Column

Column that aggregates all visible rows and shows the sum in the footer.

Sum the column across every row in table.data and format it.

class ferrosoft.apps.ferrobase.tables.columns.WidgetColumn(widget, name=None, widget_attrs=None, *args, **kwargs)[source]

Bases: Column

Render any django.forms Widget in a column.

render(*args, **kwargs)[source]

Pipe value through each mixin’s render and return the result.

ferrosoft.apps.ferrobase.tables.crud module

class ferrosoft.apps.ferrobase.tables.crud.Action(url, label)[source]

Bases: object

Extra header action exposed in the table template (label + URL).

label: str
url: str
class ferrosoft.apps.ferrobase.tables.crud.CRUDTable(*args, **kwargs)[source]

Bases: Table

Table preconfigured with create/update/delete affordances.

Renders the “with add button” Bootstrap 5 template and an actions column containing per-row edit/delete buttons. The button URLs are resolved through get_update_action_url() and get_delete_action_url(), both of which subclasses are expected to override when they need custom routes. Passing disable_update=True on construction hides the actions column and the add button — useful for read-only views.

Template context exposes actions, create_label, create_url and disable_update in addition to the base table context.

class Meta[source]

Bases: object

create_label = 'Add'
create_url = None
template_name = 'ferrobase/bootstrap5/table/with_add_button.html'
base_columns = {'actions': <ferrosoft.apps.ferrobase.tables.columns.WidgetColumn object>}
before_render(request)[source]

Hide the actions column when constructed with disable_update.

get_delete_action_url(*args, **kwargs)[source]

Return the delete URL for kwargs['record'] or None (default).

Return type:

str | None

get_update_action_url(*args, **kwargs)[source]

Return the row’s get_absolute_url() if the model defines one.

Return type:

str | None

template_context(request)[source]

Augment base template context with CRUD-specific keys.

ferrosoft.apps.ferrobase.tables.models module

class ferrosoft.apps.ferrobase.tables.models.APITokenTable(data=None, order_by=None, orderable=None, empty_text=None, exclude=None, attrs=None, row_attrs=None, pinned_row_attrs=None, sequence=None, prefix=None, order_by_field=None, page_field=None, per_page_field=None, template_name=None, default=None, request=None, show_header=None, show_footer=True, extra_columns=None)[source]

Bases: Table

Read-only listing of APIToken records (name, tenant, status, expiry).

class Meta[source]

Bases: object

fields = ['name', 'tenant', 'status', 'expiration']
model

alias of APIToken

base_columns = {'expiration': <django_tables2.columns.datetimecolumn.DateTimeColumn object>, 'name': <django_tables2.columns.base.Column object>, 'status': <django_tables2.columns.base.Column object>, 'tenant': <django_tables2.columns.base.Column object>}
class ferrosoft.apps.ferrobase.tables.models.FeatureAssignmentTable(*args, **kwargs)[source]

Bases: CRUDTable

CRUD table for FeatureAssignment; renders 0 limits as an em-dash.

class Meta[source]

Bases: Meta

fields = ['actions', 'feature', 'limit']
model

alias of FeatureAssignment

base_columns = {'actions': <ferrosoft.apps.ferrobase.tables.columns.WidgetColumn object>, 'empty': <ferrosoft.apps.ferrobase.tables.columns.EmptyExpandColumn object>, 'feature': <django_tables2.columns.base.Column object>, 'limit': <ferrosoft.apps.ferrobase.tables.columns.NumberColumn object>}
get_delete_action_url(*args, **kwargs)[source]

Resolve the delete URL via the featureassignment_delete route.

Return type:

str | None

class ferrosoft.apps.ferrobase.tables.models.IDSequenceTable(data=None, order_by=None, orderable=None, empty_text=None, exclude=None, attrs=None, row_attrs=None, pinned_row_attrs=None, sequence=None, prefix=None, order_by_field=None, page_field=None, per_page_field=None, template_name=None, default=None, request=None, show_header=None, show_footer=True, extra_columns=None)[source]

Bases: Table

Listing of ID-sequence configurations linkified on the name column.

class Meta[source]

Bases: object

fields = ['name', 'prefix', 'padding_amount']
model

alias of IdSequenceConfig

base_columns = {'name': <ferrosoft.apps.ferrobase.tables.columns.Column object>, 'padding_amount': <django_tables2.columns.base.Column object>, 'prefix': <django_tables2.columns.base.Column object>}
class ferrosoft.apps.ferrobase.tables.models.OrganizationTable(data=None, order_by=None, orderable=None, empty_text=None, exclude=None, attrs=None, row_attrs=None, pinned_row_attrs=None, sequence=None, prefix=None, order_by_field=None, page_field=None, per_page_field=None, template_name=None, default=None, request=None, show_header=None, show_footer=True, extra_columns=None)[source]

Bases: Table

Listing of Organization records linkified on the name column.

class Meta[source]

Bases: object

fields = ['name', 'contact_email', 'contact_first_name', 'contact_last_name']
model

alias of Organization

base_columns = {'contact_email': <django_tables2.columns.emailcolumn.EmailColumn object>, 'contact_first_name': <django_tables2.columns.base.Column object>, 'contact_last_name': <django_tables2.columns.base.Column object>, 'name': <ferrosoft.apps.ferrobase.tables.columns.Column object>}
class ferrosoft.apps.ferrobase.tables.models.StoredFileTable(data=None, order_by=None, orderable=None, empty_text=None, exclude=None, attrs=None, row_attrs=None, pinned_row_attrs=None, sequence=None, prefix=None, order_by_field=None, page_field=None, per_page_field=None, template_name=None, default=None, request=None, show_header=None, show_footer=True, extra_columns=None)[source]

Bases: Table

Listing of stored files linking each name to its update view.

class Meta[source]

Bases: object

fields = ['name', 'owner', 'media_type', 'creation_time', 'expire_on']
model

alias of StoredFile

base_columns = {'creation_time': <django_tables2.columns.datetimecolumn.DateTimeColumn object>, 'expire_on': <django_tables2.columns.datetimecolumn.DateTimeColumn object>, 'media_type': <django_tables2.columns.base.Column object>, 'name': <ferrosoft.apps.ferrobase.tables.columns.Column object>, 'owner': <django_tables2.columns.base.Column object>}
class ferrosoft.apps.ferrobase.tables.models.SubscriptionPlanTable(data=None, order_by=None, orderable=None, empty_text=None, exclude=None, attrs=None, row_attrs=None, pinned_row_attrs=None, sequence=None, prefix=None, order_by_field=None, page_field=None, per_page_field=None, template_name=None, default=None, request=None, show_header=None, show_footer=True, extra_columns=None)[source]

Bases: Table

Listing of subscription plans linkified on the name column.

class Meta[source]

Bases: object

fields = ['name', 'max_tonnage', 'enable_all_features']
model

alias of SubscriptionPlan

base_columns = {'enable_all_features': <django_tables2.columns.booleancolumn.BooleanColumn object>, 'max_tonnage': <django_tables2.columns.base.Column object>, 'name': <ferrosoft.apps.ferrobase.tables.columns.Column object>}
class ferrosoft.apps.ferrobase.tables.models.TenantTable(*args, **kwargs)[source]

Bases: CRUDTable

CRUD table for tenants nested under an organisation.

class Meta[source]

Bases: Meta

fields = ['actions', 'name', 'active', 'expiry_date']
model

alias of Tenant

base_columns = {'actions': <ferrosoft.apps.ferrobase.tables.columns.WidgetColumn object>, 'active': <django_tables2.columns.booleancolumn.BooleanColumn object>, 'empty': <ferrosoft.apps.ferrobase.tables.columns.EmptyExpandColumn object>, 'expiry_date': <django_tables2.columns.datetimecolumn.DateTimeColumn object>, 'name': <django_tables2.columns.base.Column object>}
get_delete_action_url(*args, **kwargs)[source]

Resolve the delete URL via the tenant_delete route.

Return type:

str | None

class ferrosoft.apps.ferrobase.tables.models.UserTable(data=None, order_by=None, orderable=None, empty_text=None, exclude=None, attrs=None, row_attrs=None, pinned_row_attrs=None, sequence=None, prefix=None, order_by_field=None, page_field=None, per_page_field=None, template_name=None, default=None, request=None, show_header=None, show_footer=True, extra_columns=None)[source]

Bases: Table

Listing of users linkified on the username column.

class Meta[source]

Bases: object

fields = ['username', 'is_active', 'first_name', 'last_name', 'email', 'organization', 'date_joined']
model

alias of User

base_columns = {'date_joined': <django_tables2.columns.datetimecolumn.DateTimeColumn object>, 'email': <django_tables2.columns.emailcolumn.EmailColumn object>, 'first_name': <django_tables2.columns.base.Column object>, 'is_active': <django_tables2.columns.booleancolumn.BooleanColumn object>, 'last_name': <django_tables2.columns.base.Column object>, 'organization': <django_tables2.columns.base.Column object>, 'username': <ferrosoft.apps.ferrobase.tables.columns.Column object>}

ferrosoft.apps.ferrobase.tables.table module

class ferrosoft.apps.ferrobase.tables.table.Table(data=None, order_by=None, orderable=None, empty_text=None, exclude=None, attrs=None, row_attrs=None, pinned_row_attrs=None, sequence=None, prefix=None, order_by_field=None, page_field=None, per_page_field=None, template_name=None, default=None, request=None, show_header=None, show_footer=True, extra_columns=None)[source]

Bases: Table

Base table class that adapts to the responsive UI and permission state.

On render the table strips its fixed-layout CSS class in portrait/UI mode and removes the first visible column’s link when the current user lacks UPDATE permission on the model.

base_columns = {}
before_render(request)[source]

Apply responsive layout tweaks and permission-driven unlinkification.

Parameters:

request – The current HTTP request. None skips the responsive check; permission resolution still runs against the global permission registry.