Home > Mobile >  Django Q objects in model constraints
Django Q objects in model constraints

Time:03-21

I am trying to extend a model in an Django App. The only problem I have is that I need to extend the model constraints as well and that does not work properly.

This is the original constraint for the object in models.py:

 models.CheckConstraint(
                check=(
                    models.Q(inventory_item__isnull=True, device_type__isnull=False)
                    | models.Q(inventory_item__isnull=False, device_type__isnull=True)
                ),
                name="At least one of InventoryItem or DeviceType specified.",
            )

I have tried to extend it like that:

 models.CheckConstraint(
                check=(
                    models.Q(inventory_item__isnull=True, 
                             device_type__isnull=False,
                             module_type__isnull=False)
                    | models.Q(inventory_item__isnull=False, 
                             device_type__isnull=True,
                             module_type__isnull=False)
                    | models.Q(inventory_item__isnull=False, 
                             device_type__isnull=False,
                             module_type__isnull=True)
                ),
                name="At least one of InventoryItem, ModuleType or DeviceType specified.",
            ),

This is how this looks in the migration:

migrations.AddConstraint(
            model_name='hardwarelcm',
            constraint=models.CheckConstraint(check=models.Q(models.Q(('device_type__isnull', False), ('inventory_item__isnull', True), ('module_type__isnull', False)), models.Q(('device_type__isnull', True), ('inventory_item__isnull', False), ('module_type__isnull', False)), models.Q(('device_type__isnull', False), ('inventory_item__isnull', False), ('module_type__isnull', True)), _connector='OR'), name='At least one of InventoryItem or ModelType or DeviceType specified.'),
        )

My problem is that I tried all combinations and it fails every time, but I can see from the error message that only one value is set and the other are Null.

DETAIL: Failling row contains (3, null, 1, null)

Is there some limitation with Q objects that I don't understand? I have tried to read the Django documentation, but could not figure out what the problem is.

CodePudding user response:

Your condition does the opposite: it requires that two items are not None. You should make a check with:

from django.db.models import Q

models.CheckConstraint(
    check=Q(inventory_item=None, device_type=None, module_type__isnull=False) |
          Q(inventory_item=None, device_type__isnull=False, module_type=None) |
          Q(inventory_item__isnull=False, device_type=None, module_type=None),
    name='At least one of InventoryItem, ModuleType or DeviceType specified.'
)

This means that you can specify exactly one. If you want to specify at least one, you can work with:

from django.db.models import Q

models.CheckConstraint(
    check=Q(
        inventory_item__isnull=False,
        device_type__isnull=False,
        module_type__isnull=False,
        _connector=Q.OR
    ),
    name='At least one of InventoryItem, ModuleType or DeviceType specified.'
)
  • Related