[Django]-Django models: Only permit one entry in a model?

20👍

Please see this question on “keep[ing] settings in database”, where the answer seems to be django-dbsettings

Update

Just thought of another option: you can create the following model:

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)

Because of the OneToOneField field, you can only have one ManagementEmail record per site. Then, just make sure you’re using sites and then you can pull the settings thusly:

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

Note that what everyone else is telling you is true; if your goal is to store settings, adding them one by one as fields to a model is not the best implementation. Adding settings over time is going to be a headache: you have to add the field to your model, update the database structure, and modify the code that is calling that setting.

That’s why I’d recommend using the django app I mentioned above, since it does exactly what you want — provide for user-editable settings — without making you do any extra, unnecessary work.

16👍

I think the easiest way you can do this is using has_add_permissions function of the ModelAdmin:

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)

You can set the above to be any number you like, see the django docs.

If you need more granularity than that, and make the class a singleton at the model level, see django-solo. There are many singleton implementations also that I came across.

For StackedInline, you can use max_num = 1.

👤radtek

4👍

3👍

I’d take a page out of wordpress and create a Model that support settings.

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)

Then you can just pickle (serialize) objects into the fields and you’ll be solid.

Build a little api, and you can be as crafty as wordpress and call. AdminOptions.get_option(opt_name)

Then you can just load the custom settings into the runtime, keeping the settings.py module separate, but equal. A good place to write this would be in an __init__.py file.

2👍

Just set up an GlobalSettings app or something with a Key and Value field.

You could easily prevent admin users from changing values by not giving them permission to edit the GlobalSettings app.

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

There are apps for this but I prefer looking at them and writing my own.

2👍

You can prevent users from adding/deleting an object by overriding this method on your admin class:

ModelAdmin.has_add_permission(self, request)

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

👤Ski

0👍

Modification of @radtek answer to prevent deleting if only one entry is left

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

0👍

I had basically the same problem as the original poster describes, and it’s easily fixed by overriding modelAdmin classes. Something similar to this in an admin.py file easily prevents adding a new object but allows editing the current one:

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

This doesn’t prevent a user from posting a form that edits data, but keeps things from happening in the Admin site. Depending on whether or not you feel it’s necessary for your needs you can enable deletion and addition of a record with a minimum of coding.

Leave a comment