# 搞懂Django中的class Meta
- edited: 2019.10.24
---
## Resource - 關於@staticmethod及@classmethod
- [@staticmethod和@classmethod的用法](https://blog.csdn.net/GeekLeee/article/details/52624742)
- [python @classmethod 的使用场合](https://blog.csdn.net/dyh4201/article/details/78336529)
- [ Python 文章收集 : 深刻理解 Python 中的元類 (metaclass) ](http://puremonkey2010.blogspot.com/2015/02/python-python-metaclass.html)
- [必看!Python “黑魔法” 之 Meta Classes](https://segmentfault.com/a/1190000004426130)
- [廖雪峰-使用元类](https://www.liaoxuefeng.com/wiki/1016959663602400/1017592449371072)
>- 廖雪峰這篇下半段, 有針對Django ORM的實做解析, 必看
## Intro
- 我們在Django中宣告Model時, 一般會如下定義我們的Model, ex:宣告一個Person
```
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=30)
age = models.IntegerField()
# 定義一個class Meta並宣告資料要呈現的方式, ex: ordering...
# Meta支援的功能可參考:
# http://www.liujiangblog.com/course/django/99
class Meta:
ordering = ['pub_date']
```
- 使用上相當方便,宣告`class Meta`後,緊跟著加入資料的功能(ex: 排序),即可取得預期的排序資料
## 問題探討:
- 問題來了, 這個`class Meta`有什麼關係??
- 嚴格上來說,`class Meta`這個`子class`,與python的` __metaclass__`<font color='blue'>並無直接關係,而是屬於間接關係</font>
- 在宣告新的model class時,我們繼承`models.Model`,這個父類別使用的metaclass為`ModelBase`,這個metaclass就是在背後協助`models.Model`來處理`Meta`支援的項目
- 來看一下[Django-git上的程式碼](https://github.com/django/django/blob/stable/2.0.x/django/db/models/base.py), 相關說明寫於code的commend中
- `django/db/models/base.py`
```
# === 71 line, class ModelBase ===
class ModelBase(type): #<--注意!他是類(type), 也就是python最底層的物件
"""Metaclass for all models."""
def __new__(cls, name, bases, attrs):
super_new = super().__new__
...
# === 89 line, 取得 Meta這個class物件
attr_meta = attrs.pop('Meta', None)
abstract = getattr(attr_meta, 'abstract', False)
if not attr_meta:
meta = getattr(new_class, 'Meta', None)
else:
meta = attr_meta # <-- 有抓到Meta就給meta吧
...
# === 134 line, 處理class Meta底下的功能, ===
if base_meta and not base_meta.abstract:
# Non-abstract child classes inherit some attributes from their
# non-abstract parent (unless an ABC comes before it in the
# method resolution order).
if not hasattr(meta, 'ordering'):
new_class._meta.ordering = base_meta.ordering
if not hasattr(meta, 'get_latest_by'):
new_class._meta.get_latest_by = base_meta.get_latest_by
...
...
# === 393 line, class Model ===
class Model(metaclass=ModelBase): # <-- 使用ModelBase當作metaclass
...
```
## 小結:
- 這也是為什麼, 其他django內建的model class, ex: ` django.contrib.auth.models.User`, 均可支援`class Meta`, 因為追溯源頭, 是`ModelBase`幫了一把!!
```
from django.contrib.auth.models import User
User.__base__ # <--User繼承AbstractUser
>>> <class 'django.contrib.auth.models.AbstractUser'>
from django.contrib.auth.models import AbstractUser
AbstractUser.__base__ # <--AbstractUser繼承AbstractBaseUser
>>> <class 'django.contrib.auth.base_user.AbstractBaseUser'>
from django.contrib.auth.models import AbstractBaseUser
AbstractBaseUser.__base__ # <--AbstractBaseUser繼承至Model, 所以都支援class Meta啦!!
>>> <class 'django.db.models.base.Model'>
```
## 補充說明:什麼是python的類(type)?
- 簡單來說, 所有的東西, 都源自於同一個根, 這個根在python中, 就稱為`類(type)`
- 開啟terminal觀察一下:
```
>>> a=5 # 宣告一個int物件, 並查看他的型態
>>> a.__class__
<class 'int'> # 沒錯!型態是int
>>> a.__class__.__class__ # 那int底層的型態又是什麼呢?
<class 'type'> # 答案就是我們討論的 type
```
- 從上面的例子我們可以發現, 所有型態物件的`根`, 就是`類type`
- 要搞懂類, 你可以看[ Python 文章收集 : 深刻理解 Python 中的元類 (metaclass) ](http://puremonkey2010.blogspot.com/2015/02/python-python-metaclass.html)