Skip to content

StateZero Additional Fields Documentation ​

Additional fields in StateZero allow you to expose computed or derived data from your Django models that requires server-side context or real-time data that isn't available on the frontend. These fields are read-only and are calculated on the backend using information that only the server has access to.

Overview ​

Additional fields enable you to:

  • Access server-side data like real-time exchange rates, external API data, or system state
  • Perform calculations with sensitive data that shouldn't be exposed to the frontend
  • Include real-time computed values that depend on current server state
  • Add derived values from external systems or third-party services

Additional fields are always read-only and are computed server-side during serialization using data that's only available on the backend.

When to Use Additional Fields ​

Use additional fields when you need to:

  • Access real-time external data (currency rates, stock prices, API data)
  • Perform calculations with server-only information (user permissions, system configuration)
  • Include time-sensitive computations that must reflect current server state
  • Aggregate data across tenants or systems that the frontend can't access

Don't use additional fields for:

  • Simple formatting (handle on frontend)
  • Static choices/enums (use frontend mapping)
  • Client-side calculations (do in JavaScript)
  • Data the frontend already has access to

Configuration ​

Additional fields are configured using the AdditionalField class when registering models with StateZero:

python
from statezero.core.config import ModelConfig
from statezero.core.classes import AdditionalField
from statezero import register_model
from django.db import models

register_model(
    Product,
    ModelConfig(
        model=Product,
        additional_fields=[
            AdditionalField(
                name="price_in_user_currency",
                title="Price in User Currency",
                field=models.DecimalField(max_digits=10, decimal_places=2),
            ),
            AdditionalField(
                name="real_time_availability",
                title="Real-time Availability", 
                field=models.BooleanField(),
            ),
        ],
        # ... other configuration options
    )
)

AdditionalField Parameters ​

Required Parameters ​

  • name: The name of the property or method on your Django model that provides the value
  • field: A Django field instance that defines the serialization behavior and type

Optional Parameters ​

  • title: Display title for the field (overrides any title from the field definition)

Django Model Implementation ​

For additional fields to work, your Django model must have corresponding properties or methods that access server-side data:

python
from django.db import models
from decimal import Decimal
import requests
from django.core.cache import cache

class Product(models.Model):
    name = models.CharField(max_length=100)
    price_usd = models.DecimalField(max_digits=10, decimal_places=2)
    sku = models.CharField(max_length=50)
    
    def price_in_user_currency(self, request=None):
        """Computed field: price converted to user's currency using real-time rates"""
        if not request or not hasattr(request.user, 'preferred_currency'):
            return self.price_usd
        
        user_currency = request.user.preferred_currency
        if user_currency == 'USD':
            return self.price_usd
        
        # Get real-time exchange rate (with caching)
        cache_key = f"fx_rate_USD_{user_currency}"
        exchange_rate = cache.get(cache_key)
        
        if exchange_rate is None:
            # Fetch from external API
            response = requests.get(f"https://api.exchangerate.com/USD/{user_currency}")
            exchange_rate = response.json()['rate']
            cache.set(cache_key, exchange_rate, timeout=300)  # 5 minutes
        
        return self.price_usd * Decimal(str(exchange_rate))
    
    @property
    def real_time_availability(self):
        """Computed field: check real-time inventory from external system"""
        # Check with external inventory API
        response = requests.get(f"https://inventory-api.com/check/{self.sku}")
        return response.json()['available']

class Investment(models.Model):
    symbol = models.CharField(max_length=10)
    shares = models.DecimalField(max_digits=10, decimal_places=2)
    purchase_price = models.DecimalField(max_digits=10, decimal_places=2)
    
    @property
    def current_value(self):
        """Computed field: current market value using real-time prices"""
        # Get current stock price from market data API
        cache_key = f"stock_price_{self.symbol}"
        current_price = cache.get(cache_key)
        
        if current_price is None:
            response = requests.get(f"https://market-api.com/price/{self.symbol}")
            current_price = response.json()['price']
            cache.set(cache_key, current_price, timeout=60)  # 1 minute
        
        return self.shares * Decimal(str(current_price))
    
    @property
    def gain_loss(self):
        """Computed field: profit/loss calculation"""
        purchase_value = self.shares * self.purchase_price
        return self.current_value - purchase_value

Common Use Cases ​

1. Real-Time Currency Conversion ​

