[Solved]-Limit a single record in model for django app?

14đź‘Ť

âś…

An easy way is to use the setting’s name as the primary key in the settings table. There can’t be more than one record with the same primary key, so that will allow both Django and the database to guarantee integrity.

15đź‘Ť

Try this:

class MyModel(models.Model):
    onefield = models.CharField('The field', max_length=100)

class MyModelAdmin(admin.ModelAdmin):
  def has_add_permission(self, request):
    # if there's already an entry, do not allow adding
    count = MyModel.objects.all().count()
    if count == 0:
      return True

    return False
👤mpeirwe

13đź‘Ť

William is right, but I guess this is the best practice

def has_add_permission(self, *args, **kwargs):
    return not MyModel.objects.exists()

As reported in the official Django Documentation:

Note: Don’t use this if all you want to do is determine if at least one result exists.
It’s more efficient to use exists().

https://docs.djangoproject.com/en/dev/ref/models/querysets/#when-querysets-are-evaluated

👤Arch

10đź‘Ť

Overwriting has_add_permission works, but in the given examples it breaks the permissions system in Django(staff without necessary permissions can add settings). Here’s a one that doesn’t break it:

class SettingAdmin(admin.ModelAdmin):
    def has_add_permission(self, request):
        base_add_permission = super(SettingAdmin, self).has_add_permission(request)
        if base_add_permission:
            # if there's already an entry, do not allow adding
            count = Setting.objects.all().count()
            if count == 0:
                return True
        return False

3đź‘Ť

A model with a single allowed row is nothing more than a perverted form of a “persisted object” — maybe even a “persisted singleton”? Don’t do that, that’s not how models work.

Check out https://github.com/danielroseman/django-dbsettings

👤eternicode

2đź‘Ť

It looks like Ali Reza’s answer but you can update the existed records and return the error message to any form that uses this model. I believe it is reliable and much easy to control.

class MyModel(models.Model):
    ...

    def clean(self):
        super().clean()
        if not self.id and MyModel.objects.exists():
            raise ValidationError('You cannot add more somethings.')
👤aysum

0đź‘Ť

The following is a class I have created which can be used as a singleton class.

from django.db import models
class SingletonModel(models.Model):
    class Meta:
        abstract = True

    def save(self, *args, **kwargs):
        self.__class__.objects.exclude(id=self.id).delete()
        super(SingletonModel, self).save(*args, **kwargs)

    @classmethod
    def load(cls):
        try:
            return cls.objects.get()
        except cls.DoesNotExist:
            return cls()

From the above SingletonModel we can create multiple models, all of which will be having only one record

class ProjectSettings(SingletonModel):
    max_tickets = models.IntegerField(default=15)
    min_tickets = models.IntegerField(default=2)
    ...

We can access the only object of the settings model as follows

ProjectSettings.load().max_tickets

It is also possible to register ProjectSettings to django admin

@admin.register(ProjectSettings)
class ProjectSettingsAdmin(admin.ModelAdmin):
    list_display = [field.name for field in ProjectSettings._meta.get_fields()]
    def has_delete_permission(self, request, obj=None):
        # Nobody is allowed to delete
        return False
👤Akhil RS

-1đź‘Ť

You can rewrite the save method on your model. Whenever the user wants to register a new record, you can check the existence then, either save the record or, reject the request.

class MyModel(models.Model):
    title = models.CharField(...)
    body = models.TextField(...)
    
    def save(self, *args, **kwargs):
        if MyModel.objects.exists():
            raise ValueError("This model has already its record.")
        else:
            super().save(*args, **kwargs)

You can also use validators. I prefer to use this method.
Hope you find it useful.

👤Sadra

Leave a comment