【问题标题】:DRF Serializer How do I serialize my data and displayDRF Serializer 如何序列化我的数据并显示
【发布时间】:2021-08-03 15:50:47
【问题描述】:

我有以下序列化程序我在序列化方面遇到 Json 问题。我有一个名为 daniel james 的用户,他有多个学科,比如数学科学

这是我的模型。

class Result(BaseModel):
    semester_choices = (
        ('first', 'First'),
        ('second', 'Second'),
        ('third', 'Third'),
        ('fourth', 'Fourth'),
        ('fifth', 'Fifth'),
        ('sixth', 'Sixth'),
        ('seventh', 'Seventh'),
        ('eight', 'Eight'),
        ('all', 'All'),
    )
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    registration_number = models.CharField(null=True, blank=True, max_length=20)
    semester = models.CharField(max_length=50, choices=semester_choices, null=True, blank=True)
    gpa = models.CharField(max_length=20)
    subject = models.CharField(max_length=50)

serializers.py

 class ResultSerializer(serializers.ModelSerializer):
    class Meta:
        model = Result
        fields = '__all__'

class ListResultSerializer(ResultSerializer):
    user = serializers.CharField()
    semester = serializers.CharField()
    subject = serializers.SerializerMethodField()

class Meta(ResultSerializer.Meta):
    fields = (
        'user',
        'semester',
        'subject',
    )

def get_subject(self, instance):
    return SubjectSerializer(instance).data

这是我的SubjectSerializer

class SubjectSerializer(ResultSerializer):
    class Meta(ResultSerializer.Meta):
        fields = (
            'gpa',
            'subject'
        )

在我的views.py中我已经这样做了。

class ListResultView(rest_generics.ListAPIView, UserMixin):
    serializer_class = serializers.ListResultSerializer
    permission_classes = (AllowAny,)

    def get_object(self):
        return self.get_user()

    def get_queryset(self):
        return usecases.ListResultUseCase(
            user=self.get_user()
        ).execute()

我使用 usecases.py 来过滤数据,这里是进一步的代码

class ListResultUseCase:
    def __init__(self, user: User):
        self._user = user

    def execute(self):
        self._factory()
        return self._result

    def _factory(self):
        self._result = Result.objects.filter(user=self._user)

现在这是我现在从上面的代码中得到的 Json。

[
    {
        "user": "daniel james",
        "semester": "first",
        "subject": {
            "gpa": "a+",
            "subject": "maths"
        }
    },
    {
        "user": "daniel james",
        "semester": "first",
        "subject": {
            "gpa": "A",
            "subject": "data structures"
        }
    }
]

我希望我的 json 采用这种格式

 [
  {
    "user": "daniel james",
    "semester": "first",
    "subject": [
      {
        "gpa": "a+",
        "subject": "maths"
      },
      {
        "gpa": "A",
        "subject": "data structures"
      }
    ]
  }
]

对序列化器有帮助吗?

【问题讨论】:

  • 你能分享你的模型吗?
  • 添加了看看@OpticPython
  • 当您有多个学期时,您希望如何响应?
  • 有什么解决办法吗?我需要改变我的模型吗?

标签: python django django-rest-framework django-serializer


【解决方案1】:

您可以创建一个单独的序列化程序以与嵌套序列化程序一起使用。

class SubjectNestedSerializer(serializers.ModelSerializer):
    class Meta:
        model = Subject
        exclude = ['user']

附言

试着像这样改变你的模型

class Semester(BaseModel):
    semester_choices = (
        ('first', 'First'),
        ('second', 'Second'),
        ('third', 'Third'),
        ('fourth', 'Fourth'),
        ('fifth', 'Fifth'),
        ('sixth', 'Sixth'),
        ('seventh', 'Seventh'),
        ('eight', 'Eight'),
        ('all', 'All'),
    )
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='semesters')
    registration_number = models.CharField(null=True, blank=True, max_length=20)
    semester = models.CharField(max_length=50, choices=semester_choices, null=True, blank=True)

class Subject(BaseModel):
    semester = models.ForeignKey(Semester, on_delete=models.CASCADE, related_name='semester_subjects')
    gpa = models.CharField(max_length=20)
    subject = models.CharField(max_length=50)

【讨论】:

  • 感谢您的回答,一旦检查我在我的问题中添加了 SubjectSerializer。
  • 您有重复数据。如果没有额外的处理,很难合并它们。您会考虑将分离主题与学期模型分开吗?我会在上面添加它
  • 我的模型是否正确?我要改变什么?
  • 检查上述更改并查看。因此您可以通过嵌套的序列化程序轻松访问数据
【解决方案2】:

您可以为您的用户创建一个序列化程序,并添加一个方法字段来检索用户的所有主题。

def get_subjects(self,instace):
    subjects = Subject.objects.filter(user=instance)
    return SubjectSerializer(subjects, many=True)

【讨论】:

  • 我仍然得到相同的 Json 没有变化
  • 添加过一次看看
【解决方案3】:

您想要的是对现有数据进行聚合,以便为前端提供更有意义的结果。我宁愿自己生成响应,也不愿为此使用序列化程序。

这是一个简单的例子。

假设您想要多个用户的结果。 (如果您想要一个用户,那就更容易了)

def get_item_with_attribute_from_list(items, attribute, attribute_value):
"""
This is just a utility function that I use occasionally
"""
    if items is None or len(items) == 0:
        return None

    if isinstance(items[0], dict):
        for item in items:
            if item.get(attribute) == attribute_value:
                return item
    else:
        for item in items:
            if getattr(item, attribute, None) == attribute_value:
                return item

results = Result.objects.all().select_related('user')

response = []
for result in results:
    user_dict = get_item_with_attribute_from_list(response, "user", result.user.name)
    subject = {"gpa": "A", "subject": "data structures"}
    if user_dict:
        semester_list = user_dict['semesters']
        semester = get_item_with_attribute_from_list(semester_list, 'semester_name', result.semester)
        if semester:
            semester['subjects'].append(subject)
        else:
            semester_list.append({'subjects': [subject]})
    else:
        response.append({'user': result.user.name, 'semesters': [{'semester_name': result.semester, 'subjects': [subject]}]})

生成的 JSON 将是这样的。

[
  {
    "user": "daniel james",
    "semesters": [
        {
            "semester_name": "first",
            "subjects": [
                
                {
                    "gpa": "a+",
                    "subject": "maths"
                },
                {
                    "gpa": "A",
                    "subject": "data structures"
                }
            ]
        },
        {
            "semester_name": "second",
            "subjects": [
                
                {
                    "gpa": "b+",
                    "subject": "geometry"
                },
                {
                    "gpa": "C",
                    "subject": "chemistry"
                }
            ]
        }
    ]
  },
  ... # Other user's data
]

这样,您将拥有更多结构化数据,您将能够轻松计算每个学期的 SPA。

【讨论】:

  • 我在哪里放置上面的方法?
  • 我总是将utils.py 放在我的应用程序中以实现这种实用功能。你可以把它放在那里,然后将它导入你的views.py
  • 你能告诉我如何在视图中调用你的函数
  • 在后端聚合数据工作。但最好的做法是避免数据库中的重复,并且使用 django 具有最少的代码,让框架为您处理负担。对于这个问题,我认为您可以重构数据(在规范化之后)并让序列化程序进行聚合是最好的
猜你喜欢
  • 1970-01-01
  • 2022-12-12
  • 2020-07-19
  • 1970-01-01
  • 2015-08-13
  • 2022-06-14
  • 2018-03-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多