python
# Django Model
class Product(models.Model):
    name = models.CharField(max_length=100)
    price_usd = models.DecimalField(max_digits=10, decimal_places=2)
    
    def price_in_user_currency(self, request=None):
        """Convert price using real-time exchange rates"""
        if not request or not hasattr(request.user, 'preferred_currency'):
            return self.price_usd
        
        user_currency = request.user.preferred_currency
        if user_currency == 'USD':
            return self.price_usd
        
        # Get real-time FX rate from external service
        exchange_rate = get_exchange_rate('USD', user_currency)
        return self.price_usd * exchange_rate

# StateZero Configuration
register_model(
    Product,
    ModelConfig(
        model=Product,
        additional_fields=[
            AdditionalField(
                name="price_in_user_currency",
                title="Price in User Currency",
                field=models.DecimalField(max_digits=12, decimal_places=2),
            ),
        ],
    )
)

2. Real-Time External System Data ​

python
# Django Model
class Product(models.Model):
    sku = models.CharField(max_length=50)
    name = models.CharField(max_length=100)
    
    @property
    def real_time_stock_level(self):
        """Get current stock from warehouse management system"""
        response = requests.get(f"https://wms-api.com/stock/{self.sku}")
        return response.json()['quantity']
    
    @property
    def estimated_delivery_date(self):
        """Calculate delivery date based on current logistics data"""
        logistics_api = "https://logistics-api.com/delivery-estimate"
        response = requests.post(logistics_api, json={
            'sku': self.sku,
            'destination': self.get_user_location()  # From request context
        })
        return response.json()['estimated_date']

# StateZero Configuration  
register_model(
    Product,
    ModelConfig(
        model=Product,
        additional_fields=[
            AdditionalField(
                name="real_time_stock_level",
                title="Current Stock Level", 
                field=models.PositiveIntegerField(),
            ),
            AdditionalField(
                name="estimated_delivery_date",
                title="Estimated Delivery",
                field=models.DateField(),
            ),
        ],
    )
)

3. User-Specific Calculations with Server Context ​

python
# Django Model
class Investment(models.Model):
    user = models.ForeignKey('User', on_delete=models.CASCADE)
    symbol = models.CharField(max_length=10)
    shares = models.DecimalField(max_digits=10, decimal_places=2)
    
    def current_value_in_user_currency(self, request=None):
        """Calculate current value in user's preferred currency"""
        # Get real-time stock price
        current_price = get_stock_price(self.symbol)
        value_usd = self.shares * current_price
        
        # Convert to user's currency if needed
        if request and hasattr(request.user, 'preferred_currency'):
            user_currency = request.user.preferred_currency
            if user_currency != 'USD':
                fx_rate = get_exchange_rate('USD', user_currency)
                return value_usd * fx_rate
        
        return value_usd
    
    def tax_impact(self, request=None):
        """Calculate tax implications based on user's tax jurisdiction"""
        if not request or not request.user.is_authenticated:
            return None
        
        # Get user's tax jurisdiction from their profile
        tax_jurisdiction = request.user.profile.tax_jurisdiction
        
        # Calculate using jurisdiction-specific tax rules
        current_value = self.current_value_in_user_currency(request)
        purchase_value = self.shares * self.purchase_price
        gain = current_value - purchase_value
        
        if gain > 0:
            tax_rate = get_capital_gains_rate(tax_jurisdiction)
            return gain * tax_rate
        return 0

# StateZero Configuration
register_model(
    Investment,
    ModelConfig(
        model=Investment,
        additional_fields=[
            AdditionalField(
                name="current_value_in_user_currency",
                title="Current Value",
                field=models.DecimalField(max_digits=15, decimal_places=2),
            ),
            AdditionalField(
                name="tax_impact",
                title="Estimated Tax Impact",
                field=models.DecimalField(max_digits=15, decimal_places=2),
            ),
        ],
    )
)

Frontend Usage ​

Once configured, additional fields appear as regular properties on your model instances:

javascript
// Fetch a product with real-time computed fields
const product = await Product.objects.get({ id: 1 });

console.log(product.name);                    // "iPhone 15"
console.log(product.price_usd);               // 999.00
console.log(product.price_in_user_currency);  // 850.15 (real-time EUR conversion)
console.log(product.real_time_stock_level);   // 42 (from warehouse API)

// Fetch investment with current market data
const investment = await Investment.objects.get({ id: 1 });

