Models and databases 之三 自定义File

2017-06-11  本文已影响81人  低吟浅唱1990

大部分情况下我们使用Django的标准字段(field)就可以满足一般需求,但是有时不能满足特定需求。Django的内置字段也没有覆盖数据库的全部字段,只是一些常用字段。

Python对象直接序列化适应数据库的字段

class Hand(object):
    def __init__(self,north,east,south,west):
          self.north = north
          self.east = east
          self.south = south
          self.west = west

以上是一个普通的Python类,假设在model中有一个hand属性,同时hand属性时一个Hand的实例。

>>>example = MyModel.objects.get(pk=1)
>>>print(example.hand.north)
>>>new_hand = Hand(north,east,south,west)
>>>example.hand = new_hand
>>>exmple.save()

Field子类化

Django的Field都是继承django.db.models.Field。在自定义Field之前,找到你想要的Field与Django内置的哪个Field相似。

from django.db import models
class HandField(model.Field):
        description = "A hand of cards (bridge style)"
        def __init__(self,*args,**kwargs):
              kwargs['max_length']= 104
              super(HandField,self).\_\_init__(*args,**kwargs)
      def deconstruct(self):
            name,path,args,kwargs = super(HandField,self).deconstruct()
            del kwargs['max_length']   #处理添加的信息
            return name,path,args,kwargs

HandField继承了大多数的字段选项,只是重写了max_length选项以适应52张牌的

改变自定义字段的类型名,继承基类之后,重写db_type()方法
比如时间在PostgreSQL中叫做 timestamp,而在MySQL是 datetime

from django.db import models
class MytypeField(models.Field):
    def db_type(self,connection):
          if connection.settings_dict['ENGINE']=='django.db.backends.mysql':
              return 'datetime'
          else:
              return 'timestamp'
          #return 'mytype'

db_type() and rel_db_type()方法在创建表和查找相关字段的时候被调用。(rel_db_type()当字段被当做外键或者一对一关系的时候调用)

当期望的数据结构不是基本类型(string,dates,integers,floats)的时候需要重写from_db_value() and to_python()。

import re
from django.core.exceptions import ValidationError
from django.db import models
from django.utils.translation import ugettext_lazy as _
def parse_hand(hand_string):
      p1 = re.compile('.{26}')
      p2 = re.compile('..')
      args = [p2.findall(x) for x in p1.findall(hand_string)]
      if len(args) != 4
            raise ValidationError(_("Invalid input for a Hand instance"))
      return Hand(*args)
class HandField(models.Field):
      def from_db_value(self,value,expresson,connection,context):
              if value is None:
                  return value
              return parse_hand(value)
      def to_python(slef,value):
              if isinstance(value,Hand):return value
              if value is None:
                    return value
              return parse_hand(value)
      def get_prep_value(self, value): #将Python对象转换为查询值
          return ''.join([''.join(l) for l in (value.north,value.east, value.south, value.west)])

class Field 是一个抽象类,其子类表示数据表中的一列(字段)。把Python对象映射成数据库里的字段,反之亦然。

def get_internal_type(self): return 'CharField'
There are three main situations where Django needs to interact with the database backend and fields:
•when it queries the database (Python value -> database backend value)
•when it loads data from the database (database backend value -> Python value) 
•when it saves to the database (Python value -> database backend value)
def get_db_prep_value(self, value, connection, prepared=False):
      value = super(BinaryField, self).get_db_prep_value(value,            connection, prepared) 
      if value is not None:
            return connection.Database.Binary(value) 
      return value
def value_to_string(self, obj):
      value = self.value_from_object(obj) 
      return self.get_prep_value(value)

下面是一个例子来自 自强学院

from django.db import models
import ast
class ListField(models.TextField):
    __metaclass__ = models.SubfieldBase
    description = "Stores a python list"
 
    def __init__(self, *args, **kwargs):
        super(ListField, self).__init__(*args, **kwargs)
 
    def to_python(self, value):
        if not value:
            value = []
        if isinstance(value, list):
            return value
        return ast.literal_eval(value)
    def get_prep_value(self, value):
        if value is None:
            return value
        return str(value)
    def value_to_string(self, obj):
        value = self._get_val_from_obj(obj)
        return self.get_db_prep_value(value)
上一篇下一篇

猜你喜欢

热点阅读