django 数据序列化的实现

django 数据序列化的实现

为什么要自己去序列化呢?为什么不用restful呢?

django做全栈开发真的很不错,但做前、后端分离开发时,某些方面可能需要调整。比如,数据的序列化这个问题,跨域问题;当然,这都不是什么大问题。。。下面说说数据序列化

问题

后端与前端通过json数据格式交互数据;django 通过orm读取的数据,不能直接用django的serializable或python的序列化方式;那怎么办?用restful吧,有专门的针对django的 django restful fremework,具体使用方式,请参见官方文档:http://www.django-rest-framework.org/

有同事吐槽restful,嫌麻烦,因为用restful还需要额外写model什么的。。。。那怎么办?只能自己造轮子了!

1.概述

本项目:
1.实现了将从数据库获取到的数据,序列化为json格式,返回给前端
2.从数据库读取到的date、datetime字段,做了格式化处理
3.获取到的从表数据,在做处理时,将需展现的字段做了重命名处理,防止从表与主表字段冲突
2.暂未将前端提交的json映射到model

2.基础开发环境

  • Python2.7.12
  • Django1.10.3
  • sqlite3

3.简单说明

1.序列化方法写在了公共model类 CModel中,此类继承 model.Models;
2.所有model类继承CModel类;
3.一对一关系实例 http://127.0.0.1:8000/get/classroom
4.一对多关系实例 http://127.0.0.1:8000/get/article
5.多对对关系实例 http://127.0.0.1:8000/get/group

4.遗留问题

1.获取model中不存在的字段数据时,抛出异常,个人认为这个异常无需捕获。
2.实现了将从数据库获取到的数据,序列化为json格式,返回给前端
3.暂未将前端提交的json映射到model

解决方案

创建django项目,创建app略过。。。

1.创建CModel公共类

所有model类继承此类

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import unicode_literals

from django.db import models
from django.core.exceptions import FieldDoesNotExist
DATETIME_FORMAT = "%Y/%m/%d %H:%M:%S"
DATE_FORMAT = "%Y/%m/%d"


class CModel(models.Model):
    class Meta:
        abstract = True
        ordering = ['-id']

    def get_value(self, field_name, prefix=None):
        """获取指定字段的值,返回字典类型的数据;field_name 字段名称|prefix 字段前缀(默认不加前缀,外键表字段默认以外键名作为字段的前缀)"""
        _dict = {}
        try:
            field = self._meta.get_field(field_name)
            _value = getattr(self, field_name)

            if prefix is not None:
                field_name = prefix+'_'+field_name

            if isinstance(field, models.DateTimeField):  # DateTimeField字段特殊处理,做两种类型的格式化
                if _value is not None:
                    _dict[field_name] = _value.strftime(DATETIME_FORMAT)
                    _dict['%s_short' % field_name] = _value.strftime(DATE_FORMAT)
                else:
                    _dict[field_name] = ''
                    _dict['%s_short' % field_name] = ''
            elif isinstance(field, models.DateField):  # DateField字段做格式化处理
                if _value is not None:
                    _dict['%s_short' % field_name] = _value.strftime(DATE_FORMAT)
                else:
                    _dict['%s_short' % field_name] = ''
            else:
                _dict[field_name] = _value

        except FieldDoesNotExist:
            return getattr(self, field_name)

        return _dict


    def serializable_values(self, field_name_list=None):
        """数据序列化;field_name_list 需要序列化的字段名列表(默认None,表示此model中的字段全部序列化)"""
        _dict = {}

        if not field_name_list:  # 如果field_name_list字段为None,则遍历此model,获取全部字段
            field_name_list = []
            for i in self._meta.fields:
                field_name_list.append(i.attname)

        for field_name in field_name_list:  # 序列化

            if isinstance(field_name, dict):  # 获取外键表的字段值
                for key in field_name:  # key->外键名
                    field = self._meta.get_field(key)
                    obj_external_table = getattr(self, key)

                    if isinstance(field, models.ManyToManyField):  # 多对多字段,单独处理
                        _list_e = []
                        for e in obj_external_table.all():
                            _list_e.append(e.serializable_values(field_name[key]))

                        _dict[key] = _list_e
                    else:    # 一对一,一对多字段,统一处理
                        for k in field_name[key]:
                            _dict = dict(_dict, **obj_external_table.get_value(k, key))
            else:  # (2017-03-24更新)
                _values = self.get_value(field_name)
                if type(_values) == dict:
                    _dict = dict(_dict, **_values)
                else:  # 如果此字段是方法(使用了装饰器@property),做单独处理
                    _dict = dict(_dict, **{"field_name":_values})

        return _dict

