2011-08-20 62 views
4

我正在运行Django 1.1,无法让我的ManytoManyField工作时使用“limit_choices_to”选项。Django:“limit_choices_to”在ManyToManyField上不起作用

我有两个型号:

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 = { '成员':用户} ---不工作

limit_choices_to = {'member__username':'kyle'} ---这样做可以,但是没用,我只是手动指定用户名

我该如何让用户从当前的“锁定”对象中过滤掉MemberPhoto“成员“的财产呢?

感谢任何人的帮助。

凯尔

回答

9

我发现,实现正是我想要的这个链接的答案: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”开头。实例“,然后是该字段的名称,在上面的示例中它是”用户“)
  6. 最后,确保您的自定义管理员表单和管理模型的类名都匹配。

希望这有助于某人!

+1

你可以使用管理员模式的form_for_foreignkey方法也都做到了。 ;) –

+0

您可能需要将该赋值放在try块中以满足过滤器值尚不存在的创建用例。 –

1

要添加到凯尔的回答,

创建自定义表单是定制多对多场以这种方式的唯一途径。但是,就像我发现的那样,只有在您将更改为时,该方法才有效。 (至少在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中的许多字段定义。它不会必须有空和空白设置为True。请记住,如果您不需要在定义中为它们分配默认值,或者将它们设置在MyModelCreationForm的save()函数中。

希望这会有所帮助! (如果这是完全错误请指正!我需要学习的太多。)

-Thanks