我有一些包括尺寸的数据,就像下面的模型。
class Product(models.Model):
width = models.CharField()
height = models.CharField()
length = models.CharField()
通过注释,我们有一个名为at_size的字段,它产生如下数据:
- [None, None, None]
- ['200', '000', '210']
- ['180', None, None]
这是这样完成的(感谢:)https://stackoverflow.com/a/70266320/5731101:
class Array(Func):
template = '%(function)s[%(expressions)s]'
function = 'ARRAY'
out_format = ArrayField(CharField(max_length=200))
annotated_qs = Product.objects.all().annotate(
at_size=Array(F('width'), F('height'), F('length'),
output_field=out_format)
)
我想把这个转换成:
- "
- '200 x 000 x 210'
- "180">
在代码中,这可能有点像' x '.join([i for i in data if i])
。但是,由于我需要使用数据库函数来完成这一点,这有点更具挑战性。
我一直在玩StringAgg,但我一直得到:
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
看起来我需要确保None值从初始的array - function中排除。但我不知道从哪里开始。我怎样才能做到这一点呢?
问题是双重的。
- 清除Null值可以通过使用array_remove 来完成
- 通过StringAgg用分隔符粘合字符串只有在输入是字符串时才有效。但由于我们使用的是数组,所以这不是正确的方法。而是使用array_to_string
最终结果如下:
class Array(Func):
# https://www.postgresql.org/docs/9.6/functions-array.html
template = '%(function)s[%(expressions)s]'
function = 'ARRAY'
class ArrayRemove(Func):
# https://www.postgresql.org/docs/9.6/functions-array.html
function = 'array_remove'
class ArrayToString(Func):
# https://stackoverflow.com/a/57873772/5731101
function = 'array_to_string'
out_format = ArrayField(CharField(max_length=200))
annotated_qs = annotated_qs.annotate(
at_size=ArrayToString(
ArrayRemove(
Array(F('width'), F('height'), F('length'), output_field=out_format),
None, # Remove None values from the Array with ArrayRemove
),
Value(" x "), # Delimiter.
Value(''), # If there are null-values, replace with... (fallback)
output_field=CharField(max_length=200),
)
)
生成所需的格式:
for product in annotated_qs:
print(product.at_size)
180 x 000 x 200
180 x 026 x 200
180 x 7 x 200
180 x 000 x 200
200 x 000 x 220
180 x 000 x 200
175 x 230 x 033
160 x 000 x 200
60 x 220
Product.objects.annotate(display_format=Concat(F('width'), '×', F('height'), '×', F('length')))
应该做的伎俩不是吗?
不需要过于复杂,让我们保持它的漂亮和简单,并使用数据库连接3个字符串,并用乘法符号分开它们(显然,如果你喜欢另一个字符替换)。
看看这里的文档:https://docs.djangoproject.com/en/4.1/ref/models/database-functions/concat