美文网首页
Models and databases 之三 自定义File

Models and databases 之三 自定义File

作者: 低吟浅唱1990 | 来源:发表于2017-06-11 13:29 被阅读81次

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

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

    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()。

    • from_db_value()
      当数据重数据库中被加载的时候调用,即查询的时候。函数用于转化数据库中的字符到 Python的变量
    • to_python()
      需要反序列化和表单中调用clean()方法的时候调用。把数据编程Python对象。to_python需要处理的是 正确的对象,字符串和None,需要判断。 函数用于转化数据库中的字符到 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对象映射成数据库里的字段,反之亦然。

    • description类属性表示类的描述
      从Field到数据库中的字段,数据库提供了一下方法
    • get_internal_type()
      返回一个字符串,已表明相应的在数据库中的类型,通常是Field的类名
    def get_internal_type(self): return 'CharField'
    
    • db_type(connection)
      结合连接的数据(MySQL),返回此Field在数据表中数据类型
    • rel_db_type(connection)
      与db_type(connection)功能类似,只不过在字段充当外键的时候用
    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)
    
    • get_prep_value(value)
      value表示当时model相应属性的值。返回一个能够用于查询参数的格式化数据。
      If your custom field uses the CHAR, VARCHAR or TEXT types for MySQL, you must make sure that get_prep_value() always returns a string type.

    • get_db_prep_value(value, connection, prepared=False)
      某些数据需要有特定格式存储于数据库中,get_db_prep_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
    
    • from_db_value(value, expression, connection, context)
      把从数据库返回的数据 转换成Python变量。是 get_prep_value()反向操作

    • to_python(value)
      把value转换成一个Python对象。与value_to_string(obj)是相反的操作。model调用clean()时候调用

    • value_to_string(obj)
      把一个对象转成字符串,序列化对象的值

    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)
    

    相关文章

      网友评论

          本文标题:Models and databases 之三 自定义File

          本文链接:https://www.haomeiwen.com/subject/wxdcqxtx.html