Django模型:如何限制模型中只有一个条目?

20 投票
8 回答
12567 浏览
提问于 2025-04-16 11:09

我想让我的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 吗?

谢谢!

8 个回答

4

可以试试django-constance这个工具。

这里有一些有用的链接:

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

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

16

我觉得最简单的方法是使用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文档

如果你需要更细致的控制,并且想在模型层面上让这个类成为单例,可以看看django-solo。我还遇到过很多其他的单例实现。

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

20

请查看这个关于“在数据库中保存设置”的问题,答案似乎是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应用,因为它正好满足你的需求——提供可供用户编辑的设置——而且不需要你做额外的、不必要的工作。

撰写回答