为什么要自己去序列化呢?为什么不用restful呢?
django做全栈开发真的很不错,但做前、后端分离开发时,某些方面可能需要调整。比如,数据的序列化这个问题,跨域问题;当然,这都不是什么大问题。。。下面说说数据序列化
后端与前端通过json数据格式交互数据;django 通过orm读取的数据,不能直接用django的serializable或python的序列化方式;那怎么办?用restful吧,有专门的针对django的 django restful fremework,具体使用方式,请参见官方文档:http://www.django-rest-framework.org/
有同事吐槽restful,嫌麻烦,因为用restful还需要额外写model什么的。。。。那怎么办?只能自己造轮子了!
本项目:
1.实现了将从数据库获取到的数据,序列化为json格式,返回给前端
2.从数据库读取到的date、datetime字段,做了格式化处理
3.获取到的从表数据,在做处理时,将需展现的字段做了重命名处理,防止从表与主表字段冲突
2.暂未将前端提交的json映射到model
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
1.获取model中不存在的字段数据时,抛出异常,个人认为这个异常无需捕获。
2.实现了将从数据库获取到的数据,序列化为json格式,返回给前端
3.暂未将前端提交的json映射到model
创建django项目,创建app略过。。。
所有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
一作者对应多文章
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
一教室编号对应一教室 (事例不贴切,见谅)
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
一用户组对用多个菜单;一菜单对应多个用户组
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
#!/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)
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.一对一
2.一对多
3.多对多
详细代码,请参见我的github:https://github.com/apple9005/django-serializable