我正在运行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"成员"属性?
感谢所有能帮忙的人。
凯尔
我找到了一个答案,正好达到了我想要的在这个链接: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)
你只需要修改:
- 你的模型的名字(在上面的例子中它是"lock")
- 模型中ManyToManyField字段的名称(在上面的示例中它是"unlocked_photos")
- 相关模型的名称(在上面的例子中是"MemberPhoto")
- 你想要过滤相关对象的字段名(在上面的例子中是"member")
- 你想要用来过滤相关对象的字段的值(它将以"self.instance."开头,然后是字段的名称,在上面的例子中是"user")
- 最后,确保你的自定义管理表单和管理模型的类名都匹配。
希望这能帮助到一些人!
对于Kyle的回答,
创建自定义表单是以这种方式自定义多对多字段的唯一方法。但是,就像我发现的那样,该方法只有在更改该模型的实例时才有效。(至少在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和blank设置为True。只要记住,如果您不这样做,您将不得不在定义中为它们分配一个默认值,或者在MyModelCreationForm的save()函数中设置它们。
希望这对你有帮助!(如果完全错了,请纠正我!我也需要学习
-谢谢
我花了几个小时试图让它在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)