Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django models: Only permit one entry in a model?

Tags:

I want to make some of my Django global settings configurable through the admin interface.

To that end, I've decided to set them as database fields, rather than in settings.py.

These are the settings I care about:

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

These are one-off global settings, so I only ever want there to be a single librarian_email, intro_text etc floating around the system.

Is there a way I can prevent admin users from adding new records here, without preventing them from editing the existing record?

I guess I can do this by writing a custom admin template for this model, but I'd like to know if there's a neater way to configure this.

Could I use something other than class, for example?

Thanks!

like image 371
AP257 Avatar asked Feb 03 '11 15:02

AP257


2 Answers

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.

like image 176
Jordan Reiter Avatar answered Sep 23 '22 03:09

Jordan Reiter


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.

like image 37
radtek Avatar answered Sep 25 '22 03:09

radtek