内容简介:自定义一个Django的Model Filed--StaticJSONField
使用JSON保存用户数据的问题
有时候我们会用json来保存一些杂乱的数据,比如一个用户的各种信息,这些信息被序列化为一个json字符串并最终存放在数据库的一个column里面。
user.config = { "accept_notification": True, "accept_invitation": True, "level": "golden" }
使用json保存这些配置的好处在于,添加或者修改属性的时候你不需要对数据库进行修改。在关系型数据库看来,这个config不过是一个字符串而已。
但是这样做也会有一些问题,比如:
-
有时候写了错别字,依然可以正常地保存到数据库:
user.config["leel"] = “golden”
- 删除json里面的字段时需要遍历数据库,将所有的json里面对应字段删除,不然它们会一直占用空间。
-
获取数据时,往往需要添加一个默认值:
user.config.get("level", "golden")
,因为你无法确认level是否一定在config里面。
使用 __getattr__
以及 __setattr__
的一个解决方案
__getattr__
和 __setattr__
是 python 的魔术方法,用它可以对自定义的类添加一些特殊的效果。
调用instance.atttibute的时候, 如果这个attribute没有明确的在instance所属的类里面明确定义,就会触发对 __getattr__
的访问。调用instance.attribute = value的时候,必然会命中对 __setattr__
的访问。基于这两个原理,我们可以编写这么一个类:
class InvalidAttributeException(Exception): pass class StaticJSON(object): def __init__(self, default, value=None): value = value or {} self.__dict__["_default"] = default self.__dict__["_value"] = value for k, v in self._default.items(): self.__dict__["_value"].setdefault(k, v) def __getattr__(self, name): if name in self.__dict__.get("_default", {}): return self.__dict__["_value"][name] else: raise AttributeError(name) def __setattr__(self, name, value): if name == "_default" or name == "_value": setattr(self.__dict__[name], name, value) if name not in self.__dict__["_default"]: raise InvalidAttributeException("{} is not a valid attribute, try {} instead".format( name, ", ".join(self.__dict__["_default"].keys()) )) self.__dict__["_value"][name] = value def items(self): """ used for serializer.to_representation """ return self._value.items() def __iter__(self): """ for i in StaticJSON: pass """ for item in self._value: yield item
看着上面代码有一点头晕,这里我们举一个例子,我们可以这么使用这个类:
# 用户的默认属性 default= { "accept_invitation": True, "accept_notification": False, "level": "golden" } # 用户的属性 value = { "level": "diamond" } config = StaticJSON(default=default, value=value) # 因为value里面明确定义了level是diamond,因此这边获取到的是value的值 config.level >>>diamond config.level = "golden" # 用户没有定义accept_notification 属性,因此返回的是默认值 config.accept_notification >>> False # 调用未定义的属性, 报错 config.non_exist_attribute = "some attribute" >>> Traceback (most recent call last): File "<input>", line 1, in <module> config.non_exist_attribute = "some attribute" File "static_json.py", line 34, in __setattr__ raise InvalidAttributeException("{} is not a valid attribute, try {} instead".format( __console__.InvalidAttributeException: non_exist_attribute is not a valid attribute, try accept_invitation, accept_notification, level instead # 像字典一样对这个instance迭代: for key in config: print(key, getattr(config, key)) for key,value in config.items(): print(key, value)
总而言之,我们做了这几件事情:
-
__init__
函数接受默认值(default)以及实际值(value),并将这些数据分别保存到<StaticJSON instance>._default
以及<StaticJSON instance>._value
里面. 如果传入的default里面有一些attribute在value里面不存在,那么就用default去填充它。 -
编写
__getattr__
方法,这个方法使得在获取值的时候(<StaticJSON instance>.attribute
), 实际从<StaticJSON instance>._value
里面获取,如果找不到, 说明这个attribute不应该被访问,报错。 -
编写
__setattr__
方法,在赋值的时候(<StaticJSON instance>.attribute = value
), 先检查这个attribute是否符合被允许, 然后保存到<StaticJSON instance>._value
里面。 -
编写
_iter_
以及items
方法吗,因此我们可以使用类似for key,value in instance.items():
或者for key in instance
两种方法对这个instance进行迭, 其实也就是让<StaticJSON instance>
表现的更加像字典。
为了让这个类更加像字典, 我们还可以实现 __getitem__
, __setitem__
方法。
实现一个Django的自定义Field
上面的 StaticJSON
可以用来对数据进行修改,查询,但是不能够被直接定义到Djanog的model里面,为此我们需要实现一个StaticJSONField,具体的实现代码在 gist
里面。
一般来讲我们可以这样定义一个model:
from somewhere import StaticJSONField class User(Model): DEFAULT_CONFIG = { "accept_invitation": True, "accept_notification": False "level": "golden" } name = models.CharField(max_length=20) config = StaticJSONField(default=DEFAULT_SUMMARY) print(user.config.level) user.config.level = "diamond" user.config.accept_notification = False
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Android 自定义 View (04自定义属性)
- Vue自定义组件(简单实现一个自定义组件)
- Android 自定义View:深入理解自定义属性(七)
- Qt编写自定义控件20-自定义饼图 原 荐
- SpringBoot2 | SpringBoot自定义AutoConfiguration | SpringBoot自定义starter(五)
- 『互联网架构』软件架构-springboot自定义视图和自定义Starter(90)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
技术元素
[美] 凯文·凯利 / 张行舟、余倩、周峰、管策、金鑫、曾丹阳、李远、袁璐 / 译言·东西文库/电子工业出版社 / 2012-5 / 55.00元
我会将我不成熟的想法、笔记、内心争论、草稿以及对其他文章的回应都写在《技术元素》中,这样我就能知道自己到底在想些什么。——KK “技术元素”(technium)是凯文•凯利专门创造出来的词语。“技术元素不仅仅包括一些具象的技术(例如汽车、雷达和计算机等),它还包括文化、 法律、社会机构和所有的智能创造物。”简而言之,技术元素就是从人的意识中涌现出来的一切。KK把这种科技的延伸面看成一个能产生......一起来看看 《技术元素》 这本书的介绍吧!