0

I have a use case in django_tables2 with django.db.models Sum, but can not figure out the usage after reading django doc with aggregation, I am wondering whether that is possible:

# models.py 
class AModel(models.Model):
    a_id = models.IntegerField()
    a_name = models.CharField(max_length=50)
    def __unicode__(self):
        return unicode(self.name)


class BModel(models.Model):
    b_id = models.IntegerField()
    b_name = models.CharField(max_length=50)
    a_name = models.ForeignKey(AModel)
    def __unicode__(self):
        return self.b_name

class CModel(models.Model):
    c_id = models.IntegerField()
    c_name = models.CharField(max_length=50)
    c_status = models.CharField(max_length=8)
    def __unicode__(self):
        return self.c_name

class DModel(models.Model):
    d_id = models.IntegerField()
    dmode = models.CharField(max_length=50)
    bmodel = models.ForeignKey(BModel)
    cmodel = models.ForeignKey(CModel)
    date = models.DateField(null=True)
    cost = models.FloatField(default=0.00)
    def __unicode__(self):
        return self.d_name

# tables.py
import django_tables2 as tables
class DmodelTable(tables.Table)
    class Meta:
        model = DModel
        fields = ('dmodel', 'bmodel', 'cmodel',  'cost')

class TargetTable(tables.Table)
    a_name = tables.Column(accessor='b_name.a_name')
    class Meta:
        model = DModel
        fields = ('bmodel', 'cmodel', 'amodel', 'cost_sum')

# view.py
from django.db.models import Sum
...
def page(request):
    queryset = DModel.objects.values('bmodel','cmodel').annotate(cost_sum=Sum('cost'))
    table = TargetTable(queryset)
    return render(request, 'tartget.html', {'table':table})

def dmodelpage(request):
    table = DModelTable(DModel.objects.all())
    return render(request, 'tartget.html', {'table':table})

the result I got is as following is the TargetTable:

+---------+------------+----------+--------------------+
| b_name  | c_name     | a_name   | cost_sum           |
+---------+------------+----------+--------------------+
| 1863703 |    8485748 |   -      |               3150 |
| 1863703 |    8688288 |   -      |                  0 |
| 1863703 |    8691184 |   -      |              712.5 |

I encounter 2 problems with the solution:

  1. The b_name and c_name are ids, not the name as expected.

  2. a_name is null, I think because the first issue, that the bmodel is not correctly return bmodel in queryset, then the bmodel.a_name dose not work.

I can find solution for display "id" issue for only one ForeignKey in DModel, like mentioned here, but have no idea how to deal with mutlti-foreign key cases.

Can someone help? Thanks very much

Community
  • 1
  • 1
zhihong
  • 1,808
  • 2
  • 24
  • 34

2 Answers2

0
  1. You might need to define a __str__/__unicode__ method on your models returning self.x_name.

  2. The name of your foreign key on DModel is b_name, so you should use a_name = tables.Column(accessor='b_name.b_name')

Jieter
  • 4,101
  • 1
  • 19
  • 31
  • Hi, Jieter, thanks for your reply. 1. I do have __unicode__in the code, update it in my question, and this dose not work. 2. thought I write "bmodel" in my original question, it is actually the value of the "b_name" in Dmodel. Sorry for the confusing. But it dose not work. – zhihong Sep 16 '16 at 14:42
  • Do you use python 2 or 3? If using 2, you should add `__str__`, and not `__unicode__`, [also see django docs](https://docs.djangoproject.com/en/1.10/topics/python3/#str-and-unicode-methods). The django admin also doesn't show the name if you didn't define the right method. – Jieter Sep 18 '16 at 19:01
  • Hi, Jieter, I use python 2, and use __ unicode __, all admin display the name correctly, and also the other tables display the names correctly like the DModelTable. I think the problem here is related to the aggregation calculation in the TargetTable. – zhihong Sep 28 '16 at 15:42
0

all, later I figure out the issues:

# table.py
class TargetTable(tables.Table)
        class Meta:
            model = DModel
            fields = ('bmodel__b_name', 'cmodel__c_name', 'cmodel__amodel__a_name', 'cost_sum')

# view.py
from django.db.models import Sum
...
def page(request):
    queryset = DModel.objects.values('bmodel__b_name','cmode__c_name', 'cmode__amode__a_name').annotate(cost_sum=Sum('cost'))
    table = TargetTable(queryset)
    return render(request, 'tartget.html', {'table':table})

If you want show name, then should refer to the exactly field name of that model. And all the aggragation columns that need must be added in the .values().

zhihong
  • 1,808
  • 2
  • 24
  • 34