原始查询必须包含主键

时间:2013-06-27 15:38:26

标签: django django-models

我的views.py

中有一个原始的SQL语句
Message.objects.raw('''
        SELECT s1.ID, s1.CHARACTER_ID, MAX(s1.MESSAGE) MESSAGE, MAX(s1.c) occurrences
        FROM
           (SELECT ID, CHARACTER_ID, MESSAGE, COUNT(*) c
            FROM tbl_message WHERE ts > DATE_SUB(NOW(), INTERVAL %s DAY) GROUP BY CHARACTER_ID,MESSAGE) s1
        LEFT JOIN
           (SELECT ID, CHARACTER_ID, MESSAGE, COUNT(*) c
            FROM tbl_message WHERE ts > DATE_SUB(NOW(), INTERVAL %s DAY) GROUP BY CHARACTER_ID,MESSAGE) s2
          ON s1.CHARACTER_ID=s2.CHARACTER_ID
         AND s1.c < s2.c
        WHERE s2.c IS NULL
        GROUP BY CHARACTER_ID
        ORDER BY occurrences DESC''', [days, days])

此SQL语句的结果(直接在数据库上测试)是:

ID  | CHARACTER_ID | MESSAGE | OCCURENCES
----+--------------+---------+--------------
148 | 10           | test    | 133

但我得到的只是一个InvalidQuery异常信息Raw query must include the primary key

然后我仔细检查docs并阅读:

  

只有一个字段你不能遗漏 - 主键   field ....如果您忘记包含主键,将引发InvalidQuery异常。

正如您所看到的,我在声明中添加了所请求的主键。怎么了?

class Message(models.Model):
    character = models.ForeignKey('Character')
    message = models.TextField()
    location = models.ForeignKey('Location')
    ts = models.DateTimeField()

    class Meta:
        pass

    def __unicode__(self):
        return u'%s: %s...' % (self.character, self.message[0:20])

3 个答案:

答案 0 :(得分:10)

我使用Python 2.7.5,Django 1.5.1和Mysql 5.5重现了同样的问题。

我已将raw调用的结果保存到results变量,因此我可以查看其中包含的列:

>>> results.columns
['ID', 'CHARACTER_ID', 'MESSAGE', 'occurrences']

ID是大写的,因此在您的查询中,我将s1.ID更改为s1.id并且有效:

>>> results = Message.objects.raw('''
...         SELECT s1.id, s1.CHARACTER_ID, MAX(s1.MESSAGE) MESSAGE, MAX(s1.c) occurrences
...         FROM
...            (SELECT ID, CHARACTER_ID, MESSAGE, COUNT(*) c
...             FROM tbl_message WHERE ts > DATE_SUB(NOW(), INTERVAL %s DAY) GROUP BY CHARACTER_ID,MESSAGE) s1
...         LEFT JOIN
...            (SELECT ID, CHARACTER_ID, MESSAGE, COUNT(*) c
...             FROM tbl_message WHERE ts > DATE_SUB(NOW(), INTERVAL %s DAY) GROUP BY CHARACTER_ID,MESSAGE) s2
...           ON s1.CHARACTER_ID=s2.CHARACTER_ID
...          AND s1.c < s2.c
...         WHERE s2.c IS NULL
...         GROUP BY CHARACTER_ID
...         ORDER BY occurrences DESC''', [days, days])
>>> results.columns
['id', 'CHARACTER_ID', 'MESSAGE', 'occurrences']
>>> results[0]
<Message_Deferred_character_id_location_id_message_ts: Character object: hello...>

答案 1 :(得分:8)

在查询中包含1作为ID

Message.objects.raw('''
        SELECT 1 as id , s1.ID, s1.CHARACTER_ID, MAX(s1.MESSAGE) MESSAGE, MAX(s1.c) occurrences
        FROM
           (SELECT ID, CHARACTER_ID, MESSAGE, COUNT(*) c
            FROM tbl_message WHERE ts > DATE_SUB(NOW(), INTERVAL %s DAY) GROUP BY CHARACTER_ID,MESSAGE) s1
        LEFT JOIN
           (SELECT ID, CHARACTER_ID, MESSAGE, COUNT(*) c
            FROM tbl_message WHERE ts > DATE_SUB(NOW(), INTERVAL %s DAY) GROUP BY CHARACTER_ID,MESSAGE) s2
          ON s1.CHARACTER_ID=s2.CHARACTER_ID
         AND s1.c < s2.c
        WHERE s2.c IS NULL
        GROUP BY CHARACTER_ID
        ORDER BY occurrences DESC''', [days, days]) 

答案 2 :(得分:0)

对于那些也被这个问题困扰的人,也许和我一样,想知道为什么 Django 需要一个 pk,当你没有一个 pk 用于查询时(例如你想要多行) – Django只需要返回一个 id 字段,pk 不需要成为 where 子句的一部分。即:

select * from table where foo = 'bar';

select id, description from table where foo = 'bar';

如果表中有一个字段 id,那么这两种方法都有效。但这会引发 Thomas Schwärzl 描述的错误,因为没有返回 id 字段:

select description from table where foo = 'bar';