Session对象的保存
从1.6开始Django的Session中保存的对象必须可被JSON序列化,原生的对象将不在被支持。
数据库查询结果序列化
- DecimalField字段将被序列化成字符串,使用如可以,使用FloatField好了,它是可以被正常序列化的。
- Django自带的序列化工具不支持单个查询结果
- 如果有继承存在,Django自带的序列化工具将不能序列化,父类的属性,所以要将Django的序列化工具拷贝出来修改。
# encoding=utf-8 import json import warnings from django.core.serializers.json import DjangoJSONEncoder from django.db import models from django.db.models.query import QuerySet from django.utils import six from django.utils.deprecation import RemovedInDjango19Warning from django.utils.encoding import force_text, is_protected_type def serialize(obj): ''' 返回字典类型 :param format: :param obj: :return: ''' if isinstance(obj, QuerySet): return json.loads(djserialize('json', obj)) if isinstance(obj, models.Model): return json.loads(djserialize('json', [obj])[1:-1]) if hasattr(obj, 'isoformat'): return obj.isoformat() return obj def djserialize(format, queryset, **options): """ Serialize a queryset (or any iterator that returns database objects) using a certain serializer. """ s = JsonSerializer() s.serialize(queryset, **options) return s.getvalue() class Serializer(object): """ django.core.serializers 里面的serialize类不能序列化父类的属性,所以拷贝过来改了改 Abstract serializer base class. """ # Indicates if the implemented serializer is only available for # internal Django use. internal_use_only = False def serialize(self, queryset, **options): """ Serialize a queryset. """ self.options = options self.stream = options.pop("stream", six.StringIO()) self.selected_fields = options.pop("fields", None) self.use_natural_keys = options.pop("use_natural_keys", False) if self.use_natural_keys: warnings.warn("``use_natural_keys`` is deprecated; use ``use_natural_foreign_keys`` instead.", RemovedInDjango19Warning) self.use_natural_foreign_keys = options.pop('use_natural_foreign_keys', False) or self.use_natural_keys self.use_natural_primary_keys = options.pop('use_natural_primary_keys', False) self.start_serialization() self.first = True for obj in queryset: self.start_object(obj) # Use the concrete parent class' _meta instead of the object's _meta # This is to avoid local_fields problems for proxy models. Refs #17717. concrete_model = obj._meta.concrete_model for field in concrete_model._meta.fields: # django 中是local_fields,不能显示父类内容 if field.serialize: if field.rel is None: if self.selected_fields is None or field.attname in self.selected_fields: self.handle_field(obj, field) else: if self.selected_fields is None or field.attname[:-3] in self.selected_fields: self.handle_fk_field(obj, field) for field in concrete_model._meta.many_to_many: if field.serialize: if self.selected_fields is None or field.attname in self.selected_fields: self.handle_m2m_field(obj, field) self.end_object(obj) if self.first: self.first = False self.end_serialization() return self.getvalue() def start_serialization(self): """ Called when serializing of the queryset starts. """ raise NotImplementedError('subclasses of Serializer must provide a start_serialization() method') def end_serialization(self): """ Called when serializing of the queryset ends. """ pass def start_object(self, obj): """ Called when serializing of an object starts. """ raise NotImplementedError('subclasses of Serializer must provide a start_object() method') def end_object(self, obj): """ Called when serializing of an object ends. """ pass def handle_field(self, obj, field): """ Called to handle each individual (non-relational) field on an object. """ raise NotImplementedError('subclasses of Serializer must provide an handle_field() method') def handle_fk_field(self, obj, field): """ Called to handle a ForeignKey field. """ raise NotImplementedError('subclasses of Serializer must provide an handle_fk_field() method') def handle_m2m_field(self, obj, field): """ Called to handle a ManyToManyField. """ raise NotImplementedError('subclasses of Serializer must provide an handle_m2m_field() method') def getvalue(self): """ Return the fully serialized queryset (or None if the output stream is not seekable). """ if callable(getattr(self.stream, 'getvalue', None)): return self.stream.getvalue() class PySerializer(Serializer): """ Serializes a QuerySet to basic Python objects. """ internal_use_only = True def start_serialization(self): self._current = None self.objects = [] def end_serialization(self): pass def start_object(self, obj): self._current = {} def end_object(self, obj): self.objects.append(self.get_dump_object(obj)) self._current = None def get_dump_object(self, obj): data = { "model": force_text(obj._meta), "fields": self._current, } if not self.use_natural_primary_keys or not hasattr(obj, 'natural_key'): data["pk"] = force_text(obj._get_pk_val(), strings_only=True) return data def handle_field(self, obj, field): value = field._get_val_from_obj(obj) # Protected types (i.e., primitives like None, numbers, dates, # and Decimals) are passed through as is. All other values are # converted to string first. if is_protected_type(value): self._current[field.name] = value else: self._current[field.name] = field.value_to_string(obj) def handle_fk_field(self, obj, field): if self.use_natural_foreign_keys and hasattr(field.rel.to, 'natural_key'): related = getattr(obj, field.name) if related: value = related.natural_key() else: value = None else: value = getattr(obj, field.get_attname()) if not is_protected_type(value): value = field.value_to_string(obj) self._current[field.name] = value def handle_m2m_field(self, obj, field): if field.rel.through._meta.auto_created: if self.use_natural_foreign_keys and hasattr(field.rel.to, 'natural_key'): m2m_value = lambda value: value.natural_key() else: m2m_value = lambda value: force_text(value._get_pk_val(), strings_only=True) self._current[field.name] = [m2m_value(related) for related in getattr(obj, field.name).iterator()] def getvalue(self): return self.objects class JsonSerializer(PySerializer): """ Convert a queryset to JSON. """ internal_use_only = False def _init_options(self): if json.__version__.split('.') >= ['2', '1', '3']: # Use JS strings to represent Python Decimal instances (ticket #16850) self.options.update({'use_decimal': False}) self._current = None self.json_kwargs = self.options.copy() self.json_kwargs.pop('stream', None) self.json_kwargs.pop('fields', None) if self.options.get('indent'): # Prevent trailing spaces self.json_kwargs['separators'] = (',', ': ') def start_serialization(self): self._init_options() self.stream.write("[") def end_serialization(self): if self.options.get("indent"): self.stream.write("\n") self.stream.write("]") if self.options.get("indent"): self.stream.write("\n") def end_object(self, obj): # self._current has the field data indent = self.options.get("indent") if not self.first: self.stream.write(",") if not indent: self.stream.write(" ") if indent: self.stream.write("\n") json.dump(self.get_dump_object(obj), self.stream, cls=DjangoJSONEncoder, **self.json_kwargs) self._current = None def getvalue(self): # Grand-parent super return super(PySerializer, self).getvalue()