Ограничить количество экземпляров модели - django
У меня есть модель, из которой я хочу только создать один экземпляр, и больше не нужно допускать экземпляры.
Возможно ли это? У меня такое чувство, что я видел это где-то, но, к сожалению, я не могу его найти.
EDIT:
Мне нужно это для глупо простой CMS. У меня есть абстрактный класс, для которого наследуются классы FrontPage и Page. Я хочу только создать один объект главной страницы.
Различие между объектом FrontPage и объектами "Страница" заключается в том, что они должны иметь несколько разные поля и шаблоны, и, как упоминалось, нужно создать только один FrontPage.
Ответы
Ответ 1
Я хотел сделать что-то подобное себе и обнаружил, что проверка модели Django обеспечила удобный крючок для принудительного применения:
from django.db import models
from django.core.exceptions import ValidationError
def validate_only_one_instance(obj):
model = obj.__class__
if (model.objects.count() > 0 and
obj.id != model.objects.get().id):
raise ValidationError("Can only create 1 %s instance" % model.__name__)
class Example(models.Model):
def clean(self):
validate_only_one_instance(self)
Это не только предотвращает создание новых экземпляров, но и пользовательский интерфейс администратора Django будет сообщать, что создание завершилось неудачно, и причина в том, что "может создать только один пример экземпляра" (тогда как метод раннего возврата в документах не дает никаких указаний почему сохранение не сработало).
Ответ 2
Если вы просто хотите запретить пользователям, использующим административный интерфейс, создавать дополнительные объекты модели, вы можете изменить метод has_add_permission модели ModelAdmin:
# admin.py
from django.contrib import admin
from example.models import Example
class ExampleAdmin(admin.ModelAdmin):
def has_add_permission(self, request):
num_objects = self.model.objects.count()
if num_objects >= 1:
return False
else:
return True
admin.site.register(Example, ExampleAdmin)
Это приведет к удалению кнопки "добавить" в административном интерфейсе, позволяющей пользователям даже пытаться создать больше, чем указанное число (в данном случае 1). Конечно, программные дополнения будут по-прежнему возможны.
Ответ 3
Вы можете сделать что-то вроде этого из документации Django:
class ModelWithOnlyOneInstance(models.Model):
... fields ...
def save(self, *args, **kwargs):
if ModelWithOnlyOneInstance.objects.count() > 1:
return
super(ModelWithOnlyOneInstance, self).save(*args, **kwargs)
Ответ 4
@ncoghlan ваше решение работает нормально, но не очень удобно: пользователь имеет доступ к форме создания и будет думать, что он/она может использовать его, даже если он/она никогда не сможет его сохранить.
Фактически возможно объединить его с решением Брендана, которое скроет кнопку "Добавить". Использование Mixins для простого повторного использования:
# models.py
from django.db import models
from django.core.exceptions import ValidationError
class SingleInstanceMixin(object):
"""Makes sure that no more than one instance of a given model is created."""
def clean(self):
model = self.__class__
if (model.objects.count() > 0 and self.id != model.objects.get().id):
raise ValidationError("Can only create 1 %s instance" % model.__name__)
super(SingleInstanceMixin, self).clean()
class Example(SingleInstanceMixin, models.Model):
pass
# admin.py
from django.contrib import admin
from example.models import Example
class SingleInstanceAdminMixin(object):
"""Hides the "Add" button when there is already an instance."""
def has_add_permission(self, request):
num_objects = self.model.objects.count()
if num_objects >= 1:
return False
return super(SingleInstanceAdminMixin, self).has_add_permission(request)
class ExampleAdmin(SingleInstanceAdminMixin, admin.ModelAdmin):
model = Example
Ответ 5
Я бы переопределил метод create() в менеджере по умолчанию, но, как указано выше, это не гарантирует ничего в многопоточной среде.