Django models 里的类为什么要用类变量而不是实例变量?

2014-12-14 12:49:29 +08:00
 kidlj

刚刚接触Django,读它的overview 文档,发现在models.py里的类没有定义__init__方法,而是定义了类变量(Class Variable):

class Reporter(models.Model):
                full_name = models.CharField(max_length=70)

而后却能正常初始化实例:

r = Reporter(full_name='John Smith')

我知道这里肯定是用了什么魔法,比如metaclass之类的东西。可是为什么不直接将这些变量定义为在__init__方法之中的实例变量?

4085 次点击
所在节点    Python
13 条回复
RIcter
2014-12-14 13:00:49 +08:00
看一下 models.Model 的源码_(:з」∠)_
在 __init__ 里有写..虽然窝看不太懂OAQ
messense
2014-12-14 13:01:00 +08:00
用了 metaclass 和 descriptor,建议去读一下 model 部分的源码。
RIcter
2014-12-14 13:04:09 +08:00
另外定义成 __init__ 方法中的变量多丑..
比如:

def __init__(self, name, title):
缩缩self.name = name
缩缩self.title = title
缩缩super(SampleModel, self).__init__()

...麻烦死了辣
bcxx
2014-12-14 13:22:31 +08:00
@RIcter 不是丑不丑的问题,是用类变量才能让这个 model 类的 instance 都具有相同的 mapping。具体实现就是 @messense 提到的用 metaclass 来在 __new__ 的时候进行处理。
kidlj
2014-12-14 13:30:34 +08:00
@RIcter @messense Django源码我就先不读了,先把应用写起来吧。只是乍一看到类里面统统使用类变量感觉奇怪,觉得这肯定是有什么目的的。

@bcxx “用类变量才能让这个 model 类的 instance 都具有相同的 mapping”,虽然目前还看不懂这句话,但是起码知道了这里使用类变量而不是实例变量的必要性,是有其理由的。
messense
2014-12-14 13:33:14 +08:00
@kidlj Django 的实现比较复杂,可以先看看 peewee 这个小巧的 ORM 框架里的实现方法,挺简单的。
messense
2014-12-14 13:37:11 +08:00
metaclass 和 descriptor 这些“魔法”可以实现一些很优雅的东西,ORM 是其中之一。我写的 wechatpy 项目用 metaclass 和 descriptor 实现了对微信公众号消息的 mapping 和生成,也比较简单。

https://github.com/messense/wechatpy/blob/master/wechatpy/messages.py#L29
kidlj
2014-12-14 13:53:48 +08:00
找到了这么一条解释:

“ Django provides a metaclass for Model which scans class attributes and converts them to instance attributes but only if they subclass Field.”

http://stackoverflow.com/a/22993791

但比起从类变量到实例变量的转化是怎么实现的,我目前更想知道的是为什么不直接使用实例变量,而非要用类变量的方式呢?这个问题可以等到以后再去考察吧。

我想现在先认识到这种使用方法就够了。感谢大家。
messense
2014-12-14 14:00:13 +08:00
@kidlj 使用实例变量的话 Django 不好从 model 生成 SQL 啥的,用类变量通过 metaclass Django 在运行时记录了所有的信息,然后可以做生成 SQL、验证数据啥的。实例变量你再赋值,Field 信息就没了......
ccdjh
2014-12-14 14:15:10 +08:00
没想过回复的,不小心,不知道,手一抖,点了感谢 @RIcter -_-
为了不让你困惑,告诉你,我是不小心点感谢回复你的,没其他意思。

平时用tornado,自己写一个简单通用于各数据model。只有几行代码。你可以看一下mongodb的例子:

https://github.com/ccdjh/boxmongodb


使用StringProperty() 这些是因为,
1,我是通过def __new__(cls,**arg) 返回一个用于检测数据的列表,并且方便输入初始值
2,可以接纳一些设定值
ccdjh
2014-12-14 17:00:50 +08:00
@messense

谢谢。虽然只有一个文件,你也统统看完并且修改,这是对代码的一种认真认可。

就像小学生作业一样,满篇红红的,搞的自己挺不好意思的哈。
完整的安装文件你可以在这里获取:
https://pypi.python.org/pypi/boxmongodb

这本身就是一个demo文件,我并没有释放更新出来。而且有许多错误的地方。
1,安装的时候出现依赖版本错误
2,AuthProperty的__new__问题,值的更新
3,ModelFilter的__new__废除,使用静态函数

还有很多,包括使用到redis和sqlite等。。

并没有贬性的意思。代码修改后,有运行过么?出错误了

就像0 star一样,有人认真我都很开心了。
但你应该使用后,提出使用问题,提出上面的错误,我会超兴奋和高兴。

但你没有使用,但你没有提出bug,而是对我屎一样的代码风格提出纠正更改,我羞愧死了哈。

谢谢!
virusdefender
2014-12-15 00:21:34 +08:00
kfll
2014-12-15 08:21:21 +08:00
用实例变量的话,继承和覆盖不就显得麻烦了么…

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/153811

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX