Django Rest Framework - 如何重组json响应?

时间:2016-06-18 19:30:26

标签: python django django-rest-framework

我正在使用Django Rest Framework(以及rest_framework_mongoengine)并覆盖我的序列化程序的 to_representation()以发回我自己的自定义JSON对象。一切正常,但JSON字段的顺序搞砸了。请告诉我如何重新排序/重组正在发送回的JSON对象。序列化器看起来像这样:

`arm-none-eabi-gcc -Wall -g -std=c99 -Os -mlittle-endian -mcpu=cortex-m4 -march=armv7e-m -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -ffunction-sections -fdata-sections -Itemplate/inc -Icube/Drivers/BSP/STM32F4-Discovery -Icube/Drivers/CMSIS/Include -Icube/Drivers/CMSIS/Device/ST/STM32F4xx/Include -Icube/Drivers/STM32F4xx_HAL_Driver/Inc -Icube/Middlewares/ST/STM32_USB_Device_Library/Core/Inc -Icube/Middlewares/ST/STM32_USB_Device_Library/Class/HID/Inc -DSTM32F407xx -DUSE_HAL_DRIVER -DUSE_DBPRINTF -mthumb-interwork -Wl,--gc-sections -Wl,-Map=demo.map -Lcube/Drivers/CMSIS/Lib -Ttemplate/stm32f401xc.ld --specs=rdimon.specs -lc -lrdimon template/src/startup_stm32f401xc.s template/obj/main.o template/obj/system_stm32f4xx.o template/obj/stm32f4xx_it.o template/obj/usbd_conf_template.o template/obj/usbd_core.o template/obj/usbd_ctlreq.o template/obj/usbd_ioreq.o template/obj/usbd_hid.o template/obj/usbd_desc.o template/obj/stm32f4xx_hal_pcd.o template/obj/stm32f4_discovery_accelerometer.o template/obj/stm32f4xx_hal_tim.o -o demo.elf -Lcube/Drivers/STM32F4xx_HAL_Driver -lstm32f4_hal -Lcube/Drivers/BSP/STM32F4-Discovery -lstm32f4_bsp'

我得到的回应是:

class PharmacySerializer(DocumentSerializer):
    bank_account = serializers.DictField(child=serializers.CharField(), required=False)

    class Meta:
        model = Pharmacy
        fields = (
            'id', 'name', 'email', 'mobile', 'address_line_1', 'address_line_2',
            'city', 'state', 'zip', 'created_by', 'created_on', 'last_updated_by', 'license_number',
            'bank_account', 'last_updated_on', 'is_email_verified', 'is_mobile_verified', 'is_active')
        read_only_fields = ('created_by', 'created_on', 'last_updated_by', 'last_updated_on', 'is_active')

    def to_representation(self, pharmacy):
        return {
            'id': str(pharmacy.id),
            'name': pharmacy.name,
            'email': pharmacy.email,
            'mobile': pharmacy.mobile,
            'address_line_1': pharmacy.address_line_1,
            'address_line_2': pharmacy.address_line_2,
            'city': pharmacy.city,
            'state': pharmacy.state,
            'zip': pharmacy.zip,
            'created_by': pharmacy.created_by,
            'created_on': pharmacy.created_on,
            'last_updated_by': pharmacy.last_updated_by,
            'license_number': pharmacy.license_number,
            'bank_account': {
                'bank_name': pharmacy.bank_account.bank_name,
                'account_number': pharmacy.bank_account.account_number,
                'account_type': pharmacy.bank_account.account_type
            },
            'last_updated_on': pharmacy.last_updated_on,
            'is_email_verified': pharmacy.is_email_verified,
            'is_mobile_verified': pharmacy.is_mobile_verified,
            'is_active': pharmacy.is_active
        }

我希望它与to_representation()

的返回词典的顺序相同

2 个答案:

答案 0 :(得分:3)

尝试在to_representation中返回OrderedDict

def to_representation(self, pharmacy):
  return OrderedDict([('id', str(pharmacy.id),), ...])

代码中的dict对象本质上没有排序。假设框架在内部使用json.dump,您可以使用建议here的有序对象来保持订单。

答案 1 :(得分:3)

If you want to maintain order of response keys, you can use an OrderedDict. But there is one thing you should remember about OrderedDicts:

OrderedDict maintains order only while insertion of keys. The order gets lost while initializing with kwargs.

From Python docs:

The OrderedDict constructor and update() method both accept keyword arguments, but their order is lost because Python’s function call semantics pass-in keyword arguments using a regular unordered dictionary.

You need to first create an OrderedDict instance and then add keys one by one.

from collections import OrderedDict

def to_representation(self, pharmacy):
    ret = OrderedDict() # initialize on ordereddict

    # insert keys one by one in desired oreder
    ret['id'] = str(pharmacy.id)
    ret['name'] = pharmacy.name
    ret['email'] = pharmacy.email
    ret['mobile'] = pharmacy.mobile
    ret['address_line_1'] = pharmacy.address_line_1
    ret['address_line_2'] = pharmacy.address_line_2
    ret['city'] = pharmacy.city
    ret['state'] = pharmacy.state
    ret['zip'] = pharmacy.zip
    ret['created_by'] = pharmacy.created_by
    ret['created_on'] = pharmacy.created_on
    ret['last_updated_by'] = pharmacy.last_updated_by
    ret['license_number'] = pharmacy.license_number
    ret['bank_account'] = {
        'bank_name' = pharmacy.bank_account.bank_name
        'account_number' = pharmacy.bank_account.account_number
        'account_type' = pharmacy.bank_account.account_type
    }
    ret['last_updated_on'] = pharmacy.last_updated_on
    ret['is_email_verified'] = pharmacy.is_email_verified
    ret['is_mobile_verified'] = pharmacy.is_mobile_verified
    ret['is_active'] = pharmacy.is_active

    return ret

NOTE: Another option(recommended) is to use EmbeddedDocumentSerializer for bank_account field. Then you won't need to override the to_representation() method.