Python Django:是否可以转换列中的逗号分隔值并将每个值检索为查询集行
Python Django: Is it possible to convert comma separated values in a column and retrieve each value as query set rows
我在 table 中的数据集是这样的,我们将 table 命名为 plans_tracker(第一个屏幕截图)我正在尝试检索查询集,例如(第二个屏幕截图).有人可以帮我解决这个问题吗,我无法修改 table 结构。我正在尝试在 Django 模板中执行此操作
使用 PostgreSQL 时是可以的。不过,我不确定如何使用其他数据库后端来实现它。请注意,您存储数据的方式并不理想,可以使用更好的解决方案。下面有 2 个更好的解决方案示例,其中一个是独立于数据库的。
假设您有一个定义如下的模型(我已经用单个字符字段替换了示例中不相关的字段):
from django.core.validators import validate_comma_separated_integer_list
from django.db import models
class Plan(models.Model):
group = models.CharField(max_length=256)
student_course_records = models.TextField(validators=[validate_comma_separated_integer_list])
鉴于此,您可以使用 string_to_array
通过 Django 的 Func
:
将学生列表转换为 PostgreSQL 数组
Plan.objects.annotate(
students=Func(
F('student_course_records'),
Value(','),
function='string_to_array',
output_field=ArrayField(models.IntegerField())
)
)
这将为您的对象添加一个名为 students
的“虚拟”字段。它将在一个数组中表示所有学生 ID,以便以后更容易处理。
由于您现在有一个 ID 数组,您可以使用 unnest
函数将这些值分解为单独的记录:
Plan.objects.annotate(
学生=功能(
函数(
F('student_course_records'),
价值(','),
函数='string_to_array',
output_field=ArrayField(models.IntegerField())
),
函数='unnest'
)
)
现在,您将拥有单独的记录,而不是 students
字段,每个记录都有一个 student
值。请注意,student_course_records
在每条记录中仍然可用,但您可以使用 values
、values_list
、only
或 exclude
.
更改它
为了简化这些查询的编写,您可以子类化 Func
class StringToArray(models.Func):
function = 'string_to_array'
def __init__(self, *args, output_field, **kwargs):
super().__init__(*args, output_field=ArrayField(output_field), **kwargs)
class Unnest(models.Func):
function = 'unnest'
arity = 1
然后您的通话将如下所示:
Plan.objects.annotate(
student=Unnest(
StringToArray(
F('student_course_records'),
Value(','),
output_field=models.IntegerField(),
)
)
)
如我之前所说,此数据模型并不理想,因为它需要在每次数据访问时解析以逗号分隔的列表。更不用说在这个字段上查询数据的麻烦了。有 2 种更好的方法:使用 ArrayField
而不是逗号分隔的文本字段或使用嵌套模型。第一种方法仍然需要 PostgreSQL 数据库,第二种方法可以与 Django 官方支持的任何数据库一起使用,但在这种简单的用例中可能显得嘈杂和多余。对于第一种方法,您可以将模型定义为:
class Plan(models.Model):
group = models.CharField(max_length=256)
student_course_records = ArrayField(models.IntegerField())
对于此模型,您的查询将简化为:
Plan.objects.annotate(
student=Unnest(F('student_course_records'))
)
并且 student_course_records
在所有情况下都将表示为数组,无需将其转换为其他任何内容。
第二种方法如下:
class Plan(models.Model):
group = models.CharField(max_length=256)
class Student(models.Model):
plan = models.ForeignKey(Plan, related_name='student_course_records', on_delete=models.CASCADE
对于此模型,您的查询将简化为:
Student.objects.all()
使用可选的 select_related
或 values
调用同时从 Plan
模型中提取数据。
我在 table 中的数据集是这样的,我们将 table 命名为 plans_tracker(第一个屏幕截图)我正在尝试检索查询集,例如(第二个屏幕截图).有人可以帮我解决这个问题吗,我无法修改 table 结构。我正在尝试在 Django 模板中执行此操作
使用 PostgreSQL 时是可以的。不过,我不确定如何使用其他数据库后端来实现它。请注意,您存储数据的方式并不理想,可以使用更好的解决方案。下面有 2 个更好的解决方案示例,其中一个是独立于数据库的。
假设您有一个定义如下的模型(我已经用单个字符字段替换了示例中不相关的字段):
from django.core.validators import validate_comma_separated_integer_list
from django.db import models
class Plan(models.Model):
group = models.CharField(max_length=256)
student_course_records = models.TextField(validators=[validate_comma_separated_integer_list])
鉴于此,您可以使用 string_to_array
通过 Django 的 Func
:
Plan.objects.annotate(
students=Func(
F('student_course_records'),
Value(','),
function='string_to_array',
output_field=ArrayField(models.IntegerField())
)
)
这将为您的对象添加一个名为 students
的“虚拟”字段。它将在一个数组中表示所有学生 ID,以便以后更容易处理。
由于您现在有一个 ID 数组,您可以使用 unnest
函数将这些值分解为单独的记录:
Plan.objects.annotate( 学生=功能( 函数( F('student_course_records'), 价值(','), 函数='string_to_array', output_field=ArrayField(models.IntegerField()) ), 函数='unnest' ) )
现在,您将拥有单独的记录,而不是 students
字段,每个记录都有一个 student
值。请注意,student_course_records
在每条记录中仍然可用,但您可以使用 values
、values_list
、only
或 exclude
.
为了简化这些查询的编写,您可以子类化 Func
class StringToArray(models.Func):
function = 'string_to_array'
def __init__(self, *args, output_field, **kwargs):
super().__init__(*args, output_field=ArrayField(output_field), **kwargs)
class Unnest(models.Func):
function = 'unnest'
arity = 1
然后您的通话将如下所示:
Plan.objects.annotate(
student=Unnest(
StringToArray(
F('student_course_records'),
Value(','),
output_field=models.IntegerField(),
)
)
)
如我之前所说,此数据模型并不理想,因为它需要在每次数据访问时解析以逗号分隔的列表。更不用说在这个字段上查询数据的麻烦了。有 2 种更好的方法:使用 ArrayField
而不是逗号分隔的文本字段或使用嵌套模型。第一种方法仍然需要 PostgreSQL 数据库,第二种方法可以与 Django 官方支持的任何数据库一起使用,但在这种简单的用例中可能显得嘈杂和多余。对于第一种方法,您可以将模型定义为:
class Plan(models.Model):
group = models.CharField(max_length=256)
student_course_records = ArrayField(models.IntegerField())
对于此模型,您的查询将简化为:
Plan.objects.annotate(
student=Unnest(F('student_course_records'))
)
并且 student_course_records
在所有情况下都将表示为数组,无需将其转换为其他任何内容。
第二种方法如下:
class Plan(models.Model):
group = models.CharField(max_length=256)
class Student(models.Model):
plan = models.ForeignKey(Plan, related_name='student_course_records', on_delete=models.CASCADE
对于此模型,您的查询将简化为:
Student.objects.all()
使用可选的 select_related
或 values
调用同时从 Plan
模型中提取数据。