Sometimes you want to set a hard limit on the number of Django objects you let a user store and unfortunately, this isn’t easily possible in a vanilla Django install - especially not for objects you don’t control, such as the django.auth.User model.

However, with some tweaking, this is actually quite easy.

The first step is to setup a django signal to catch the particular model before it is saved:

    from django.core.exceptions import PermissionDenied
    from django.db.models.signals import pre_save
    
    @receiver(pre_save, User)
    def check_limits(sender, **kwargs):
        if sender.objects.count() > YOUR_LIIMIT:
            raise PermissionDenied

This will work, but cause a generic PermissionDenied error, when we might want to be clearer. Instead, if we use a custom exception we know exactly why the save failed:

from django.core.exceptions import PermissionDenied
from django.db.models.signals import pre_save

class LimitExceeed(PermissionDenied):
    pass

@receiver(pre_save, User)
def check_limits(sender, **kwargs):
    if sender.objects.count() > YOUR_LIIMIT:
        raise LimitExceeded

But this will propgate up and cause 500 errors instead of the 403 permission denied…

Unless we write a custom django middleware!

class LimitExceededMiddleware(object):
    def process_exception(self, request, exception):
        if isinstance(exception, LimitExceeded):
            return some_view
        return None

Here some_view is any regular django view necessary to tell the user what happen. And voila, all done.

This code only allows you to restrict but customisation should make other objects easy to trap. Alternatively, I’ve started working on django-city-limits that makes it easier to just define patterns of models and maximum values to make restricting item content easier.