django proxy model

django 中的代理类
当你希望给原有对象进行增删改操作又不想改动源代码的时候,代理类就是为解决这个问题而生。代理类不同于子类。

代理类的定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Create your models here.
class Person(models.Model):
first_name = models.CharField('FristName',max_length=20)
last_name = models.CharField('LastName',max_length=10)
class SDPerson(Person):
class Meta:
proxy = True
def say_name(self):
return self.first_name

通过在子类SDPerson的Meta类中添加proxy属性,将SDPerson声明为代理类。

1
2
3
4
5
6
>>> SDPerson.objects.create(first_name="Kong")
<SDPerson: SDPerson object>
>>> SDPerson.objects.get(first_name='Kong')
<SDPerson: SDPerson object>
>>> Person.objects.get(first_name='Kong')
<Person: Person object>

代理类可以通过属性搜到原类,原类也可以通过属性搜索到代理类。但是通过Person得到的QuerySet仍旧是Person对象,所以调用say_name方法会报错。

1
2
3
4
5
6
7
8
9
>>> from demo.models import Person,SDPerson
>>> sd = SDPerson.objects.get(first_name='Kong')
>>> sd.say_name()
u'Kong'
>>> p = Person.objects.get(first_name='Kong')
>>> p.say_name()
Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: 'Person' object has no attribute 'say_name'

代理类不允许定义字段:

1
2
ERRORS:
?: (models.E017) Proxy model 'SDPerson' contains model fields.

代理类Manager的重定义

如果想要自定义Manager,可以通过继承models.Manager来实现:

1
2
3
4
5
6
7
8
9
10
11
12
class NewManager(models.Manager):
pass
class SDPerson(Person):
objects = NewManager()
class Meta:
proxy = True
def say_name(self):
pass

这样就替换掉了默认的manager。如果不希望替换默认的,则可以通过定义抽象类的方式进行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class NewManager(models.Manager):
pass
class ExtraManager(models.Model):
secondary = NewManager()
class Meta:
abstract = True
class SDPerson(Person,ExtraManager):
objects = NewManager()
class Meta:
proxy = True
def say_name(self):
pass

这样SDPerson就有了第二个Manager:

1
2
3
4
5
6
7
8
>>> from demo.models import Person,SDPerson
>>> SDPerson.secondary.all()
<QuerySet [<SDPerson: SDPerson object>]>
>>> SDPerson.secondary.all()[0]
<SDPerson: SDPerson object>
>>> SDPerson.secondary.all()[0].first_nmae
>>> SDPerson.secondary.all()[0].first_name
u'Kong'

model文件分成多个

删除models.py 创建models文件夹,然后将model文件导入到init.py