在Django中只允许模型的一个示例

vxbzzdmp  于 2023-04-22  发布在  Go
关注(0)|答案(7)|浏览(116)

我想使用数据库模型控制项目的一些配置设置。例如:

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()并接受可能存在重复的问题?

gijlo24d

gijlo24d1#

我在我的管理中做了这样的事情,所以我根本不会去原始的add_new视图,除非已经没有对象存在:

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)

仅在管理员保存时有效

zqdjd7g9

zqdjd7g92#

你可以重写save方法来控制多个示例:

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 be raised in the update of exists model
            raise ValidationError('There is can be only one JuicerBaseSettings instance')
        return super(JuicerBaseSettings, self).save(*args, **kwargs)
cbjzeqam

cbjzeqam3#

您可以重写保存并创建一个类函数JuicerBaseSettings.object()

class JuicerBaseSettings(models.Model):

    @classmethod
    def object(cls):
        return cls._default_manager.all().first() # Since only one item

    def save(self, *args, **kwargs):
        self.pk = self.id = 1
        return super().save(*args, **kwargs)

======
简单地说,使用django_solo
https://github.com/lazybird/django-solo
Snippet Courtsy: django-solo-documentation.

# models.py

from django.db import models
from solo.models import SingletonModel

class SiteConfiguration(SingletonModel):
    site_name = models.CharField(max_length=255, default='Site Name')
    maintenance_mode = models.BooleanField(default=False)

    def __unicode__(self):
        return u"Site Configuration"

    class Meta:
        verbose_name = "Site Configuration"
# admin.py

from django.contrib import admin
from solo.admin import SingletonModelAdmin
from config.models import SiteConfiguration

admin.site.register(SiteConfiguration, SingletonModelAdmin)

# There is only one item in the table, you can get it this way:
from .models import SiteConfiguration
config = SiteConfiguration.objects.get()

# get_solo will create the item if it does not already exist
config = SiteConfiguration.get_solo()
5anewei6

5anewei64#

如果你的模型只在django-admin中使用,你还可以为你的模型设置动态 * 添加权限 *:

# 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
slhcrj9b

slhcrj9b5#

我不是一个Maven,但我猜你可以覆盖模型的保存()方法,这样它就会检查是否已经有一个示例,如果有,save()方法就会返回,否则它会调用super().save()

gdrx4gfi

gdrx4gfi6#

可以使用pre_保存信号

@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')
vwoqyblh

vwoqyblh7#

我有点晚了,但是如果你想确保只创建一个对象的示例,修改模型保存()函数的另一种解决方案是在创建示例时总是指定ID为1-这样,如果示例已经存在,将引发完整性错误。

JuicerBaseSettings.objects.create(id=1)

而不是:

JuicerBaseSettings.objects.create()

它不像修改保存函数那样是一个干净的解决方案,但它仍然可以做到这一点。

相关问题