2016-09-09 5 views
4

Я хотел бы управлять некоторыми настройками конфигурации для моего проекта с использованием модели базы данных. Например:Разрешить только один экземпляр модели в Django

class JuicerBaseSettings(models.Model): 
    max_rpm = model.IntegerField(default=10) 
    min_rpm = model.IntegerField(default=0) 

Там должен быть только один экземпляр данной модели:

juicer_base = JuicerBaseSettings() 
juicer_base.save() 

Конечно если кто-то случайно создает новые экземпляры, это не конец света. Я мог бы просто сделать JuicerBaseSettings.objects.all().first(). Однако есть ли способ заблокировать его таким образом, что невозможно создать более одного экземпляра?

Я нашел два связанных вопроса на SO. This answer предлагает использовать сторонние приложения, такие как django-singletons, который, похоже, не активно поддерживается (последнее обновление для git repo - 5 лет назад). Another answer предлагает использовать комбинацию разрешений или OneToOneField. Оба ответа - с 2010-2011 гг.

Учитывая, что с тех пор Django сильно изменилось, существуют ли стандартные способы решения этой проблемы? Или я должен просто использовать .first() и признать, что могут быть дубликаты?

+0

... или вы могли бы сделать '.get (рк = 1)' вместо ... – Bakuriu

+3

это не должно быть в базе данных вообще – e4c5

+1

@ e4c5 разумно, но в небольших проектах я всегда сталкиваюсь с такими настройками сайта, которые позволяют клиенту изменять администратор, что-то вроде номера телефона или другого, связанного с материалом проекта. Возможно, вы указываете на лучший способ –

ответ

6

Вы можете переопределить save способ управления количеством экземпляров:

class JuicerBaseSettings(models.Model): 

    def save(self, *args, **kwargs): 
     if JuicerBaseSettings.objects.exists() and not self.pk: 
     # 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) 
2

я не эксперт, но я думаю, вы можете переписать в модели Save() метод, так что он будет проверять, если там уже был Например, если так сохранить() метод просто возвращает, в противном случае он будет вызывать супер(). сохранить()

+0

Да, я согласен, что это лучший ответ. Перезапишите save() и проверьте, есть ли у него pk. Если это так, то это обновление, и это нормально, если нет ... Затем проверьте дБ, чтобы увидеть, существует ли id = 1 и обрабатывать соответственно. –

3

Вы можете использовать сигнал pre_save

@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

См. Пересмотренный код –

0

Если Ваша модель используется в Джанго-администратора только, вы дополнительно можете установить динамическими добавить разрешения для вашей модели:

# 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