Django admin中的unique_together和隐式填充字段

时间:2012-05-03 07:52:05

标签: django admin unique-constraint autofill

假设我正在编写一个多博客应用程序,我希望每个作者都能为他们的文章使用独特的标题(但每个用户都是唯一的,而不是全球唯一的):

class Article(models.Model):
    author = models.ForeignKey('auth.User')
    title = models.CharField(max_length=255)
    #[...]

    class Meta:
        unique_together = (('title', 'owner'),)

现在,我希望应用程序自动填写作者字段:

class ArticleAdmin(ModelAdmin):

    exclude = ('owner',)

    def save_model(self, request, obj, form, change):
        if not change:
            obj.owner = request.user
        obj.save()

实际上这不起作用:如果我尝试使用现有的作者 - 标题组合创建新文章,Django将不会检查唯一性(因为作者被排除在表单之外)并且当它出现时我将得到IntegrityError数据库。

我想过为Article类添加一个干净的方法:

def clean(self):
    if Article.objects.filter(title=self.title, owner=self.owner).exists():
        raise ValidationError(u"...")

但似乎Article.clean()在 ArticleAdmin.save_model()之前被称为,所以这不起作用。

这个问题的

Several variants已经在这里提出过,但是没有一个解决方案对我有用:

  • 我不能使用Form.clean()或其他没有可用请求的表单方法,因为我需要request.user。
  • 出于同样的原因,无法进行模型级验证。
  • 有些答案指的是基于类的视图或自定义视图,但我想留在Django管理员的上下文中。

如果不重写一半管理应用程序,我怎么能这样做呢?

1 个答案:

答案 0 :(得分:0)

您正在寻找一种方法将request带到ModelAdmin的自定义表单中,实际上是:

from django.core.exceptions import ValidationError

def make_add_form(request, base_form):
    class ArticleForm(base_form):
        def clean(self):
            if Article.objects.filter(title=self.cleaned_data['title'], owner=request.user).exists():
                raise ValidationError(u"...")
            return self.cleaned_data

        def save(self, commit=False):
            self.instance.owner = request.user
            return super(ArticleForm, self).save(commit=commit)

    return ArticleForm


class ArticleAdmin(admin.ModelAdmin):
    exclude = ('owner',)

    def get_form(self, request, obj=None, **kwargs):
        if obj is None: # add
            kwargs['form'] = make_add_form(request, self.form)
        return super(ArticleAdmin, self).get_form(request, obj, **kwargs)