考虑这个models.py:
from django.db import models
from django.db.models import signals
class CannotRemoveLastAdmin(Exception):
def __init__(self, env):
super(CannotRemoveLastAdmin, self).__init__(
u'Cannot remove the last admin of environment "%s"' % env)
class Environment(models.Model):
name = models.CharField(max_length=100, unique=True)
users = models.ManyToManyField('auth.user', through='UserEnvironment')
def __unicode__(self):
return self.name
class UserEnvironment(models.Model):
environment = models.ForeignKey('Environment')
user = models.ForeignKey('auth.user')
is_admin = models.BooleanField()
default = models.BooleanField()
creation_datetime = models.DateTimeField(auto_now_add=True)
def admin_required_delete(sender, instance, **kwargs):
if not instance.is_admin:
return
admins = UserEnvironment.objects.filter(environment=instance.environment,
is_admin=True).exclude(pk=instance.pk).count()
if not admins:
raise CannotRemoveLastAdmin(instance)
signals.pre_delete.connect(admin_required_delete, sender=UserEnvironment)
我无法删除任何环境,因为发送了UserEnvironment pre_save信号:
<<< jpic@zen!7953 G:delete_with_m2m_through jpic_so_env
>>> ./manage.py shell_plus
From 'admin' autoload: LogEntry
From 'auth' autoload: Permission, Group, User
From 'contenttypes' autoload: ContentType
From 'sessions' autoload: Session
From 'sites' autoload: Site
From 'account' autoload: Account, SignupCode, SignupCodeResult, EmailAddress, EmailConfirmation, AccountDeletion
From 'profiles' autoload: Profile
From 'test_app' autoload: Environment, UserEnvironment
Python 2.7.3 (default, Apr 24 2012, 00:06:13)
[GCC 4.7.0 20120414 (prerelease)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> Environment.objects.all().delete()
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/tmp/jpic_so_env/lib/python2.7/site-packages/django/db/models/query.py", line 514, in delete
collector.delete()
File "/tmp/jpic_so_env/lib/python2.7/site-packages/django/db/models/deletion.py", line 61, in decorated
func(self, *args, **kwargs)
File "/tmp/jpic_so_env/lib/python2.7/site-packages/django/db/models/deletion.py", line 239, in delete
sender=model, instance=obj, using=self.using
File "/tmp/jpic_so_env/lib/python2.7/site-packages/django/dispatch/dispatcher.py", line 172, in send
response = receiver(signal=self, sender=sender, **named)
File "/tmp/so_test_project/test_app/models.py", line 35, in admin_required_delete
raise CannotRemoveLastAdmin(instance)
CannotRemoveLastAdmin: Cannot remove the last admin of environment "UserEnvironment object"
>>>
我确实希望在删除环境时保留此异常,CannotRemoveLastAdmin,除。
您可以通过粘贴安全地重现此问题:
cd /tmp
rm -rf jpic_so_env jpic_so_test_project
virtualenv jpic_so_env
source jpic_so_env/bin/activate
git clone https://github.com/jpic/django_test.git -b delete_with_m2m_through jpic_so_test_project
cd so_test_project
git checkout delete_with_m2m_through
pip install django
pip install -r requirements.txt
./manage.py shell_plus
并运行:
Environment.objects.all().delete()
仅在运行测试时才需要这样做,因为setUp()
问题Environment.objects.all().delete()
,所以我宁愿不要使用像marked_for_delete
这样的额外字段来混淆我的模型......
快乐的黑客行为,并提前感谢您的帮助。
答案 0 :(得分:0)
如果要在模型上强制执行此类策略,则必须以某种方式标记环境,否则将永远无法删除。
如果您真的不喜欢marked_for_delete选项,则可能会滥用环境名称字段(通过设置特殊值)作为变通方法。这对我来说似乎更加骇人听闻。