Pytigon's model layer extends Django's ORM with a powerful JSON-backed base class and a rich set of hook methods. The JSONModel class is the foundation upon which all Pytigon applications build their data structures.
Every Pytigon model inherits from JSONModel, which adds a jsondata JSON field and a suite of behavior methods:
from django.db import models
from pytigon_lib.schdjangoext.models import JSONModel
class MyTable(JSONModel):
name = models.CharField(max_length=128)
jsondata = models.JSONField(null=True, blank=True, editable=False)
The jsondata field stores flexible, schema-less data that can evolve without database migrations. It also serves as the storage backend for Pytigon's dynamic form system.
These methods, when defined on your model, plug into Pytigon's view and form processing pipeline:
get_form_source(self) → strReturn a FastForm string definition. Pytigon uses this to dynamically generate the edit form for this record type.
set_field_value(self, field_name, attr_name, value) → FieldOverride attributes of a parent model's field at runtime:
field = self.set_field_value("item", "blank", False)
field.verbose_name = _("New description")
save_from_request(self, request, view_type, param)Called instead of model.save() when a form is submitted. Gives you access to the request object for context-dependent saving logic.
get_derived_object(self, param) → ModelReplace the current object with a derived (subclass) instance. Enables polymorphic behavior where a base table row can represent different specialized types.
table_action(cls, list_view, request, data)Handle custom actions triggered from the table view — select rows and perform batch operations.
row_action(model, request, args, kwargs)Handle actions on individual rows.
filter(cls, value) → QuerySetCustom filtering for dynamic relationships (used with row_related_list).
filter_by_permissions(queryset_or_obj, request) → QuerySetRow-level security — restrict which records a user can see.
sort(queryset, sort_field, order) → QuerySetCustom sort logic beyond simple field ordering.
redirect_href(self, view, request) → str | NoneRedirect to a different URL after viewing this record. Useful for polymorphic navigation.
get_form_class(self, view, request, create) → Form classGenerate a custom Django Form class dynamically based on the record's state.
is_form_valid(form) → boolStatic method for custom form validation logic.
post_form(self, view, form, request) → boolHook called after form validation but before save. Return False to prevent the save.
template_for_object(self, view, context, doc_type) → str | NoneCustomize which template renders this specific record.
template_for_list(view, model, context, doc_type) → str | NoneCustomize which template renders the list view for this model.
Pytigon supports table relationships beyond standard Django ForeignKeys:
filter + init_new PatternDefine a filter class method and init_new instance method on the related table to create dynamic, non-SQL relationships:
@classmethod
def filter(cls, value):
app, tbl, parent_id, grp = value.split('__')
return cls.objects.filter(
application=app, table=tbl, parent_id=parent_id, group=grp
)
def init_new(self, request, view, value=None):
return {'application': app, 'table': tbl, 'parent_id': parent_id, 'group': grp}
These are connected in templates via:
Pytigon models automatically get:
- Timestamp fields (created, modified) via the base class
- JSON serialization for API responses
- Integration with Pytigon's generic views
- Permission checking hooks
- Search support for list views