动态设置ModelMultipleChoiceField的queryset为自定义记录集
我看到很多关于如何设置ModelMultipleChoiceField来使用自定义查询集的教程,我试过了,它们都能用。不过,它们都用的是同一种方法:查询集只是同一类对象的一个过滤列表。
在我的情况下,我想让后台管理界面显示一个多选表单,而不是用用户名作为文本部分,我想用我账户类中的name
字段。
这是我目前的代码:
# models.py
class Account(models.Model):
name = models.CharField(max_length=128,help_text="A display name that people understand")
user = models.ForeignKey(User, unique=True) # Tied to the User class in settings.py
class Organisation(models.Model):
administrators = models.ManyToManyField(User)
# admin.py
from django.forms import ModelMultipleChoiceField
from django.contrib.auth.models import User
class OrganisationAdminForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
from ethico.accounts.models import Account
self.base_fields["administrators"] = ModelMultipleChoiceField(
queryset=User.objects.all(),
required=False
)
super(OrganisationAdminForm, self).__init__(*args, **kwargs)
class Meta:
model = Organisation
这个可以工作,但我想让上面的queryset
显示一个选择框,里面的内容是Account.name
属性和User.id
属性。可是这样做没有成功:
queryset=Account.objects.all().order_by("name").values_list("user","name")
结果出现了这个错误:
'tuple' object has no attribute 'pk'
我本以为这很简单,但结果花了我几个小时都没找到解决办法。有人能帮我解答一下吗?
3 个回答
0
当你使用查询集时,它需要是一个查询集(QuerySet),而使用values_list会得到一个列表,所以这样是行不通的。
如果你想改变模型的默认显示方式,只需要重写一下__unicode__
这个方法。你可以查看这个链接了解更多信息:http://docs.djangoproject.com/en/dev/ref/models/instances/#unicode
举个例子:
def __unicode__(self):
return u"%s for %s" % (self.name, self.user)
每当你要求Django打印一个模型时,它都会使用__unicode__
这个方法。你可以在命令行中加载一个模型,然后用print my_instance
来测试一下。
0
我从sebpiq那里得到了灵感,终于搞明白了:
class OrganisationAdminForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
from django.forms import MultipleChoiceField
from ethico.accounts.models import Account
self.base_fields["administrators"] = MultipleChoiceField(
choices=tuple([(a.user_id, a.name) for a in Account.objects.all().order_by("name")]),
widget=forms.widgets.SelectMultiple,
required=False
)
super(OrganisationAdminForm, self).__init__(*args, **kwargs)
class Meta:
model = Organisation
class OrganisationAdmin(admin.ModelAdmin):
form = OrganisationAdminForm
admin.site.register(Organisation, OrganisationAdmin)
关键在于完全放弃使用查询集(queryset)。一旦我使用了固定的choices=
参数,所有的东西就都正常运作了。谢谢大家!
1
你可以使用一个自定义的小部件,重写它的 render
方法。下面是我为一个文本框做的:
class UserToAccount(forms.widgets.TextInput):
def render(self, name, value, attrs=None):
if isinstance(value, User) :
value = Account.objects.get(user=value).name
return super (UserToAccount, self).render(name, value, attrs=None)
然后,当然要在你的管理字段中使用 widget
参数,这样才能用上你自定义的小部件。我不确定这个方法是否可以用在 select
上,但你可以试试看。