2.事例:一对多model

一作者对应多文章

class Author(CModel):
    """作者"""
    username = models.CharField(max_length=32, verbose_name=u'作者姓名')

    def __unicode__(self):
        return self.username


class Article(CModel):
    """文章"""
    author = models.ForeignKey(Author)
    title = models.CharField(max_length=64, verbose_name=u'文章标题')
    content = models.TextField(verbose_name=u'文章内容')
    write_date = models.DateTimeField(verbose_name=u'发布时间')

    def __unicode__(self):
        return self.title

3.事例:一对一model

一教室编号对应一教室 (事例不贴切,见谅)

class Classroom(CModel):
    """教室"""
    position = models.CharField(max_length=64, verbose_name=u'教室所在位置')

    def __unicode__(self):
        return self.position


class ClassNumber(CModel):
    """教室编号"""
    number = models.CharField(max_length=32, verbose_name=u'教室编号')
    classroom = models.OneToOneField(Classroom, verbose_name=u'教室')

    def __unicode__(self):
        return self.number

4.事例:多对多model

一用户组对用多个菜单;一菜单对应多个用户组

class Menu(CModel):
    """菜单"""
    name = models.CharField(max_length=32, verbose_name=u'菜单名称')

    def __unicode__(self):
        return self.name


class Group(CModel):
    """用户组"""
    name = models.CharField(max_length=32, verbose_name=u'组名')
    menu = models.ManyToManyField(Menu, verbose_name=u'菜单')

    def __unicode__(self):
        return self.name

5.视图

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from django.shortcuts import render
from app.models import *
from django.views.generic import View
from django.http import JsonResponse
# 可以对应着上面的model类看一下下面list中的字段类型,字典里是要显示的外联表的字段(外键可以是ForeignKey,ManyToManyField,OneToOneField类型)
article_field_list = ['id', 'title', 'content', 'write_date', {'author': ['id', 'username']}]
group_field_list = ['id', 'name', {'menu': ['id', 'name']}]
classnumber_field_list = ['id', 'number', {'classroom': ['id', 'position']}]


class ArticleView(View):
    """文章视图类"""
    def get(self, request):
        _list = Article.objects.all()
        _rtn = [i.serializable_values(article_field_list) for i in _list]

        result = {"data": _rtn}
        return JsonResponse(result)


class GroupView(View):
    """用户组类"""
    def get(self, request):
        _list = Group.objects.all()
        _rtn = [i.serializable_values(group_field_list) for i in _list]

        result = {"data": _rtn}
        return JsonResponse(result)


class ClassNumberView(View):
    """教室类"""
    def get(self, request):
        _list = ClassNumber.objects.all()
        _rtn = [i.serializable_values(classnumber_field_list) for i in _list]

        result = {"data": _rtn}
        return JsonResponse(result)

6.URL配置

from django.conf.urls import url
from django.contrib import admin
from app.views import ArticleView, GroupView, ClassNumberView

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^get/article$', ArticleView.as_view()),
    url(r'^get/group$', GroupView.as_view()),
    url(r'^get/classroom$', ClassNumberView.as_view()),
]

结果图

1.一对一
django 数据序列化的实现_第1张图片
2.一对多
django 数据序列化的实现_第2张图片
3.多对多
django 数据序列化的实现_第3张图片
详细代码,请参见我的github:https://github.com/apple9005/django-serializable

你可能感兴趣的:(python,django)