You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django Tables2结合Slug实现外键链接层级下钻的开发问题

Django 层级应收款汇总表下钻链接实现问题

需求背景

我正在开发带有可点击跳转链接的层级数据汇总表,实现从上层数据向下钻取查看下层明细的功能。数据层级由高到低为 Division -> Region -> Branch -> Profit Center,每个 Profit Center 关联多条 Receivable(应收款)记录:

  • Division 汇总视图展示所有下属 Region(如California、Central Texas、Ohio等),统计各 Region 对应的 total_amount 字段合计值
  • 点击任意 Region 即可跳转至下属 Branch 汇总页,查看各 Branch 的数据汇总,以此类推实现逐层下钻

目前已尝试多种写法均未完全实现需求,相关代码如下:

初始实现代码

models.py

class Division(models.Model):
    name = models.CharField(max_length=128, unique=True)
    slug = models.SlugField(unique=True, null=True)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('division-detail', args=[str(self.slug)])

class Region(models.Model):
    name = models.CharField(max_length=128, unique=True)
    division = models.ForeignKey('Division', to_field='name', on_delete=models.CASCADE)
    slug = models.SlugField(unique=True, null=True)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('region-summary', args=[str(self.slug)])

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.name)
        super().save(*args, **kwargs)

class Branch(models.Model):
    name = models.CharField(max_length=128)
    number = models.CharField(max_length=4, unique=True)
    region = models.ForeignKey('Region', to_field='name', on_delete=models.CASCADE)
    slug = models.SlugField(unique=True, null=True)

    def __str__(self):
        return self.number

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.number)
        super().save(*args, **kwargs)

    def get_absolute_url(self):
        return reverse('branch-detail', args=[str(self.slug)])

class Profit_Center(models.Model):
    branch = models.ForeignKey('Branch', on_delete=models.CASCADE)
    number = models.CharField(max_length=32, unique=True, editable=False, null=True, blank=True)
    slug = models.SlugField(unique=True, null=True)

class Receivable(models.Model):
    document = models.IntegerField(primary_key=True, blank=False)
    payer = models.ForeignKey('Payer', on_delete=models.PROTECT)
    profit_center = models.ForeignKey(Profit_Center, to_field = 'number', on_delete=models.PROTECT,  null=True)
    total_amount = models.DecimalField(decimal_places=2, max_digits=20, null=True, blank=True)
    slug = models.SlugField(unique=True, null=True, editable=False)

tables.py

注释内容为已尝试过的失败写法:

#summary by selected division, showing summary by region
class ReceivableDivisionSummaryHTMxTable(tables.Table):
    #profit_center__branch__region = tables.Column(linkify=('region-summary', {'slug': 'central-texas'})) #always goes to central texas
    #profit_center__branch__region = tables.Column(linkify=('region-summary', {'region': tables.A('region'), 'slug': tables.A('region.slug')})) #fails on accessor key
    #profit_center__branch__region = tables.Column(linkify=('region-summary', {'slug': tables.A('profit_center__branch__region.slug')}))
    #profit_center__branch__region = tables.Column(linkify=('region-summary', {'slug': tables.A('name')})) #fails on accessor key
    #profit_center__branch__region = tables.LinkColumn('region-summary', args=[A('profit_center__branch__region.slug')])
    #profit_center__branch__region = tables.Column(linkify=True)
    #profit_center__branch__region = tables.LinkColumn('region-summary', kwargs={'slug': 'record.slug'}) #half-ass works, returns regionsummary/region_slug insteald of the real slug
    #profit_center__branch__region = tables.LinkColumn('region-summary', args=[A('pk')])
    #profit_center__branch__region = tables.Column(linkify=('region-summary', {'pk': tables.A('region__pk')}))  #half-ass works, returns regionsummary/region_slug insteald of the real slug
    #profit_center__branch__region = tables.LinkColumn('region-summary', args=[A('slug')])
    #profit_center__branch__region = tables.Column(linkify=('region-summary', {'slug': tables.A('region.slug')}))
    #species =tables.TemplateColumn('<a href="{% url "main:species" name value %}">{{value}}</a>')
    profit_center__branch__region = tables.TemplateColumn('<a href="{% url "region-summary" slug %}">{{value}}</a>') #接近可用,但链接返回的是Division slug而非Region slug,值显示正常

    class Meta:
        model = Receivable
        template_name = 'tables/bootstrap_htmx.html'
        fields = ('profit_center__branch__region', 'sum_col')

views.py

