Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在Django中只允许一个模型实例_Python_Django - Fatal编程技术网

Python 在Django中只允许一个模型实例

Python 在Django中只允许一个模型实例,python,django,Python,Django,我想使用数据库模型控制项目的一些配置设置。例如: class JuicerBaseSettings(models.Model): max_rpm = model.IntegerField(default=10) min_rpm = model.IntegerField(default=0) 此模型只能有一个实例: juicer_base = JuicerBaseSettings() juicer_base.save() 当然,如果有人意外地创建了一个新实例,这并不是世界末日。

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

class JuicerBaseSettings(models.Model):
    max_rpm = model.IntegerField(default=10)
    min_rpm = model.IntegerField(default=0)
此模型只能有一个实例:

juicer_base = JuicerBaseSettings()
juicer_base.save()
当然,如果有人意外地创建了一个新实例,这并不是世界末日。我可以只做
juicerbasettings.objects.all().first()
。但是,有没有一种方法可以锁定它,这样就不可能创建多个实例

我发现了两个相关的问题。建议使用第三方应用程序,如
django singletons
,该应用程序似乎没有得到积极维护(上次更新git repo是在5年前)。建议结合使用权限或
OneToOneField
。这两个答案都来自2010-2011年


鉴于Django自那以后发生了很大变化,有没有标准的方法来解决这个问题?或者我应该使用
.first()
并接受可能存在重复项吗?

您可以覆盖
保存
方法来控制实例数:

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)

我不是专家,但我想您可以覆盖模型的save()方法,以便它检查是否已经存在实例,如果已经存在实例,save()方法将返回,否则它将调用super()。save()

您可以使用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')

如果您的模型仅在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

我来晚了一点,但如果您想确保只创建一个对象实例,修改models save()函数的另一种解决方案是在创建实例时始终指定ID为1,这样,如果实例已经存在,则会引发完整性错误。 e、 g

而不是:

JuicerBaseSettings.objects.create()

它的解决方案不如修改save函数干净,但它仍然起作用。

您可以覆盖save并创建一个类函数
juicerbasettings.object()

================或=============

只需使用
django\u solo

科特西片段:django solo文档。

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

我在我的管理员中做了类似的操作,这样我就永远不会进入原始的
add\u new
视图,除非已经没有对象了:

def add_视图(self,request,form_url='',extra_context=None):
obj=MyModel.objects.all().first()
如果obj:
返回self.change\u视图(如果obj-else-None,则请求,object\u id=str(obj.id)
其他:
返回super(类型(self)、self)。添加视图(请求、表单url、额外上下文)
def变更列表视图(自身、请求、额外上下文=无):
返回self.add_视图(请求)

仅在从管理员保存时有效

。。。或者您可以改为执行
.get(pk=1)
操作……此时数据库中不应包含此项all@e4c5这是合理的,但在小项目中,我总是要面对这样的网站设置,允许客户更改管理,比如电话号码或其他与项目相关的内容。也许你指的是更好的way@e4c5你能推荐一个替代方案吗?在数据库中使用它的一个好处是,我可以通过RESTAPI公开它。这正是你需要的是的,我同意这是最好的答案。覆盖save()并检查它是否有主键。如果是的话,那就是一个更新,如果不是的话,那也没关系。。。然后检查数据库,看看id=1是否存在,并进行相应的处理。这是非常好和有效的。但是,super需要类名和self作为参数(super(ExampleModelAdmin,self)。拥有django_solo的添加权限(request),可以以干净的方式进行添加
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)
# 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()