Django-Tables2从字典中添加额外的列

时间:2018-08-14 17:39:23

标签: python django django-models django-tables2

很抱歉是否曾经问过这个问题,但是我找不到我所用的具体用例。

我有一个显示基本产品信息的表。产品详细信息(例如价格,销售数量和销售商数量)会定期进行抓取,并存储在单独的数据库表中。现在,我想使用tables2在前端的一个表中同时显示基本产品信息和详细信息。为此,我在产品模型中编写了一个函数,以获取最新的详细信息并将其作为字典返回,从而可以使用单个Accessor调用。

# models.py

class Product(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)

    name = models.CharField(max_length=256)
    brand = models.ForeignKey(Brand)
    category = models.CharField(max_length=128, choices=CATEGORY_CHOICES)

    def __unicode__(self):
        return self.name

    def currentState(self):
        currentDetailState = ProductDetailsState.objects.filter(
            product=self
        ).latest('created_at')

        # return current details as a dictionary
        return {
            price: currentDetailState.price,
            num_sellers: currentDetailState.num_sellers,
            num_sales: currentDetailState.num_sales
        }


class ProductDetailsState(models.Model):
    product = models.ForeignKey(Product)
    created_at = models.DateTimeField(auto_now_add=True)

    price = models.DecimalField(max_digits=6, decimal_places=2, null=True)

    num_sellers = models.IntegerField(null=True)
    num_sales = models.IntegerField(null=True)

    def __unicode__(self):
        return self.created_at



# tables.py

class ProductTable(tables.Table):
    productBrand = tables.Column(
        accessor=Accessor('brand.name'),
        verbose_name='Brand'
    )
    currentRank = tables.Column(
        accessor=Accessor('currentRank')
    )

    class Meta:
        model = Product
        ...

现在如何使用此返回的字典并将其拆分为“产品”表中的列?除了我的使用方式,还有其他使用访问器的方法吗?

1 个答案:

答案 0 :(得分:0)

您可以使用Accessor遍历字典,因此应该可以进行以下操作:

class ProductTable(tables.Table):
    # brand is the name of the model field, if you use that as the column name, 
    # and you have the __unicode__ you have now, the __unicode__ will get called, 
    # so you can get away with jus this:
    brand = tables.Column(verbose_name='Brand')
    currentRank = tables.Column()

    # ordering on the value of a dict key is not possible, so better to disable it.
    price = tables.Column(accessor=tables.A('currentState.price'), orderable=False)
    num_sellers = tables.Column(accessor=tables.A('currentState.num_sellers'), orderable=False)
    num_sales = tables.Column(accessor=tables.A('currentState.num_sales'), orderable=False)

    class Meta:
        model = Product

虽然可行,但排序也很不错。为此,您的'currentState'方法有点麻烦,您应该更改传递给表的QuerySet。此视图显示了它如何工作:

from django.db.models import F, Max
from django.shortcuts import render
from django_tables2 import RequestConfig

from .models import Product, ProductDetailsState
from .tables import ProductTable


def table(request):
    # first, we make a list of the post recent ProductDetailState instances
    # for each Product.
    # This assumes the id's increase with the values of created_at, 
    # which probably is a fair assumption in most cases.
    # If not, this query should be altered a bit.
    current_state_ids = Product.objects.annotate(current_id=Max('productdetailsstate__id')) \
        .values_list('current_id', flat=True)

    data = Product.objects.filter(productdetailsstate__pk__in=current_state_ids)

    # add annotations to make the table definition cleaner.
    data = data.annotate(
        price=F('productdetailsstate__price'),
        num_sellers=F('productdetailsstate__num_sellers'),
        num_sales=F('productdetailsstate__num_sales')
    )
    table = ProductTable(data)
    RequestConfig(request).configure(table)

    return render(request, 'table.html', {'table': table})

使用上面创建的注释可以简化表的定义:

class ProductTable(tables.Table):
    brand = tables.Column(verbose_name='Brand')
    currentRank = tables.Column()

    price = tables.Column()
    num_sellers = tables.Column()
    num_sales = tables.Column()

    class Meta:
        model = Product

您可以找到完整的django项目at github