Django: Only one of two fields can be filled in

It's not necessary that the interface reflects the data structure. You could simply have your UI present them with 1 currency field and then a selection between USD and Euro, then when the data is committed back to the Journals model, you simply assign it to the correct field and clear the other.


I'd agree with T. Stone that customizing the form is the best way to go. If you can't do that, or in addition to that, you can enforce the rule with a custom clean() method on your form. Just bear in mind that any validation errors you throw in the clean() method won't be attached to specific fields, but to the form itself.


Since Django 2.2 database constraints can be used. That means, that on top of the regular model-level validation (which has worked since forever and has been suggested by Tom) you can now make sure that invalid data cannot enter the database at all.

# models.py 
from django.db import models
from django.db.models import Q

class Journals(models.Model):
    # [...]
    
    def clean(self):
        """Ensure that only one of `price_euro` and `price_dollars` can be set."""
        if self.price_euro and self.price_dollars:
            raise ValidationError("Only one price field can be set.")


    class Meta:
        constraints = [
            models.CheckConstraint(
                check=(
                    Q(price_euro__isnull=False) & 
                    Q(price_dollars__isnull=True)
                ) | (
                    Q(price_euro__isnull=True) & 
                    Q(price_dollars__isnull=False)
                ),
                name='only_one_price',
            )
        ]

Make sure to create and apply a migration after Meta.constraints has been changed. Documentation on Meta.constraints is available here.