Как изменить кверисет в Django?
Я пытаюсь изменить вывод сериализатора Django.
В представлении на основе классов есть функция get_projects, которая возвращает набор экземпляров Contract.
Отношения между Contract и Project - один-ко-многим:
class Contract(models.Model):
project = models.ForeignKey(Project)
Теперь у меня есть такой 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'а таков:
[
{
"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"
},
]
Я хотел бы изменить вывод сериализатора на такую структуру:
[
{
"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",
},
....
]
},
]
Как я могу это сделать?
Для этого вы можете попробовать следующее
class ContactSerializer(serializers.ModelSerializer):
class Meta:
model = Contract
fields = ["contract_guid", "contract_number"]
class ProjectSerializer(serializers.ModelSerializer):
contracts = ContactSerializer(many=True)
class Meta:
model = Project
fields = ["project_guid", "project_name", "contracts"]
И не забывайте использовать prefetch relatedдля оптимизации запроса.
Проблема была связана с набором запросов. Я отрефакторил qs в get_projects:
projects = Project.objects.filter(active=True).prefetch_related(
Prefetch('contract_set', queryset=Contract.objects.filter(**filters), to_attr='contracts')
)
И рефакторить MySerializer следующим образом:
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)
Спасибо SerhiiL
за подсказку с prefetch_related.