在我刚刚完成的项目中,我有一个类似这样的系统。将这些组合在一起需要做很多工作,但以下是我必须使我的系统正常工作的一些组件:
您需要一种方法来定义编辑器和主管。可以做到这一点的三种方法是:1.)通过定义主管的 M2M 字段[并假设其他所有有权读/写的人都是编辑器],2.)创建 2 个从用户继承的新用户模型 [可能比必要的工作更多] 或 3.) 使用 django.auth 拥有 UserProfile 类的能力。方法#1 可能是最合理的。
一旦您可以确定用户是什么类型,您就需要一种方法来普遍地强制执行您正在寻找的授权。我认为这里最好的路线可能是通用管理模型。
最后,您需要某种类型的“父”模型,该模型将持有任何需要审核的权限。例如,如果您有一个 Blog 模型和 BlogPost 模型(假设同一站点中有多个博客),那么 Blog 是父模型(它可以拥有谁批准什么的权限)。但是,如果您有一个博客并且没有 BlogPost 的父模型,我们将需要一些地方来存储权限。我发现ContentType 在这里效果很好。
以下是代码中的一些想法(未经测试,比实际更具概念性)。
制作一个名为 'moderated' 的新应用,用于保存我们的通用内容。
moderated.models.py
class ModeratedModelParent(models.Model):
"""Class to govern rules for a given model"""
content_type = models.OneToOneField(ContentType)
can_approve = models.ManyToManyField(User)
class ModeratedModel(models.Model):
"""Class to implement a model that is moderated by a supervisor"""
is_approved = models.BooleanField(default=False)
def get_parent_instance(self):
"""
If the model already has a parent, override to return the parent's type
For example, for a BlogPost model it could return self.parent_blog
"""
# Get self's ContentType then return ModeratedModelParent for that type
self_content_type = ContentType.objects.get_for_model(self)
try:
return ModeratedModelParent.objects.get(content_type=self_content_type)
except:
# Create it if it doesn't already exist...
return ModeratedModelParent.objects.create(content_type=self_content_type).save()
class Meta:
abstract = True
所以现在我们应该有一个通用的、可重用的代码,我们可以识别给定模型的权限(我们将通过它的内容类型来识别模型)。
接下来,我们可以再次通过通用模型在管理员中实施我们的政策:
moderated.admin.py
class ModeratedModelAdmin(admin.ModelAdmin):
# Save our request object for later
def __call__(self, request, url):
self.request = request
return super(ModeratedModelAdmin, self).__call__(request, url)
# Adjust our 'is_approved' widget based on the parent permissions
def formfield_for_dbfield(self, db_field, **kwargs):
if db_field.name == 'is_approved':
if not self.request.user in self.get_parent_instance().can_approve.all():
kwargs['widget'] = forms.CheckboxInput(attrs={ 'disabled':'disabled' })
# Enforce our "unapproved" policy on saves
def save_model(self, *args, **kwargs):
if not self.request.user in self.get_parent_instance().can_approve.all():
self.is_approved = False
return super(ModeratedModelAdmin, self).save_model(*args, **kwargs)
一旦这些设置和工作,我们可以在许多模型中重复使用它们,正如我发现的那样,一旦你为这样的东西添加结构化权限,你很容易想要它用于许多其他事情。
假设你有一个新闻模型,你只需要让它继承我们刚刚制作的模型,你就很好了。
# in your app's models.py
class NewsItem(ModeratedModel):
title = models.CharField(max_length=200)
text = models.TextField()
# in your app's admin.py
class NewsItemAdmin(ModeratedModelAdmin):
pass
admin.site.register(NewsItem, NewsItemAdmin)
我确信我在那里犯了一些代码错误和错误,但希望这可以给你一些想法,作为你决定实施的任何事情的跳板。
您需要做的最后一件事是对is_approved 项目实施过滤,我将留给您。 (即,您不希望在新闻部分列出未经批准的项目,对吧?)