如何使用Django ORM创建交叉表SQL查询?

4

如何使用Django 1.1 ORM创建交叉表(数据透视表)SQL查询?

更新: 以下是模型和输出要求:

class Store(models.Model):
    name = models.CharField(max_length=255)
    ...

class Order(models.Model):
    store = models.ForeignKey(Store, blank=True, null=True, related_name='orders')
    description = models.CharField(_('Description'), max_length=255)
    quantity = models.IntegerField(blank=True, null=True)       
    type_detail = models.CharField(_('Type Detail'), max_length=255)
    slug = models.SlugField(blank=True)
    cost = models.DecimalField(_("Cost"), max_digits=14, decimal_places=2)
    modified = models.DateTimeField(_('modified'), auto_now=True)

目前视图显示的数据如下:

Store   | Type Detail  | Quantity 
----------------------------------
Walmart | Floor polish | 2        
Walmart | Tiles        | 1        
Walmart | Milk         | 4      
Another | Floor polish | 2        
Another | Tiles        | 1        
Another | Milk         | 4        

我希望将其转换为以下形式以查看数据:
对于商店,我需要知道数量。
Store   | Floor polish  | Tiles | Milk
------------------------------------------------
Walmart | 2             | 1     | 4
Another | 2             | 1     | 4

I hope that explains what I need.


1
你需要提供更多的细节。你有哪些模型,想要实现什么样的结果? - Daniel Roseman
3个回答

3
您可以在模板中按照以下方式完成此操作(假设您将 line_items 传递到模板中,并且 store.name 是一个唯一的属性):
{% regroup line_items by store.name as store_items %}
{% for store in store_items %}    
  <tr>
    <td>{{ store.grouper }}</td>
    {% for item in store.list %}
      <td>{{ item.count }}</td>
    {% endfor %}
  </tr>
{% endfor %}

如果所有商店的库存相同,则此方法可行,否则您需要填补视图中的空缺(例如返回缺失库存项目的0)


2

一个合适的交叉表需要为每个维度成员提供一个值。下面是我编写的一个示例。您可以在Django模板中像doctext示例那样使用它。因此,您将查询1)所有商店值,2)所有type_detail值和3)每个商店和type_detail的数量。第三个查询的结果转换为(store,type)=> quantity字典。

class Cube(object):
    """Iterable sparse cube. Iterating gives an item for every dimension member.

    >>> pythons = ['eric', 'john', 'terry']
    >>> cheeses = ['limburg', 'feta', 'parmigiano']
    >>> cheese_consumption = {
        ('eric', 'limburg'): 2,
        ('eric', 'parmigiano'): 4,
        ('john', 'feta'): 5
    }
    >>> cheese_cube = Cube((pythons, cheeses), cheese_consumption)
    >>> for python, python_cheeses in cheese_cube:
        for cheese, consumption in python_cheeses:
            print python, cheese, consumption or 0

    eric limburg 2
    eric feta 0
    eric parmigiano 4
    john limburg 0
    john feta 5 
    john parmigiano 0
    terry limburg 0
    terry feta 0
    terry parmigiano 0
    """
    def __init__(self, dimensions, facts, slice=None):
        self.dimensions = dimensions
        self.data_dict = facts
        self.slice = slice or ()
    def __iter__(self):
        if len(self.slice) + 1 < len(self.dimensions):
            for item in self.dimensions[len(self.slice)]:
                yield item, Cube(self.dimensions, self.data_dict, self.slice + (item,))
        else:
            for item in self.dimensions[len(self.slice)]:
                yield item, self.data_dict.get(self.slice + (item,), None)

-1

不了解Django,但这里有普通的SQL

SELECT Store,
SUM(CASE WHEN Type_Detail = 'Floor polish' THEN Quantity ELSE 0 END) as 'Floor polish',
SUM(CASE WHEN Type_Detail = 'Tiles' THEN Quantity ELSE 0 END) as 'Tiles',
SUM(CASE WHEN Type_Detail = 'Milk' THEN Quantity ELSE 0 END) as 'Milk'
FROM Order
GROUP BY Store

这种方法的问题在于你已经将列硬编码到了SQL中,因此如果添加了新类型,你就必须更改SQL。 - Eric Clack

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接