I want use a model to save the system setting for a django app, So I want to limit the model can only have one 开发者_JAVA技巧record, how to do the limit?
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
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.
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
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
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
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.')
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
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.
精彩评论