Documentation Index
Fetch the complete documentation index at: https://mintlify.com/allegro/ralph/llms.txt
Use this file to discover all available pages before exploring further.
Custom Fields System
Ralph’s custom fields system allows you to add dynamic fields to models without modifying the database schema. This is useful for organization-specific data that doesn’t fit into the core model structure.
Overview
Custom fields are:
- Dynamic: Created through the admin interface, no code changes required
- Typed: Support string, integer, date, URL, and choice list types
- Inheritable: Can be inherited from related objects
- API-enabled: Automatically exposed in the REST API
- Permission-controlled: Can be restricted to specific user groups
Adding Custom Fields to Models
Step 1: Add the Mixin
Mix WithCustomFieldsMixin into your model:
from django.db import models
from ralph.lib.custom_fields.models import WithCustomFieldsMixin
from ralph.lib.mixins.models import AdminAbsoluteUrlMixin
class Asset(WithCustomFieldsMixin, AdminAbsoluteUrlMixin, models.Model):
hostname = models.CharField(max_length=255)
barcode = models.CharField(max_length=200, unique=True)
# ... other fields
Source: src/ralph/lib/custom_fields/models.py:212-221
Step 2: Enable Admin Integration
Mix CustomFieldValueAdminMixin into your admin class:
from ralph.admin import RalphAdmin, register
from ralph.lib.custom_fields.admin import CustomFieldValueAdminMixin
from myapp.models import Asset
@register(Asset)
class AssetAdmin(CustomFieldValueAdminMixin, RalphAdmin):
list_display = ['hostname', 'barcode', 'status']
# ... other admin configuration
Source: src/ralph/lib/custom_fields/admin.py:67-84
Step 3: Enable API Integration
For Django Rest Framework, mix WithCustomFieldsSerializerMixin into your serializer:
from rest_framework import serializers
from ralph.lib.custom_fields.api import WithCustomFieldsSerializerMixin
from myapp.models import Asset
class AssetSerializer(WithCustomFieldsSerializerMixin, serializers.ModelSerializer):
class Meta:
model = Asset
fields = '__all__'
Source: docs/development/custom-fields.md:12-14
Field Types
Ralph supports five custom field types:
String
Plain text values:
# Field configuration in admin:
# Type: String
# Default value: "N/A"
Integer
Numeric values:
# Field configuration in admin:
# Type: Integer
# Default value: 0
Date
Date values (YYYY-MM-DD format):
# Field configuration in admin:
# Type: Date
# Default value: 2024-01-01
URL
Validated URL values:
# Field configuration in admin:
# Type: URL
# Default value: https://example.com
Choice List
Predefined choices separated by pipe (|):
# Field configuration in admin:
# Type: Choice List
# Choices: Production|Staging|Development|Testing
# Default value: Production
Source: src/ralph/lib/custom_fields/models.py:23-48
Creating Custom Fields
Custom fields are created through the admin interface at /admin/custom_fields/customfield/:
- Navigate to Custom Fields in the admin
- Click Add Custom Field
- Fill in the details:
- Name: Display name (e.g., “Purchase Order Number”)
- Attribute Name: Auto-generated slug (e.g., “purchase_order_number”)
- Type: Select from String, Integer, Date, URL, or Choice List
- Choices: For Choice List type, enter options separated by
|
- Default Value: Optional default value
- Managing Group: Restrict editing to specific group (optional)
- Use as Configuration Variable: Expose in API configuration_variables
Using Custom Fields
In Python Code
Access custom field values:
# Get all custom fields as a dictionary
asset = Asset.objects.get(id=1)
custom_data = asset.custom_fields_as_dict
# {'Purchase Order': 'PO-12345', 'Warranty Expiry': '2025-12-31'}
# Update a custom field
asset.update_custom_field('Purchase Order', 'PO-67890')
# Get configuration variables only
config_vars = asset.custom_fields_configuration_variables
Source: src/ralph/lib/custom_fields/models.py:222-242
Direct QuerySet Access
from ralph.lib.custom_fields.models import CustomField, CustomFieldValue
# Get a specific custom field
purchase_order_field = CustomField.objects.get(name='Purchase Order')
# Find all assets with a specific custom field value
assets_with_po = Asset.objects.filter(
custom_fields__custom_field=purchase_order_field,
custom_fields__value='PO-12345'
)
# Create a custom field value
CustomFieldValue.objects.create(
custom_field=purchase_order_field,
object=asset,
value='PO-12345'
)
Source: src/ralph/lib/custom_fields/models.py:125-149
In Templates
Display custom fields in admin templates:
{% for cfv in object.custom_fields.all %}
<div class="field">
<label>{{ cfv.custom_field.name }}:</label>
<span>{{ cfv.value }}</span>
</div>
{% endfor %}
Custom Field Inheritance
Custom fields can be inherited from related objects. For example, a virtual server can inherit custom fields from its hypervisor:
class Hypervisor(WithCustomFieldsMixin, models.Model):
name = models.CharField(max_length=255)
# No custom_fields_inheritance needed - this is the parent
class VirtualServer(WithCustomFieldsMixin, models.Model):
name = models.CharField(max_length=255)
hypervisor = models.ForeignKey(Hypervisor, on_delete=models.CASCADE)
# Define inheritance path
custom_fields_inheritance = {
'hypervisor': 'myapp.Hypervisor'
}
Now when you access virtual_server.custom_fields.all(), it returns both:
- Custom fields set directly on the virtual server
- Custom fields inherited from its hypervisor
Source: src/ralph/lib/custom_fields/models.py:190-210
Clearing Inherited Values
When a parent object’s custom field is deleted, you can clear it from child objects:
# This is handled automatically when using the admin interface
hypervisor.clear_children_custom_field_value(custom_field)
Source: src/ralph/lib/custom_fields/models.py:244-265
Permission Management
Restrict custom field editing to specific groups:
# In admin, when creating/editing a custom field:
# Managing Group: IT Administrators
When a managing group is set:
- Only users in that group can create/edit/delete values for this field
- Other users can still view the field values
- Useful for sensitive data like license keys or compliance information
Source: src/ralph/lib/custom_fields/models.py:75-84
Configuration Variables
Mark custom fields as configuration variables to expose them in the API:
# In admin, when creating/editing a custom field:
# Use as Configuration Variable: ✓ (checked)
These fields are then available in API responses under configuration_variables:
{
"id": 123,
"hostname": "server01",
"configuration_variables": {
"ENVIRONMENT": "production",
"APP_VERSION": "2.1.0",
"MONITORING_ENABLED": "true"
}
}
This is useful for configuration management tools like Ansible or Puppet.
Source: src/ralph/lib/custom_fields/models.py:86-93, src/ralph/lib/custom_fields/models.py:229-236
Admin Interface Features
Custom Field Values Summary
The admin shows a summary of all custom field values, including inherited ones:
@register(Asset)
class AssetAdmin(CustomFieldValueAdminMixin, RalphAdmin):
# Show summary of custom field values (default: True)
show_custom_fields_values_summary = True
The summary displays:
- Field name
- Current value
- Source object (if inherited)
- Link to source object
Source: src/ralph/lib/custom_fields/admin.py:67-133
Inline Editing
Custom fields appear as an inline formset in the change form, allowing you to:
- Add new custom field values
- Edit existing values
- Delete custom field values
- Clear inherited values (if applicable)
Source: src/ralph/lib/custom_fields/admin.py:55-65
Data Model
CustomField Model
Defines the custom field configuration:
class CustomField(models.Model):
name = models.CharField(max_length=255, unique=True)
attribute_name = models.SlugField(max_length=255, unique=True) # auto-generated
type = models.PositiveIntegerField(choices=CustomFieldTypes())
choices = models.TextField(null=True, blank=True) # for choice lists
default_value = models.CharField(max_length=1000)
managing_group = models.ForeignKey(Group, null=True, blank=True)
use_as_configuration_variable = models.BooleanField(default=False)
Source: src/ralph/lib/custom_fields/models.py:50-95
CustomFieldValue Model
Stores the actual values:
class CustomFieldValue(models.Model):
custom_field = models.ForeignKey(CustomField)
value = models.CharField(max_length=1000) # stored as string
content_type = models.ForeignKey(ContentType) # generic relation
object_id = models.PositiveIntegerField()
object = GenericForeignKey('content_type', 'object_id')
class Meta:
unique_together = ('custom_field', 'content_type', 'object_id')
Source: src/ralph/lib/custom_fields/models.py:125-149
Best Practices
- Use descriptive names: “Purchase Order Number” instead of “PO Num”
- Choose appropriate types: Use Integer for numbers, Date for dates, etc.
- Set defaults wisely: Provide sensible defaults to reduce data entry
- Use managing groups: Protect sensitive fields from unauthorized edits
- Mark config variables: Only mark fields as configuration variables if they’re needed by external tools
- Avoid overuse: Don’t replace proper model fields with custom fields for core functionality
Complete Example
Here’s a complete example of adding custom fields to an Asset model:
# models.py
from django.db import models
from ralph.lib.custom_fields.models import WithCustomFieldsMixin
from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, TimeStampMixin
class Asset(WithCustomFieldsMixin, AdminAbsoluteUrlMixin, TimeStampMixin, models.Model):
hostname = models.CharField(max_length=255)
barcode = models.CharField(max_length=200, unique=True)
status = models.PositiveIntegerField(choices=AssetStatus())
class Meta:
verbose_name = 'Asset'
verbose_name_plural = 'Assets'
# admin.py
from ralph.admin import RalphAdmin, register
from ralph.lib.custom_fields.admin import CustomFieldValueAdminMixin
from myapp.models import Asset
@register(Asset)
class AssetAdmin(CustomFieldValueAdminMixin, RalphAdmin):
list_display = ['hostname', 'barcode', 'status']
search_fields = ['hostname', 'barcode']
list_filter = ['status']
# Show custom field summary in change form
show_custom_fields_values_summary = True
# serializers.py (for API)
from rest_framework import serializers
from ralph.lib.custom_fields.api import WithCustomFieldsSerializerMixin
from myapp.models import Asset
class AssetSerializer(WithCustomFieldsSerializerMixin, serializers.ModelSerializer):
class Meta:
model = Asset
fields = ['id', 'hostname', 'barcode', 'status']
# custom_fields and configuration_variables are added automatically
Now you can:
- Create custom fields in the admin at
/admin/custom_fields/customfield/
- Add custom field values when editing assets
- Access values via
asset.custom_fields_as_dict in Python
- See custom fields in API responses automatically
Next Steps