我如何"分组"在django中使用ForeignKey上的过滤器

时间:2014-06-28 15:38:43

标签: django

我正在尝试根据名称过滤成员并返回成员和附属公司。我的模特是:

class Member( models.Model ):
    first_name = models.CharField( max_length=40, blank=False, null=False )
    last_name = models.CharField( max_length=40, blank=False, null=False )

 class Affiliation( models.Model ):

    member = models.ForeignKey( Member )
    company = models.ForeignKey( Company )
    date_entered = models.DateField( null = False, blank = False )
    date_exited = models.DateField( null = True, blank = True )

 class Company( models.Model ):
    name = models.CharField( max_length = 100 )

然后我想搜索会员,找到名字与某些字符串相匹配的所有人,并将其与他们的公司关系一起显示。因此对于我可以做的搜索:

def member_search(request):

    member_list = Member.objects.filter(
                Q( first_name__icontains=request.POST['q'].lower() )  |
                Q( last_name__icontains=request.POST['q'].lower() ) )

    return render_to_response('member/member_list.html', {'member_list': member_list } )

def member_search2(request):

    affiliation_list = Affiliation.objects.filter(
                Q( member__first_name__icontains=request.POST['q'].lower() )  |
                Q( member__last_name__icontains=request.POST['q'].lower() ) )

    return render_to_response('member/member_list2.html', {'affiliation_list': affiliation_list } )

在第一种情况下,模板将类似于:

<ul>
    {% for member in member_list %}
        <li>
            <a href="/member/{{ member.pk }}">view</a>

            <a href="/member/{{ member.pk }}/update">edit</a>

            {{ member.first_name }} {{ member.last_name }}

            {{ member.affiliation.all ??? }}

        </li>
    {% endfor %}
</ul>

但是我没有看到如何通过Affiliation ForeignKey反转。我怀疑我的过滤器将不得不改变,但我不明白如何。

在第二种情况下它会是这样的:

<ul>
    {% for affiliation in affiliation_list %}
        <li>
            <a href="/member/{{ affiliation.member.pk }}">view</a>

            <a href="/member/{{ affiliation.member.pk }}/update">edit</a>

            {{ affiliation.member.first_name }} {{ affiliation.member.last_name }}

            {{ affiliation.member.company.name }}

        </li>
    {% endfor %}

但如果他们隶属于多家公司,我会为会员获得多行。我查看了汇总,但在这种情况下我不清楚,因为我也想列出这些公司。

我最终想要的是:

member 1 ( company 1 [entry date], company 2 [entry date] )
member 2 ( company 1 [entry date] )
member 3 ( company 2 [entry date] )

这很可能与另一个问题重复,但我没有发现这个问题:-)。这似乎是某人想做的常见事情。

2 个答案:

答案 0 :(得分:2)

以下是您可以尝试的内容:

对于1st,您可以与affiliation_set

建立联系
{{ member.affiliation_set.all }}

对于第二个,您需要获得要显示的值的字典。之后,您可以使用regroup模板过滤器标记来适当地对dict进行分组。示例代码

def member_search2(request):

    affiliation_list = Affiliation.objects.filter( #your filter ...)
                      .values('member__first_name', 'member__last_name', 
                              'company__name', `date_entered') 
      ....

在模板中

{% regroup affiliation_list|dictsort:"member__first_name" by 
       member__first_name as aflist %}

<ul>
{% for af in aflist %}
    <li> {{af.grouper }}
    <ul>
     {%for m in af.list %}
        <li> {{m.company__name}} : {{m.date_entered}} </li>
     {%endfor%}
    </ul>
    </li>
{%endfor%}
</ul>

答案 1 :(得分:1)

第一种方法到目前为止更简单,仍然可以获得所需的输出 - 正如Rohan所示,您只需要为每个成员使用{{ member.affiliation_set.all }}

然而,这将是非常昂贵的,因为每个调用是另一个数据库查询,并且从关联到公司的跳跃每次都是另一个数据库调用。您可以在初始数据库调用中使用prefetch_related来降低成本:

member_list = Member.objects.prefetch_related('affiliation__toppings').filter(...)

要考虑的另一件事是,虽然它对您当前的情况不一定有帮助,但会员和公司之间的关系实际上是多对多关系,Affiliation是直通表。您可以通过明确声明来添加额外的功能而无需更改数据库结构:

class Member( models.Model ):
    ...
    companies = models.ManyToManyField('Company', through='Affiliation')

现在成员对象可以member.companies.all()直接获取所有公司。