Search code examples
pythondjangoserialization

How to change a queryset in Django?


I try to change output of Django serializer.

Class-based view has function get_projects that returns queryset of Contract instances.

projects = Project.objects.all()
contracts = Contract.objects.filter(project__in=projects)

Relationship of Contract and Project is one-to-many:

class Contract(models.Model):
    project = models.ForeignKey(Project)

Now I have such MySerializer:

class MySerializer(serializers.Serializer):
    project_guid = serializers.UUIDField(source='guid')
    project_name = serializers.CharField(source='name')
    contract_guid = serializers.UUIDField(source='guid')
    contract_number = serializers.CharField(source='number')

MySerializer's response is:

[
  {
    "projectGuid": "project_guid_1",
    "projectName": "project_name_1",
    "contractGuid": "contract_guid_1",
    "contractNumber": "contract_number_1"
  },
  {
    "projectGuid": "project_guid_1",
    "projectName": "project_name_1",
    "contractGuid": "contract_guid_2",
    "contractNumber": "contract_number_2"
  },
  {
    "projectGuid": "project_guid_2",
    "projectName": "project_name_2",
    "contractGuid": "contract_guid_4",
    "contractNumber": "contract_number_4"
  },
  {
    "projectGuid": "project_guid_2",
    "projectName": "project_name_2",
    "contractGuid": "contract_guid_5",
    "contractNumber": "contract_number_5"
  },
]

I would like to change serializer output - to group contracts for exact projects like this:

[
 {
  "project_guid": "project_guid_1",
  "project_name": "project_name_1",
  "contracts": [
    {
      "contract_guid": "contract_guid_1",
      "contract_number": "contract_number_1",
    },
    {
      "contract_guid": "contract_guid_2",
      "contract_number": "contract_number_2",
    },
    ....
  ]
 },
 {
  "project_guid": "project_guid_2",
  "project_name": "project_name_2",
  "contracts": [
    {
      "contract_guid": "contract_guid_4",
      "contract_number": "contract_number_4",
    },
    {
      "contract_guid": "contract_guid_5",
      "contract_number": "contract_number_5",
    },
    ....
  ]
 },
]

How can I do this?


Solution

  • The problem was with the queryset. I refactored qs in get_projects:

    projects = Project.objects.filter(active=True).prefetch_related(
            Prefetch('contract_set', queryset=Contract.objects.filter(**filters), to_attr='contracts')
        )
    

    And refactored MySerializer like this:

    class ContractSerializer(serializers.Serializer):
        contract_guid = serializers.UUIDField(source='guid')
        contract_number = serializers.CharField(source='number')
    
    class MySerializer(serializers.Serializer):
        project_guid = serializers.UUIDField(source='guid')
        project_name = serializers.CharField(source='name')
        contracts = ContractSerializer(many=True)
    

    Thanks to SerhiiL for hint with prefetch_related.