Home > OS >  How best to validate number of total reverse relationships before saving
How best to validate number of total reverse relationships before saving

Time:12-31

I have an Item model that is reverse-related to two other models (ItemComponent and or ItemComponentCategory). The idea is I'd like to be able to validate that Items have no more than 4 relations to the two other models, combined, before being saved.

class Item(models.Model):
    name = models.CharField(max_length=40, unique=True)

class ItemComponent(models.Model):
    parent_item = models.ForeignKey(Item, related_name='components')

class ItemComponentCategory(models.Model):
    parent_item = models.ForeignKey(Item, related_name='categories')

I'd like to create a validation that raises an error before saving either the Item, ItemComponent, or ItemComponentCategory objects if the saved objects will result in > 4 object relations between them.

I have tried adding something like this to the clean methods for all three:

    def clean(self):

        if (self.parent_item.components.count()   self.parent_item.categories.count()) > 4:
            raise ValidationError(_(f'Items can have no more than 4 components and/or component categories'))

This seems to work as long as the Items and their relations are already saved with 4 and you're trying to add more relations.

However, if I create a TabularInline in the ItemAdmin to add these 'sub types,' if you will.. I can create a new Item and add as many of these sub types and save it no problem.

What am I missing here?

CodePudding user response:

It seems my issue is related to timing and order of processes.

When saving an admin page with inline references, the model of the main page is saved first then the inline objects. This poses an issue when trying to use a model's clean() method to validate against the relation, because it simply does not exist yet.

As mentioned in THIS article it seems that my solution is to modify the modelAdmin functions to ensure that the inline objects are saved first, then validate the main objects after they're saved.

Also, I think this save_related method for modelAdmin will come in handy.

  • Related