def ReceivableDivisionSummaryHTMxTableView(request, slug):
    #post = get_object_or_404(Receivable, slug=slug)
    queryset = Receivable.objects.values('profit_center__branch__region').annotate(sum_col=Sum('total_amount'))
    table= ReceivableDivisionSummaryHTMxTable(queryset)
    context = {'table': table, 'slug': slug}

    if request.htmx:
        template_name = "app/receivable_table_partial.html"
    else:
        template_name = 'app/receivable_summary_htmx.html'
    template_name
    return render(request, template_name, context)

def ReceivableRegionSummaryHTMxTableView(request, slug):
    queryset = Receivable.objects.values('profit_center').annotate(sum_col=Sum('total_amount'))
    table= ReceivableRegionSummaryHTMxTable(queryset)
    context = {'table': table, 'slug':slug}

    if request.htmx:
        template_name = "app/receivable_table_partial.html"
    else:
        template_name = 'app/receivable_summary_htmx.html'
    template_name
    return render(request, template_name, context)

问题排查过程更新

更新1:最小复现版本报错

将代码精简到最小可复现版本后,仍然抛出错误:for linkify=True, '100100' must have a method get_absolute_url,其中100100为某条 Profit Center 的编号,对应精简代码如下:

models.py

class Profit_Center(models.Model):
    branch = models.ForeignKey('Branch', on_delete=models.CASCADE)
    number = models.CharField(max_length=32, unique=True, editable=False, null=True, blank=True)
    profit_center_slug = models.SlugField(unique=True, null=True)
     def get_absolute_url(self):
        return reverse('branch-detail', args=[str(self.profit_center_slug)])


class Receivable(models.Model):
    document = models.IntegerField(primary_key=True, blank=False)
    profit_center = models.ForeignKey(Profit_Center, to_field = 'number', on_delete=models.PROTECT,  null=True)
    total_amount = models.DecimalField(decimal_places=2, max_digits=20, null=True, blank=True)
    receivable_slug = models.SlugField(unique=True, null=True, editable=False)

tables.py

class AllProfitCenterSummaryHTMxTable(tables.Table):
    profit_center = tables.Column(linkify=True)

    class Meta:
        model = Receivable
        template_name = 'tables/bootstrap_htmx.html'
        fields = ('profit_center', 'sum_col', )

views.py

def AllProfitCenterSummaryHTMxTableView(request):
    queryset = Receivable.objects.values('profit_center').annotate(sum_col=Sum('total_amount'))
    table= AllProfitCenterSummaryHTMxTable(queryset)
    
    if request.htmx:
        template_name = "app/receivable_table_partial.html"
    else:
        template_name = 'app/receivable_summary_htmx.html'
    template_name
    return render(request, template_name, {'table':table})

urls.py

path('htmx/allprofitcentersummary/', views.AllProfitCenterSummaryHTMxTableView, name='all-profit-center-summary'),

更新2:半可用实现与slug转换问题

通过自定义render方法实现了半可用的跳转效果,但该写法直接使用字段的文本值(如Central Texas)拼接链接,需要将其转换为标准slug格式(如central-texas),初始尝试的slug转换代码未生效:

class ReceivableDivisionSummaryHTMxTable(tables.Table):
    class Meta:
        model = Receivable
        template_name = 'tables/bootstrap_htmx.html'
        fields = ('profit_center__branch__region', 'sum_col',)

    # 初始半可用版本:直接拼接文本值
    # def render_profit_center__branch__region(self, value):
    #     return format_html('<a href="regionsummary/{}">{}</a>', value, value)

    # 未生效的slug转换写法
    def render_profit_center__branch__region(self, value):
        value_slug = value
        slugify(value_slug)
        return format_html('<a href="regionsummary/{}">{}</a>', value_slug, value)

疑问:是否可以向render方法传入slug参数。

更新3:slug转换成功,待解决上级参数传递问题

调整代码后已成功实现slug格式转换,但目前仍需要向render方法传入上级Division的slug参数,期望生成的链接格式为 divisionsummary/[事业部slug]/regionsummary/[区域slug],尝试编写的传参代码未生效:

# 已生效的slug转换版本
# def render_profit_center__branch__region(self, value):
#     return format_html('<a href="regionsummary/{}">{}</a>', slugify(value), value)

# 未生效的上级参数传参写法
def render_profit_center__branch__region(self, value, division_slug):
    return format_html('<a href="{}/regionsummary/{}">{}</a>', division_slug, slugify(value), value)

疑问:如何正确传递division_slug参数。


内容的提问来源于stack exchange,提问作者ducktapeonmydesk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 14:36:22