Skip to content

Conditional Fields Guide - djadmin-formset

Plugin: djadmin-formset Version: 0.1.0 (Alpha) Last Updated: October 21, 2025

Overview

Conditional fields allow you to show or hide form fields dynamically based on the values of other fields. This is powered by django-formset's client-side reactivity system and requires no page refresh.

Prerequisites

  • djadmin-formset plugin installed
  • Layout API with Field components

Basic Usage

Show Field When Condition is True

Use the show_if attribute to display a field only when a condition matches:

from djadmin import ModelAdmin, register, Layout, Field

@register(Product)
class ProductAdmin(ModelAdmin):
    layout = Layout(
        Field('name'),
        Field('product_type'),

        # Show 'weight' only for physical products
        Field('weight', show_if=".product_type === 'physical'"),

        # Show 'file_size' only for digital products
        Field('file_size', show_if=".product_type === 'digital'"),
    )

How it works: - When product_type changes to 'physical', the weight field appears - When product_type changes to 'digital', the file_size field appears - Fields are hidden/shown instantly via JavaScript (no page reload)

Hide Field When Condition is True

Use the hide_if attribute for inverse logic:

@register(Order)
class OrderAdmin(ModelAdmin):
    layout = Layout(
        Field('status'),
        Field('shipped_date'),

        # Hide 'cancel_reason' unless order is cancelled
        Field('cancel_reason', hide_if=".status !== 'cancelled'"),

        # Equivalent to: show_if=".status === 'cancelled'"
    )

Expression Syntax

Conditional expressions use django-formset's expression language, which is similar to JavaScript:

Accessing Field Values

Use the dot notation to reference field values:

# Current field value
".field_name"

# Example
show_if=".status === 'active'"

Comparison Operators

# Equality
show_if=".type === 'premium'"

# Inequality
show_if=".type !== 'basic'"

# Greater than / Less than
show_if=".quantity > 10"
show_if=".price < 100"

# Greater than or equal / Less than or equal
show_if=".quantity >= 5"
show_if=".price <= 50"

Logical Operators

# AND
show_if=".status === 'active' && .verified === true"

# OR
show_if=".type === 'premium' || .type === 'enterprise'"

# NOT
show_if="!(.status === 'deleted')"

Boolean Fields

# Show when checkbox is checked
show_if=".is_published === true"

# Show when checkbox is NOT checked
show_if=".is_published === false"

# Or use hide_if
hide_if=".is_published === true"

Null/Undefined Checks

# Show only if field has a value
show_if=".discount !== null && .discount !== ''"

# Show only if field is empty
show_if=".discount === null || .discount === ''"

Advanced Examples

Example 1: Multi-Level Conditionals

@register(ShippingAddress)
class ShippingAddressAdmin(ModelAdmin):
    layout = Layout(
        Field('country'),
        Field('state', show_if=".country === 'US'"),
        Field('province', show_if=".country === 'CA'"),
        Field('postal_code', show_if=".country === 'US' || .country === 'CA'"),
        Field('zip_code', show_if=".country === 'US'"),
    )

Example 2: Dependent Cascade

@register(Vehicle)
class VehicleAdmin(ModelAdmin):
    layout = Layout(
        Field('vehicle_type'),  # car, motorcycle, bicycle

        # Level 1: Show based on vehicle type
        Field('fuel_type', show_if=".vehicle_type === 'car' || .vehicle_type === 'motorcycle'"),

        # Level 2: Show based on fuel type
        Field('battery_capacity', show_if=".fuel_type === 'electric'"),
        Field('fuel_tank_size', show_if=".fuel_type === 'gasoline' || .fuel_type === 'diesel'"),

        # Always show for certain types
        Field('num_wheels', show_if=".vehicle_type === 'car'"),
        Field('frame_size', show_if=".vehicle_type === 'bicycle'"),
    )

Example 3: Numeric Ranges

@register(Discount)
class DiscountAdmin(ModelAdmin):
    layout = Layout(
        Field('discount_type'),  # percentage, fixed
        Field('percentage', show_if=".discount_type === 'percentage'"),
        Field('fixed_amount', show_if=".discount_type === 'fixed'"),

        # Show warning for high discounts
        Field('approval_required', show_if=".percentage > 50 || .fixed_amount > 100"),
    )

Example 4: Complex Business Logic

@register(Subscription)
class SubscriptionAdmin(ModelAdmin):
    layout = Layout(
        Field('plan'),  # basic, premium, enterprise
        Field('is_trial'),

        # Show billing fields only for non-trial paid plans
        Field('billing_cycle',
            show_if="(.plan === 'premium' || .plan === 'enterprise') && .is_trial === false"
        ),

        # Show trial end date only during trial
        Field('trial_end_date', show_if=".is_trial === true"),

        # Show upgrade offer only for basic plan
        Field('upgrade_offer', show_if=".plan === 'basic' && .is_trial === false"),
    )

Example 5: Conditional Fieldsets

You can use conditional fields inside fieldsets:

from djadmin import ModelAdmin, register, Layout, Field, Fieldset

@register(Event)
class EventAdmin(ModelAdmin):
    layout = Layout(
        Fieldset('Basic Information',
            Field('title'),
            Field('event_type'),  # 'online', 'in-person', 'hybrid'
        ),

        # Fieldset with conditional fields
        Fieldset('Location Details',
            Field('venue_name', show_if=".event_type === 'in-person' || .event_type === 'hybrid'"),
            Field('address', show_if=".event_type === 'in-person' || .event_type === 'hybrid'"),
            Field('zoom_link', show_if=".event_type === 'online' || .event_type === 'hybrid'"),
        ),
    )

