【问题标题】:Django Limit ManytoMany queryset based on selected FKDjango 根据选定的 FK 限制多对多查询集
【发布时间】:2012-03-29 11:42:31
【问题描述】:

我有一个看起来像这样的模型:

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

【问题讨论】:

    标签: django django-admin


    【解决方案1】:

    您可能想要以下内容:

    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

    【讨论】:

    • 问题清楚地表明“我怎样才能只显示与我在更改表单选择的事件相关的角色”这绝对是动态完成(ajax)。您的解决方案是静态的。
    • 啊,我错过了那个细节,谢谢。我不一定将其称为 static 解决方案,因为它会根据加载的对象和在数据库中选择的事件而有所不同,但我认为您是对的,这实际上并不能解决问题 正在呈现 :)
    【解决方案2】:

    您想要动态过滤roles choices 的选择,因此您需要ajax 来执行此任务。

    您可以通过以下方式完成这项工作..

    1: OnChange 中的eventevent_id 通过ajax 发送到您的自定义view

    2:Roles模型filter基于你从ajax请求得到的event_id并将serializing过滤的roles返回到JSON .

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

    例如: 这是jquerygetJSON 示例

    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);
    

    网址:

    ('^/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 的示例,您可以使用任何类型的ajax 并实现此目的。

    【讨论】:

    • 解决方案需要 java 脚本,因为当他在表单中选择 event 时,必须动态过滤角色(无需按下按钮,提交整个表单,然后返回过滤后的选项)因此ajax 是要走的路。
    • 是的,如果你想让它在你改变小部件中的选定事件时在浏览器中改变,那么你当然需要使用Javascript。对不起,我看错了。
    【解决方案3】:

    您需要在模型的管理类中提供自定义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)
    

    【讨论】:

    • 这将在加载时完成,它不是动态的。我相信choices 必须是动态的filtered。问题似乎就是这样。
    • @Pannu:不,这实际上接近于正确的解决方案,但要解决这个特殊问题,您需要访问相关的 Invite 实例。
    【解决方案4】:

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

    1. @Pannu 描述的 ajax 方法

    2. 非ajax方法,可以通过将event字段移到更改表单之外(这意味着将有另一个表单更改event)并根据当前event过滤roles来实现.我最近不得不解决类似的问题,根据对象对特定站点的归属来限制可用选项。这是描述和代码,如果您有兴趣:http://source.mihelac.org/2011/09/8/django-sites-ext/

    【讨论】:

      猜你喜欢
      • 2020-01-24
      • 2021-11-14
      • 2022-11-10
      • 1970-01-01
      • 2018-01-05
      • 2011-04-07
      • 1970-01-01
      • 2021-03-23
      • 1970-01-01
      相关资源
      最近更新 更多