Skip to content

Validation and Clean Hooks

Factories respect the same validation pipeline as your application code. Understanding how clean() and rules interact ensures your fixtures remain realistic.

Interface validation

InterfaceBase calls parse_input_fields_to_identification() to convert raw inputs into validated types. During create and update, interfaces execute full_clean() on the underlying Django model, including Django field, uniqueness, and constraint checks plus rules declared in Meta.rules. A rule adds errors only when it returns False; True and None are treated as passing results. Rule messages are merged with Django validation messages for the same field.

Factory interaction

  • AutoFactory._model_creation() assigns field values, runs full_clean(), and saves the model. Validation errors bubble up, making faulty fixtures obvious.
  • Override AutoFactory._adjustmentMethod when complex fixture setup needs to reshape incoming kwargs into one or more record dictionaries before validation and save. See Generate Bulk Test Data for the full pattern.

Best practices

  1. Mirror production defaults. If a field has a rule requiring positive values, set a default in the factory that satisfies it.
  2. Wrap factory calls in helper functions that also create related managers, ensuring rules that reference relationships pass in tests.
  3. Test validation logic directly by asserting that factories raise ValidationError when provided with invalid data.

Example:

import pytest
from django.core.exceptions import ValidationError

def test_negative_budget_is_rejected(project_factory):
    with pytest.raises(ValidationError):
        project_factory(total_capex="-1 EUR")

By keeping factories aligned with interface validation, your tests will catch regressions early.