Files
home-information/docs/dev/backend/attribute-editing-integration-guide.md
Tony C aacb0b5bbf Configuration Settings Redesign with Attribute Framework Integration (#142)
* Implement Configuration Settings redesign with sticky header + tabs

- Add allow_reordering parameter to AttributeForm to control reorder controls
- Create ConfigEditFormHandler for unified multi-formset handling
- Create ConfigEditResponseRenderer for page-based response generation
- Add system_settings_redesigned.html template with sticky header + tabbed interface
- Update ConfigSettingsView to use helper classes following Entity/Location patterns
- Disable attribute reordering for system-defined config attributes
- Maintain existing URL structure and form submission behavior

* Fix AttributeEditContext integration with SubsystemAttributeEditData

- Create SubsystemAttributeEditContext for proper template context
- Add SubsystemAttributeEditData dataclass to cleanly pair formsets with contexts
- Update form handler and response renderer to use dataclass approach
- Simplify template logic by preparing data structure on server side
- Remove complex template logic in favor of clean dataclass properties

Fixes AttributeError: 'str' object has no attribute 'history_url_name'

* Add missing URL patterns for AttributeEditContext integration

- Add subsystem_attribute_history_inline and subsystem_attribute_restore_inline URL patterns
- Create SubsystemAttributeHistoryInlineView and SubsystemAttributeRestoreInlineView
- Follow Entity/Location pattern for inline history and restore functionality
- Resolves NoReverseMatch error for subsystem_attribute_history_inline URL

Fixes django.urls.exceptions.NoReverseMatch for inline attribute history URLs

* Tweaks for getting backend structure in place. WIP

* Config attrribute config mostly working, but still WIP.

* Good checkpoint on config attribute editing. Works, but WIP.

* Moved config settings to vertical tabs for subsystems.

* Added selected settings tab restoration url strategy.

* Added setting page error count badges to tabs.

* Tweaks to config page entry point and labeling.

* Added auto-dismiss settings update success message.

* Major refactor of attr-v2-modal.js to remove global namespacing.

* Fixed attr-v2 async initialization issue.

* CONverting magic stricts to constants.

* Refactor attribute javascript files to be better organized.

* Fixed ENTER key submit suppression for attributes. Dead code removal.

* Cleaned up all shared temp,ate id, class and selectors.

* Refactor: Attribute editing javascript message posting.

* Removed legacy config attribute history modal views.

* Refactor for better attributeb editing response code organization.

* Interim Refactor: Simple general attribute view working. WIP

* Refactor to introduce attribute page vs. item editing contexts.

* Have Entity and Location converted to refactored attribute editing.

* Checkpoint on converting Subsystem to new attribute editing. WIP

* Completed major attribute editing refactoring.

* Working on unit tests for new attribute refactor. WIP

* Fixed some unit tests. Tests are WIP though.

* Miscellaneous cleanup tasks.

* Fixed unit tests, linting and upload file deletion bug.
2025-09-05 15:26:24 +00:00

4.8 KiB

Attribute Editing Integration Guide

A comprehensive guide for integrating new models with the generic attribute editing system using the AttributeEditContext pattern.

Overview

The AttributeEditContext pattern provides a standardized way to implement attribute editing across different model types (Entity, Location, etc.) while maintaining ~95% code reuse through generic templates and handlers.

Benefits

  • Code Reuse: Share 95% of template and handler logic across model types
  • Consistency: Standardized UI/UX across all attribute editing interfaces
  • Type Safety: Clean abstraction with type-safe owner-specific access
  • Maintainability: Single source of truth for attribute editing functionality
  • Extensibility: Easy to add new model types following established patterns

When to Use

Use this pattern when you have:

  • A model that owns attributes (like Entity owns EntityAttribute)
  • Need for modal-based attribute editing with file upload support
  • Requirements for attribute history and restore functionality
  • Desire for consistent editing UI across different model types

Prerequisites

Required Model Structure

Your implementation needs:

  1. Owner Model: The main model (e.g., Entity, Location)

    class YourModel(models.Model):
        name = models.CharField(max_length=255)
        # other fields...
    
  2. Attribute Model: Related attribute model (e.g., EntityAttribute, LocationAttribute)

    class YourModelAttribute(models.Model):
        your_model = models.ForeignKey(YourModel, related_name='attributes')
        name = models.CharField(max_length=255)
        value = models.TextField()
        value_type_str = models.CharField(max_length=50)
        # history tracking fields...
    
  3. Template Directory Structure:

    hi/apps/yourapp/templates/yourapp/
    ├── modals/
    │   └── yourmodel_edit.html
    └── panes/
        └── yourmodel_edit_content_body.html
    

Step-by-Step Implementation

Step 1: Create AttributeItemEditContext Subclass

Create yourapp/yourmodel_attribute_edit_context.py:

See the following existing integrations:

# Single instance/formset
src/hi/apps/entity/entity_attribute_edit_context.py
src/hi/apps/location/location_attribute_edit_context.py

# Multipla instance/formset
src/hi/apps/config/subsystem_attribute_edit_context.py

Step 2: Create the needed views.

  • Pick whether you need a single or multiple instance implementation
  • Single instance view will include the mixin AttributeEditViewMixin
  • Multiple instance views will include the mixin AttributeMultiEditViewMixin
  • Your views get() method can render any sort of page or modal.
  • The get() method must get its template comntext from the mixin
  • The page or modal template must include a "content body" template (see below)
  • The post always goes though a mixin method and returns custom JSON for front-end (attr.js)

The full set of views include:

  • Main editing entry
  • File upload handling (optional)
  • Attribute History
  • Atribute Value restore

Step 3: Create Content Body Template

  • Create yourapp/templates/yourapp/panes/yourmodel_edit_content_body.html:
  • This template must extend attribute/components/edit_content_body.html
  • Override content blocks as needed.

Example:

src/hi/apps/config/templates/config/panes/subsystem_edit_content_body.html
src/hi/apps/entity/templates/entity/panes/entity_edit_content_body.html
src/hi/apps/location/templates/location/panes/location_edit_content_body.html

Step 4: Add URL Patterns

  • Add URL patterns for the views.
  • Follow the naming convenions in the attribute edit context classes or override them if needed

See:

src/hi/apps/entity/urls.py
src/hi/apps/location/urls.py
src/hi/apps/config/urls.py

Customizing Owner Fields

Override the owner_fields block to define model-specific fields:

{% block owner_fields %}
<div class="row">
  <div class="col-md-8">
    <!-- Name field -->
  </div>
  <div class="col-md-4">
    <!-- Type or other field -->
  </div>
</div>
{% endblock %}

Template Debugging

Add this to templates for debugging context variables:

{% comment %}DEBUG: Available context variables{% endcomment %}
{% if debug %}
  <pre>{{ attr_context|pprint }}</pre>
  <pre>Owner ID: {{ attr_context.owner_id }}</pre>
  <pre>Owner Type: {{ attr_context.owner_type }}</pre>
{% endif %}

Context Variable Verification

Verify these key context variables are available:

  • attr_owner_context - The AttributeEditContext instance
  • attr_item_context - The AttributeEditContext instance
  • owner_form - Generic alias for model-specific form
  • your_model - Your specific model instance
  • file_attributes - QuerySet of file attributes
  • regular_attributes_formset - Formset for non-file attributes