Limit number of model instances to be created - django

前端 未结 6 1522
萌比男神i
萌比男神i 2020-12-02 20:36

I have model from which I only want to create one instance, and no more instances should be allowed.

Is this possible? I\'ve got a feeling that I\'ve seen this done

相关标签:
6条回答
  • 2020-12-02 21:03

    I wanted to do something similar myself, and found that Django's model validation provided a convenient hook for enforcement:

    from django.db import models
    from django.core.exceptions import ValidationError
    
    def validate_only_one_instance(obj):
        model = obj.__class__
        if (model.objects.count() > 0 and
                obj.id != model.objects.get().id):
            raise ValidationError("Can only create 1 %s instance" % model.__name__)
    
    class Example(models.Model):
    
        def clean(self):
            validate_only_one_instance(self)
    

    That not only prevents the creation of new instances, but the Django admin UI will actually report that the creation failed and the reason was "Can only create 1 Example instance"(whereas the early return approach in the docs gives no indication as to why the save didn't work).

    0 讨论(0)
  • 2020-12-02 21:17

    @ncoghlan your solution is working fine, but not very user-friendly: the user has access to the creation form and will think he/she can use it, even though he/she will never be able to save it.

    It's actually possible to combine it with Brendan's solution, which will hide the 'Add' button. Using Mixins for easy reuse:

    # models.py
    from django.db import models
    from django.core.exceptions import ValidationError
    
    class SingleInstanceMixin(object):
        """Makes sure that no more than one instance of a given model is created."""
    
        def clean(self):
            model = self.__class__
            if (model.objects.count() > 0 and self.id != model.objects.get().id):
                raise ValidationError("Can only create 1 %s instance" % model.__name__)
            super(SingleInstanceMixin, self).clean()
    
    class Example(SingleInstanceMixin, models.Model):
        pass
    
    
    # admin.py
    from django.contrib import admin
    from example.models import Example
    
    class SingleInstanceAdminMixin(object):
        """Hides the "Add" button when there is already an instance."""
        def has_add_permission(self, request):
            num_objects = self.model.objects.count()
            if num_objects >= 1:
                return False
            return super(SingleInstanceAdminMixin, self).has_add_permission(request)
    
    class ExampleAdmin(SingleInstanceAdminMixin, admin.ModelAdmin):
         model = Example
    
    0 讨论(0)
  • 2020-12-02 21:18

    I would override create() method on default manager, but as stated above, this won't guarantee anything in multi-threaded environment.

    0 讨论(0)
  • 2020-12-02 21:21

    You can do something like this, from the Django docs:

    class ModelWithOnlyOneInstance(models.Model):
        ... fields ...
    
        def save(self, *args, **kwargs):
          if ModelWithOnlyOneInstance.objects.count() > 1:
            return
    
          super(ModelWithOnlyOneInstance, self).save(*args, **kwargs)
    
    0 讨论(0)
  • 2020-12-02 21:21

    If you only want one instance of a model , perhaps 'there is an app for that!'

    You can check django-solo witch is a complete solution for what you need.

    here is a link -> https://github.com/lazybird/django-solo

    It comes with a class for singleton models and one for admin singleton models, witch does not add an s to the end of the model name, exclude the intermediary screen witch lists all objects and also removes the 'add' button and the 'save and add another' button.

    It also comes with some other fluffy and useful stuff like importing the singletons directly on your templates, etc...

    0 讨论(0)
  • 2020-12-02 21:22

    If you just want to prevent users using the administrative interface from creating extra model objects you could modify the "has_add_permission" method of the model's ModelAdmin class:

    # admin.py
    from django.contrib import admin
    from example.models import Example
    
    class ExampleAdmin(admin.ModelAdmin):
      def has_add_permission(self, request):
        num_objects = self.model.objects.count()
        if num_objects >= 1:
          return False
        else:
          return True
    
    admin.site.register(Example, ExampleAdmin)
    

    This will remove the "add" button in the administrative interface preventing users from even attempting to create more than the specified number (in this case 1). Of course programatic additions will still be possible.

    0 讨论(0)
提交回复
热议问题