7

我正在运行 Django 1.1,并且无法让我的 ManytoManyField 工作的“limit_choices_to”选项。

我有两个模型:

class MemberPhoto(ImageModel):
    title       = models.CharField(_('title'), max_length=255, blank=True, null=True)
    caption     = models.CharField(_('caption'), max_length=255, blank=True, null=True)
    date_added  = models.DateTimeField(_('date added'), default=datetime.now, editable=False)
    member      = models.ForeignKey(User)

    def __unicode__(self):
        return u'%s (%s)' % (self.member.username, self.id)

class lock(models.Model):
    user = models.ForeignKey(User, related_name="owner")
    to_user = models.ForeignKey(User, related_name="to_user")
    unlocked_photos = models.ManyToManyField(MemberPhoto, blank=True, null=True, limit_choices_to = {'member':'user'})
    objects = locking_manager()

在第二个模型中,我想确保在 Django 的管理员中,多选字段中出现的唯一“unlocked_photos”(“MemberPhoto”对象)是那些具有“成员”值(用户对象)与“锁定”对象的“用户”(也是一个用户对象)。

我以为我已经遵循了 Django 文档,但它不起作用。我收到以下错误:

TemplateSyntaxError

Caught an exception while rendering: invalid input syntax for integer: "user"

我尝试将“limit_choices_to”更改为:

limit_choices_to = {'member': user} --- 不起作用

limit_choices_to = {'member__username':'kyle'} ---这确实有效,但没用,我只是手动指定用户名

我怎样才能从当前的“锁定”对象中获取用户并以此过滤 MemberPhoto“成员”属性?

感谢任何可以提供帮助的人。

凯尔

4

3 回答 3

14

我在这个链接上找到了一个完全符合我要求的答案:Django MTMField: limit_choices_to = other_ForeignKeyField_on_same_model? ,我在这里为任何有同样问题的人发布我的工作代码。环顾四周,“limit_choices_to”可能根本无法实现我想要的,而自定义管理员使用的表单是要走的路:

from django.contrib import admin
from django import forms
from gayhop.apps.locking.models import lock
from gayhop.apps.photos.models import MemberPhoto

class LockAdminForm(forms.ModelForm):
  class Meta:
    model = lock

  def __init__(self, *args, **kwargs):
    super(LockAdminForm, self).__init__(*args, **kwargs)
    self.fields['unlocked_photos'].queryset = MemberPhoto.objects.filter(member=self.instance.user)


class LockAdmin(admin.ModelAdmin):
  form = LockAdminForm
  filter_horizontal = ('unlocked_photos',)

django.contrib.admin.site.register(lock, LockAdmin)

你需要改变的是:

  1. 您的模型的名称(在上面的示例中它是“锁定”)
  2. 模型中 ManyToManyField 字段的名称(在上面的示例中为“unlocked_photos”)
  3. 相关模型的名称(在上面的示例中为“MemberPhoto”)
  4. 您要过滤相关对象的字段的名称(在上面的示例中它是“成员”)
  5. 您要用来过滤相关对象的字段的值(它将以“self.instance”开头,然后是字段的名称,在上面的示例中为“user”)
  6. 最后确保自定义管理表单和管理模型的类名都匹配。

希望这对某人有帮助!

于 2011-08-21T08:02:11.583 回答
4

为了补充凯尔的答案,

创建自定义表单是以这种方式自定义多对多字段的唯一方法。但是,就像我发现的那样,该方法仅在您更改该模型的实例时才有效。(至少在 Django 1.5 中)

这是因为:self.instance将返回 Model 对象。(我知道疯狂的概念)但是如果您正在创建该模型的实例,由于该模型尚未创建,因此self.instance将返回DoesNotExist异常。

解决此问题的一种方法是创建两种形式:

class MyModelChangeForm(forms.ModelForm):
    class Meta:
        model = MyModel

    def __init__(self, *args, **kwargs):
        super(MyModelChangeForm, self).__init__(*args, **kwargs)
        my_model = self.instance
        self.fields['fields'].queryset = OtherRelatedModel.objects.filter(other_id=my_model.other)


class MyModelCreationForm(forms.ModelForm):
    class Meta:
        model = MyModel

    def save(self, commit=True):
        my_model = super(MyModelCreationForm, self).save(commit=False)
        *** Do other things with the my_model if you want ***
        my_model.save()
        return my_model

然后在 admin.py 中,我们将为我们的创建表单创建一个单独的字段集:

class MyModelAdmin(admin.ModelAdmin):
    filter_horizontal = ('other')
    list_display = ('field1', 'field2' 'field3')

    fieldsets = (
        ("Model info:", {'fields': ("field1", "field2", "field3")}),
        ("More Model info:", {'fields': ("other",)}),
    )
    add_fieldsets = (
        ("Initial info:", {'fields': ("field1", "field2", "field3")}),
    )

    form = MyModelChangeForm
    add_form = MyModelCreationForm

    def get_fieldsets(self, request, obj=None):
        if not obj:
            return self.add_fieldsets
        return super(MyModelAdmin, self).get_fieldsets(request, obj)

    def get_form(self, request, obj=None, **kwargs):
        """
        Use special form during MyModel creation
        """
        defaults = {}
        if obj is None:
            defaults.update({
                'form': self.add_form,
                'fields': admin.util.flatten_fieldsets(self.add_fieldsets),
            })
        defaults.update(kwargs)
        return super(MyModelAdmin, self).get_form(request, obj, **defaults)

请注意,我们必须覆盖 get_form 和 get_fieldsets,如果 obj 为 None(或者换句话说,如果请求是添加模型的实例)它使用 MyModelCreationForm。这与 django 开发人员在 django.contrib.auth.admin 中用于获取自定义 UserCreation 表单和字段集的方法相同。(查看该示例的源代码)

最后,模型在 model.py 中看起来像这样:

class MyModel(models.Model):
    *** field definitions ***
    other = models.ManytoManyField(OtherRelatedModel, null=True, blank=True)

class OtherRelatedModel(models.Model):
    other_id = model.AutoField(primary_key=True)
    *** more field definitions ***

我包含模型的唯一原因是您可以在 MyModel 类中看到多对多字段定义。它不必null 和空白设置为 True。请记住,如果不这样做,则必须在定义中为它们分配默认值,或者在 MyModelCreationForm 的 save() 函数中设置它们。

希望这可以帮助!(如果完全错了请指正!我也需要学习。)

-谢谢

于 2013-07-31T22:14:44.843 回答
1

我花了几个小时试图让它为 Django 3 工作。将它粘贴到这里以供 Django 同胞使用。需要更新的部分是“def init ”部分。

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.fields['unlocked_photos'].queryset = MemberPhoto.objects.filter(member=self.instance.user)
于 2021-05-20T06:02:05.663 回答