console.log(investment.symbol);                        // "AAPL"
console.log(investment.shares);                        // 100
console.log(investment.current_value_in_user_currency); // 18,450.25 (real-time price)
console.log(investment.tax_impact);                    // 1,245.30 (jurisdiction-specific)

// Multiple products with real-time data
const products = await Product.objects.all().fetch();
products.forEach(product => {
    console.log(`${product.name}: ${product.price_in_user_currency} ${user.preferred_currency}`);
    console.log(`Stock: ${product.real_time_stock_level} units`);
});

Field Type Mapping ​

The Django field type you specify determines how the additional field is serialized and typed:

Django FieldPurposeFrontend Type
CharFieldText/string valuesstring
IntegerFieldWhole numbersnumber
DecimalFieldPrecise decimal numbersnumber
BooleanFieldTrue/false valuesboolean
DateTimeFieldDate and timestring (ISO format)
DateFieldDate onlystring (YYYY-MM-DD)

Best Practices ​

1. Cache External API Calls ​

Always cache data from external APIs to avoid performance issues:

python
from django.core.cache import cache

@property
def real_time_exchange_rate(self):
    cache_key = f"fx_rate_{self.from_currency}_{self.to_currency}"
    rate = cache.get(cache_key)
    
    if rate is None:
        # Fetch from external API
        rate = fetch_exchange_rate(self.from_currency, self.to_currency)
        cache.set(cache_key, rate, timeout=300)  # 5 minutes
    
    return rate

2. Handle External Service Failures Gracefully ​

Always provide fallbacks when external services are unavailable:

python
@property
def current_stock_level(self):
    try:
        response = requests.get(f"https://api.com/stock/{self.sku}", timeout=2)
        return response.json()['quantity']
    except (requests.RequestException, KeyError):
        # Fallback to last known value or estimated value
        return self.last_known_stock or 0

3. Use Appropriate Field Types for External Data ​

Match the Django field type to your external data:

python
# Financial data - use DecimalField for precision
AdditionalField(
    name="current_market_value",
    field=models.DecimalField(max_digits=15, decimal_places=2),
)

# API availability - use BooleanField
AdditionalField(
    name="is_available_for_shipping",
    field=models.BooleanField(),
)

# External timestamps - use DateTimeField
AdditionalField(
    name="next_restock_date",
    field=models.DateTimeField(),
)

Limitations ​

1. Read-Only Nature ​

Additional fields cannot be set from the frontend - they're always computed server-side:

javascript
// This won't work - additional fields are read-only
const product = await Product.objects.get({ id: 1 });
product.price_in_user_currency = 1000;  // ❌ This will be ignored
await product.save();

2. Not Filterable ​

You cannot filter or search on additional fields:

javascript
// This won't work - additional fields can't be used in filters
const products = await Product.objects
  .filter({ price_in_user_currency__gte: 1000 })  // ❌ Error
  .fetch();

3. Performance and Reliability Considerations ​

Additional fields that depend on external services can impact performance and reliability:

  • Latency: External API calls add response time
  • Rate limits: External services may have usage restrictions
  • Availability: External services may be temporarily unavailable
  • Cost: Some external APIs charge per request

Always implement proper caching, error handling, and fallbacks.

Troubleshooting ​

Common Issues ​

  1. Missing property on model: Ensure the Django model has a property/method matching the name
  2. Wrong field type: Use the appropriate Django field type for serialization
  3. Performance issues: Consider caching or database optimizations for expensive computations

Debugging ​

Check that your model property returns the expected data type:

python
# In Django shell or tests
product = Product.objects.get(id=1)
print(type(product.price_with_tax))  # Should match your field type
print(product.price_with_tax)        # Check the actual value

Conclusion ​

Additional fields are specifically designed for exposing server-side computed data that requires external APIs, real-time information, or sensitive calculations that can't be performed on the frontend. They're perfect for:

  • Real-time financial data (currency conversion, stock prices, market rates)
  • External system integration (inventory levels, shipping estimates, availability)
  • User-specific calculations that require server context (tax calculations, personalized pricing)
  • Time-sensitive data that must reflect current server state

Remember:

  • Use for data that only the server can access
  • Always implement caching and error handling for external APIs
  • Provide meaningful fallbacks when external services fail
  • Focus on real-time or server-context dependent computations
  • Avoid using for simple formatting or static data transformations