【问题标题】:Django models: Only permit one entry in a model?Django模型:模型中只允许一个条目?
【发布时间】:2011-02-03 15:37:31
【问题描述】:

我想通过管理界面配置我的一些 Django 全局设置。

为此,我决定将它们设置为数据库字段,而不是settings.py

这些是我关心的设置:

 class ManagementEmail(models.Model):
    librarian_email = models.EmailField()
    intro_text = models.CharField(max_length=1000)
    signoff_text = models.CharField(max_length=1000)

这些是一次性的全局设置,所以我只希望有一个 librarian_emailintro_text 等在系统中浮动。

有什么方法可以阻止管理员用户在此处添加新记录,不阻止他们编辑现有记录

我想我可以通过为此模型编写自定义管理模板来做到这一点,但我想知道是否有更简洁的方法来配置它。

我可以使用 class 以外的其他名称吗?

谢谢!

【问题讨论】:

    标签: python python-3.x django django-models django-admin


    【解决方案1】:

    请看this question on "keep[ing] settings in database",那里的答案似乎是django-dbsettings

    更新

    刚刚想到另一个选择:您可以创建以下模型:

    from django.contrib.sites.models import Site
    
    class ManagementEmail(models.Model):
        site = models.OneToOneField(Site)
        librarian_email = models.EmailField()
        intro_text = models.CharField(max_length=1000)
        signoff_text = models.CharField(max_length=1000)
    

    由于 OneToOneField 字段,每个站点只能有一个 ManagementEmail 记录。然后,只需确保您使用的是网站,然后您就可以提取设置:

    from django.contrib.sites.models import Site
    managementemail = Site.objects.get_current().managementemail
    

    请注意,其他人告诉你的都是真的;如果您的目标是存储设置,则将它们作为字段一一添加到模型中并不是最好的实现。随着时间的推移添加设置将是一件令人头疼的事情:您必须将字段添加到模型中,更新数据库结构,并修改调用该设置的代码。

    这就是我推荐使用我上面提到的 django 应用程序的原因,因为它完全符合你的要求——提供用户可编辑的设置——而不会让你做任何额外的、不必要的工作。

    【讨论】:

    • 谢谢。鉴于开发人员在这里的评论,我对 django-dbsettings 有点警惕:chicagodjango.com/blog/django-settings-database
    • 听起来他对 django-dbsettings 的抱怨不适用于您的情况。您正在定义代码中的所有设置。我绝对不建议您编写自己的单例来处理这个问题。
    • 开发者的评论说他不再维护它让我担心。确实,当我尝试安装它时,我开始收到有关 newforms 的错误,这表明它已经过时了...将尝试您的替代建议,谢谢!
    【解决方案2】:

    我认为最简单的方法是使用 ModelAdmin 的 has_add_permissions 函数:

    class ContactUsAdmin(admin.ModelAdmin):
        form = ContactUsForm
    
        def has_add_permission(self, request):
            return False if self.model.objects.count() > 0 else super().has_add_permission(request)
    

    您可以将上面设置为您喜欢的任何数字,请参阅django docs

    如果您需要比这更多的粒度,并在模型级别使类成为单例,请参阅django-solo。我也遇到过很多单例实现。

    对于 StackedInline,您可以使用 max_num = 1。

    【讨论】:

    • 我认为return False if self.model.objects.count() > 0 else super().has_add_permission(request) 会更好地尊重权限管理规则。
    • 删除单个条目会有错误,这样效果更好if self.model.objects.count() > 0: return False else: return True
    • 如果返回0,它将评估super().has_add_permission(request),如果没有权限则返回错误,听起来不错。
    【解决方案3】:

    试试 django-constance。 以下是一些有用的链接:

    https://github.com/jezdez/django-constance

    http://django-constance.readthedocs.org/en/latest/

    【讨论】:

    • 此问题中提到的其他库似乎不再受支持,但截至此评论,Constance 仍然很强大。
    【解决方案4】:

    我会从 wordpress 中取出一个页面并创建一个支持设置的模型。

    class Settings(models.Model):
        option_name = models.CharField(max_length=1000)
        option_value = models.CharField(max_length=25000)
        option_meta = models.CharField(max_length=1000)
    

    然后您可以将对象腌制(序列化)到字段中,然后就可以了。

    构建一个小api,你可以像wordpress和call一样狡猾。 AdminOptions.get_option(opt_name)

    然后您可以将自定义设置加载到运行时,保持 settings.py 模块独立但相等。写这个的好地方是__init__.py 文件。

    【讨论】:

      【解决方案5】:

      只需设置一个GlobalSettings 应用程序或带有键和值字段的东西。

      您可以通过不授予管理员用户编辑 GlobalSettings 应用程序的权限来轻松阻止管理员用户更改值。

      class GlobalSettingsManager(models.Manager):
            def get_setting(self, key):
                try:
                    setting = GlobalSettings.objects.get(key=key)
                except:
                    raise MyExceptionOrWhatever
                return setting
      
      class GlobalSettings(models.Model):
            key = models.CharField(unique=True, max_length=255)
            value = models.CharField(max_length=255)
      
            objects = GlobalSettingsManager()
      
      >>> APP_SETTING = GlobalSettings.objects.get_setting('APP_SETTING')
      

      有这方面的应用程序,但我更喜欢查看它们并自己编写。

      【讨论】:

      • 是的,我也更喜欢数据库中的东西而不是应用程序。但是:如问题中所述,管理员用户应该能够编辑现有字段 - 只是无法添加新项目。有什么想法吗?
      【解决方案6】:

      您可以通过在您的管理类上重写此方法来阻止用户添加/删除对象:

      ModelAdmin.has_add_permission(self, request)

      ModelAdmin.has_delete_permission(self, request, obj=None)

      【讨论】:

        【解决方案7】:

        修改@radtek 答案以防止在只剩下一个条目时删除

        class SendgridEmailQuotaAdmin(admin.ModelAdmin):
            list_display = ('quota','used')
            def has_add_permission(self, request):
                return False if self.model.objects.count() > 0 else True
            def has_delete_permission(self, request, obj=None):
                return False if self.model.objects.count() <= 1 else True
            def get_actions(self, request):
                actions = super(SendgridEmailQuotaAdmin, self).get_actions(request)
                if(self.model.objects.count() <= 1):
                    del actions['delete_selected']
                return actions
        

        【讨论】:

          【解决方案8】:

          我遇到了与原始海报描述的基本相同的问题,并且可以通过覆盖 modelAdmin 类轻松解决。 admin.py 文件中与此类似的内容很容易阻止添加新对象,但允许编辑当前对象:

          class TitleAdmin(admin.ModelAdmin):
              def has_delete_permission(self, request, obj=TestModel.title):
                  return False
          
              def has_add_permission(self, request):
                  return False
          
              def has_change_permission(self, request, obj=TestModel.title):
                  return True
          

          这不会阻止用户发布编辑数据的表单,但会阻止管理站点中发生任何事情。根据您是否认为有必要,您可以使用最少的编码启用删除和添加记录。

          【讨论】:

            【解决方案9】:

            2022 年 3 月更新:

            最简单最好的方法是使用"has_add_permission()"

            “models.py”

            from django.db import models
            
            class ManagementEmail(models.Model):
                librarian_email = models.EmailField()
                intro_text = models.CharField(max_length=1000)
                signoff_text = models.CharField(max_length=1000)
            

            “admin.py”

            from django.contrib import admin
            from .models import ManagementEmail
            
            @admin.register(ManagementEmail)
            class ManagementEmailAdmin(admin.ModelAdmin):
                def has_add_permission(self, request): # Here
                    return not ManagementEmail.objects.exists()
            

            您可以查看有关has_add_permission() 的文档。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2018-07-18
              • 2017-06-04
              • 2020-02-07
              • 1970-01-01
              • 2014-02-20
              • 2020-10-03
              • 1970-01-01
              相关资源
              最近更新 更多