Django限制ManytoMany基于选定的FK的查询集

时间:2012-03-13 03:03:29

标签: 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=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中的更改表单中选择的事件相关联的角色,而不是显示Role模型中的所有条目?

4 个答案:

答案 0 :(得分:10)

您可能需要以下内容:

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)

Django documentation for formfield_for_manytomany

答案 1 :(得分:6)

您希望动态过滤roles choices的选项,因此您需要ajax才能执行此任务。

以下是如何使这项工作......

OnChange的{​​p> 1: event通过event_idview发送到您的自定义ajax

2:根据您从Roles请求获得的filter来自event_id模型ajax并返回已过滤的{{1}通过roles进入serializing

3:清除现有的JSON并通过解析roles响应重新填充。

例如: 这是一个JSON jquery示例

javascript:

getJSON

<强>的URL:

$("#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);

<强>的观点:

('^/my-app/my-roles-filter-view/(?P<event_id>\d+)/$','my_view'),

这只是一个使用def my_view(request,event_id): qs = Role.objects.filter(event=event_id).values_list('id') return HttpResponse(simplejson.dumps(qs),mimetype='application/javascript') 的示例,您可以使用任何类型的jquery来实现此目标。

答案 2 :(得分:2)

您需要在管理类中为模型提供自定义formfield_for_foreignkey方法。

这个例子(来自我链接的文档)应该让你入门:

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)

答案 3 :(得分:1)

我相信有两种方法可以解决这个问题:

  1. @Pannu描述的ajax方法

  2. 非ajax方法,可以通过在更改表单之外移动event字段来实现(这意味着将有另一种表单可以更改event)并过滤roles基于当前event。我最近必须解决类似问题,限制基于对象属于特定站点的可用选项。如果您有兴趣,请参阅以下说明和代码:http://source.mihelac.org/2011/09/8/django-sites-ext/

相关问题