Django限制基于选定FK的多个查询集
我有一个这样的模型:Django限制基于选定FK的多个查询集,django,django-admin,Django,Django Admin,我有一个这样的模型: class Invite(models.Model): user = models.ForeignKey(User) event = models.ForeignKey(Event) roles = models.ManyToManyField(Role, blank=True, null=True) sent = models.BooleanField("Invite Sent", default=False, editable=Fals
class Invite(models.Model):
user = models.ForeignKey(User)
event = models.ForeignKey(Event)
roles = models.ManyToManyField(Role, blank=True, null=True)
sent = models.BooleanField("Invite Sent", default=False, editable=False)
created = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return u"%s" % self.user
class Meta:
unique_together =(('user','event'),)
class Role(models.Model):
"""
This associates a user's role to an event
"""
event = models.ForeignKey(Event, related_name="roles")
roletype = models.ForeignKey(RoleType)
profiles = models.ManyToManyField(Profile, related_name="roles",
blank=True, null=True)
modified = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
因此,每当创建一个新事件时,都会创建一组角色。在Invite模型中,如何在Django Admin中仅显示与我在更改表单中选择的事件相关联的角色,而不显示角色模型中的所有条目?您需要在管理类中为模型提供自定义方法 这个示例(来自我链接的文档)应该让您开始:
class MyModelAdmin(admin.ModelAdmin):
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "car":
kwargs["queryset"] = Car.objects.filter(owner=request.user)
return super(MyModelAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
您希望动态筛选
角色的选择
选择
,因此需要ajax
来执行此任务
下面是你如何使这项工作成功的方法
1:一旦更改事件
,通过ajax
将事件id
发送到您的自定义视图
2:根据从ajax
请求获得的事件id
从角色模型过滤器
,并通过序列化到JSON
返回过滤后的角色
3:清除现有的角色
并通过JSON
响应解析重新填充
例如:
这是一个jquery
getJSON
示例
javascript:
$("#event").change(function (){
var event_id = $(this).val();
$.getJSON("/my-app/my-roles-filter-view/"+ event_id +"/",function(data){
var roles_dd = $("#roles");
$('#event >option').remove();
$.each(data, function(index,value) {
roles_dd.append($("<option />").val(value).text(value));
});
})(django.jquery);
这只是一个使用jquery
的示例,您可以使用任何类型的ajax
来实现这一点。您可能需要以下内容:
class InviteAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
self.instance = obj # Capture instance before the form gets generated
return super(InviteAdmin, self).get_form(request, obj=obj, **kwargs)
def formfield_for_manytomany(self, db_field, request=None, **kwargs):
if db_field.name == 'role' and self.instance:
# restrict role queryset to those related to this instance:
kwargs['queryset'] = self.instance.event.roles.all()
return super(InviteAdmin, self).formfield_for_manytomany(
db_field, request=request, **kwargs)
我认为有两种方法可以解决这个问题:
@Pannu描述的ajax方法
非ajax方法,可通过将事件
字段移动到更改表单之外(这意味着将有另一个表单更改事件
)并基于当前事件
过滤角色
来实现。最近,我不得不解决类似的问题,根据对象对特定站点的归属限制可用选项。以下是说明和代码,如果您感兴趣:
这将在加载时完成,并且不是动态的。我相信选择
必须动态地过滤
。这就是问题所在。@Pannu:不,这实际上接近正确的解决方案,但要解决这个特定问题,您需要访问相关的Invite实例。问题清楚地表明“如何在更改表单中仅显示与我选择的事件相关联的角色”,这是肯定要做的(ajax)。您的解决方案是静态的。啊,我错过了这个细节,谢谢。我不一定把它称为静态解决方案,因为它根据加载的对象和数据库中选择的事件而变化,但我认为您是对的,这并不能解决实际出现的问题:)解决方案需要java脚本,因为当他在表单中选择事件时,角色必须动态过滤(无需按下按钮,提交整个表单,然后返回过滤后的选项),因此ajax
是一种方法。是的,如果您希望在更改小部件中的选定事件时在浏览器中更改它,那么您当然需要使用Javascript。对不起,我看错了。
def my_view(request,event_id):
qs = Role.objects.filter(event=event_id).values_list('id')
return HttpResponse(simplejson.dumps(qs),mimetype='application/javascript')
class InviteAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
self.instance = obj # Capture instance before the form gets generated
return super(InviteAdmin, self).get_form(request, obj=obj, **kwargs)
def formfield_for_manytomany(self, db_field, request=None, **kwargs):
if db_field.name == 'role' and self.instance:
# restrict role queryset to those related to this instance:
kwargs['queryset'] = self.instance.event.roles.all()
return super(InviteAdmin, self).formfield_for_manytomany(
db_field, request=request, **kwargs)