相关行的 Django ORM 连接(通过 ORM 进行字符串连接?)
Django ORM concat for related rows (string join through ORM?)
两个简单模型:
class Thread(models.Model):
pass
class Message(models.Model):
thread = models.ForeignKey(Thread, related_name='messages')
有没有可能做这样的事情?
>>> thread = Thread.objects.create()
>>> Message.objects.create(thread=thread, content='One')
>>> Message.objects.create(thread=thread, content='Two')
>>> Message.objects.create(thread=thread, content='Three')
>>> t = Thread.objects.annotate(
message_content=MySuperConcat('messages__content')).first()
>>> t.messages_content
OneTwoThree
似乎 Django 的 Concat 无法做到这一点,现在我不确定是否可以实现所需的行为。
注意:PostgreSQL 9.5 和 Django 1.11。
由于您使用的是 Postgres,因此您可以使用 StringAgg
[docs],但在 1.11 版本中,您将无法订购它。
from django.contrib.postgres.aggregates import StringAgg
Thread.objects.annotate(arr=StringAgg('messages__content', delimiter='')).values()
>>> 'ThreeTwoOne'
更新:
如果您没有 100% 确定完全通过 ORM 完成的代码,那么 straight-forward 做类似
的事情是很不错的
vals = Thread.objects.filter(id=1).annotate(m=F('messages__content')).order_by('messages__id').values('m')
''.join([x['m'] for x in vals])
>>> 'OneTwoThree'
解决此问题的实际方法是在 StringAgg
class:
之外使用 aggregate
方法
from django.contrib.postgres.aggregates import StringAgg
Thread.objects.aggregate(arr=StringAgg('messages__content', delimiter='')).values()
两个简单模型:
class Thread(models.Model):
pass
class Message(models.Model):
thread = models.ForeignKey(Thread, related_name='messages')
有没有可能做这样的事情?
>>> thread = Thread.objects.create()
>>> Message.objects.create(thread=thread, content='One')
>>> Message.objects.create(thread=thread, content='Two')
>>> Message.objects.create(thread=thread, content='Three')
>>> t = Thread.objects.annotate(
message_content=MySuperConcat('messages__content')).first()
>>> t.messages_content
OneTwoThree
似乎 Django 的 Concat 无法做到这一点,现在我不确定是否可以实现所需的行为。
注意:PostgreSQL 9.5 和 Django 1.11。
由于您使用的是 Postgres,因此您可以使用 StringAgg
[docs],但在 1.11 版本中,您将无法订购它。
from django.contrib.postgres.aggregates import StringAgg
Thread.objects.annotate(arr=StringAgg('messages__content', delimiter='')).values()
>>> 'ThreeTwoOne'
更新:
如果您没有 100% 确定完全通过 ORM 完成的代码,那么 straight-forward 做类似
的事情是很不错的vals = Thread.objects.filter(id=1).annotate(m=F('messages__content')).order_by('messages__id').values('m')
''.join([x['m'] for x in vals])
>>> 'OneTwoThree'
解决此问题的实际方法是在 StringAgg
class:
aggregate
方法
from django.contrib.postgres.aggregates import StringAgg
Thread.objects.aggregate(arr=StringAgg('messages__content', delimiter='')).values()