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
相关产品推荐
相关产品推荐

