Allow only one instance of a model in Django

后端 未结 7 1103
南笙
南笙 2020-12-06 00:57

I would like to control some configuration settings for my project using a database model. For example:

class JuicerBaseSettings(models.Model):
    max_rpm =         


        
相关标签:
7条回答
  • 2020-12-06 01:18

    i am not an expert but i guess you can overwrite the model's save() method so that it will check if there has already been a instance , if so the save() method will just return , otherwise it will call the super().save()

    0 讨论(0)
  • 2020-12-06 01:18

    You could use a pre_save signal

    @receiver(pre_save, sender=JuicerBaseSettings)
    def check_no_conflicting_juicer(sender, instance, *args, **kwargs):
        # If another JuicerBaseSettings object exists a ValidationError will be raised
        if JuicerBaseSettings.objects.exclude(pk=instance.pk).exists():
            raise ValidationError('A JuiceBaseSettings object already exists')
    
    0 讨论(0)
  • 2020-12-06 01:21

    I did something like this in my admin so that I won't ever go to original add_new view at all unless there's no object already present:

    def add_view(self, request, form_url='', extra_context=None):
        obj = MyModel.objects.all().first()
        if obj:
            return self.change_view(request, object_id=str(obj.id) if obj else None)
        else:
            return super(type(self), self).add_view(request, form_url, extra_context)
    
    def changelist_view(self, request, extra_context=None):
        return self.add_view(request)
    

    Works only when saving from admin

    0 讨论(0)
  • 2020-12-06 01:28

    If your model is used in django-admin only, you additionally can set dynamic add permission for your model:

    # some imports here
    from django.contrib import admin
    from myapp import models
    
    @admin.register(models.ExampleModel)
    class ExampleModelAdmin(admin.ModelAdmin):
    
        # some code...
    
        def has_add_permission(self, request):
            # check if generally has add permission
            retVal = super().has_add_permission(request)
            # set add permission to False, if object already exists
            if retVal and models.ExampleModel.objects.exists():
                retVal = False
            return retVal
    
    0 讨论(0)
  • 2020-12-06 01:35

    You can override save method to control number of instances:

    class JuicerBaseSettings(models.Model):
    
        def save(self, *args, **kwargs):
            if not self.pk and JuicerBaseSettings.objects.exists():
            # if you'll not check for self.pk 
            # then error will also raised in update of exists model
                raise ValidationError('There is can be only one JuicerBaseSettings instance')
            return super(JuicerBaseSettings, self).save(*args, **kwargs)
    
    0 讨论(0)
  • 2020-12-06 01:38

    I'm a bit late to the party but if you want to ensure that only one instance of an object is created, an alternative solution to modifying a models save() function would be to always specify an ID of 1 when creating an instance - that way, if an instance already exists, an integrity error will be raised. e.g.

    JuicerBaseSettings.objects.create(id=1)
    

    instead of:

    JuicerBaseSettings.objects.create()
    

    It's not as clean of a solution as modifying the save function but it still does the trick.

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