Combining with Rows

Conditional fields work inside Row layouts:

from djadmin import ModelAdmin, register, Layout, Field, Row

@register(Product)
class ProductAdmin(ModelAdmin):
    layout = Layout(
        Field('product_type'),

        # Conditional row - both fields show/hide together
        Row(
            Field('length', css_classes=['flex-1'], show_if=".product_type === 'physical'"),
            Field('width', css_classes=['flex-1'], show_if=".product_type === 'physical'"),
            Field('height', css_classes=['flex-1'], show_if=".product_type === 'physical'"),
        ),
    )

Validation Considerations

Required Fields

IMPORTANT: If a field is marked as required=True but is hidden via show_if, django-formset handles this intelligently:

Field('shipping_address',
    required=True,
    show_if=".requires_shipping === true"
)
  • When visible: Field is required (validation enforced)
  • When hidden: Field is NOT required (validation skipped)

This is automatic - no special handling needed!

Example: Conditional Required Fields

@register(CustomerOrder)
class CustomerOrderAdmin(ModelAdmin):
    layout = Layout(
        Field('requires_shipping'),  # Boolean

        # Required only when shipping is needed
        Field('shipping_address',
            required=True,
            show_if=".requires_shipping === true"
        ),
        Field('shipping_method',
            required=True,
            show_if=".requires_shipping === true"
        ),

        # Always required
        Field('billing_address', required=True),
    )

Performance Considerations

Client-Side Execution

Conditional logic runs entirely in the browser via JavaScript:

  • ✅ No server roundtrips
  • ✅ Instant feedback
  • ✅ Works offline (after page load)
  • ✅ No network latency

Limitations

  • ❌ Cannot access database values
  • ❌ Cannot call Django/Python functions
  • ❌ Limited to values in the current form

For server-side logic, use Django's form clean() methods:

# For complex validation requiring database access
class MyForm(forms.ModelForm):
    def clean(self):
        data = super().clean()
        if data['type'] == 'premium':
            # Server-side check
            if not self.instance.user.has_premium_access():
                raise ValidationError('User not authorized for premium')
        return data

Troubleshooting

Conditions Not Working

Symptom: Fields don't show/hide when values change

Checklist: 1. ✅ Plugin installed? Check INSTALLED_APPS includes 'djadmin_formset' 2. ✅ JavaScript loaded? Check browser console for errors 3. ✅ Syntax correct? Use === not =, && not and 4. ✅ Field name correct? Use exact field name (case-sensitive)

Debug:

// Browser console
// Check if formset is initialized
document.querySelector('form[data-formset]')

// Check field attributes
document.querySelector('[name="field_name"]').getAttribute('df-show')

Wrong Field Reference

Symptom: Condition always evaluates to false

Common mistake:

# WRONG - missing dot prefix
show_if="status === 'active'"

# CORRECT - dot prefix required
show_if=".status === 'active'"

Boolean Field Issues

Symptom: Boolean conditions not working

Solution: Use === true or === false:

# WRONG
show_if=".is_active"

# CORRECT
show_if=".is_active === true"

Quotes in String Values

Symptom: Syntax error in expressions with quotes

Solution: Use consistent quotes:

# WRONG - mixing quotes
show_if='.status === "active"'

# CORRECT - use single quotes for expression, escape inner quotes
show_if=".status === 'active'"

# CORRECT - or double quotes for expression, escape inner
show_if=".status === \"active\""

Best Practices

1. Keep Expressions Simple

# Good - simple, readable
show_if=".type === 'premium'"

# Avoid - complex, hard to maintain
show_if="(.type === 'premium' && .verified === true && .credits > 100) || (.type === 'enterprise' && .trial === false)"

For complex logic, consider splitting into multiple fields or using computed fields.

2. Use Meaningful Field Names

# Good - clear what it controls
Field('requires_shipping')
Field('shipping_address', show_if=".requires_shipping === true")

# Avoid - unclear
Field('flag1')
Field('address', show_if=".flag1 === true")

3. Document Complex Conditions

# Document the business logic
Field('approval_needed',
    # Show approval field when:
    # - Discount > 50% OR
    # - Fixed discount > $100
    show_if=".percentage > 50 || .fixed_amount > 100"
)

4. Test All Branches

Test that fields show/hide correctly for all possible values:

def test_conditional_fields(admin_client, product_factory):
    """Test conditional fields show/hide correctly."""
    # Test physical product - weight visible
    response = admin_client.get(...)
    # Check weight field has df-show attribute

    # Test digital product - file_size visible
    # ...

5. Provide Visual Feedback

When fields appear/disappear, ensure smooth transitions:

/* Add to your CSS */
[df-show], [df-hide] {
    transition: opacity 0.2s ease-in-out;
}

Expression Reference

Operators

Operator Example Description
=== .status === 'active' Strict equality
!== .status !== 'deleted' Strict inequality
> .quantity > 10 Greater than
< .price < 100 Less than
>= .quantity >= 5 Greater than or equal
<= .price <= 50 Less than or equal
&& .a === 1 && .b === 2 Logical AND
|| .a === 1 || .b === 2 Logical OR
! !(.status === 'deleted') Logical NOT

Data Types

Type Example Values Usage
String 'active', 'pending' Use single quotes
Number 10, 99.99 No quotes
Boolean true, false Lowercase, no quotes
Null null Lowercase, no quotes

See Also