自强学堂
自强学堂:学习、分享、让你更强!
Django 教程HTMLCSSJAVASCRIPTJQUERYSQLPHPBOOTSTRAPANGULARXML
 

Django 自定义Field

Django 的官方提供了很多的 Field,但是有时候还是不能满足我们的需求,不过Django提供了自定义 Field 的方法:

提示:如果现在用不到可以跳过这一节,不影响后面的学习,等用到的时候再来学习不迟。

来一个简单的例子吧。

1. 减少文本的长度,保存数据的时候压缩,读取的时候解压缩,如果发现压缩后更长,就用原文本直接存储:

Django 1.7 以下

from django.db import models

class CompressedTextField(models.TextField):
    """    model Fields for storing text in a compressed format (bz2 by default)    """
    __metaclass__ = models.SubfieldBase

    def to_python(self, value):
        if not value:
            return value

        try:
            return value.decode('base64').decode('bz2').decode('utf-8')
        except Exception:
            return value

    def get_prep_value(self, value):
        if not value:
            return value

        try:
            value.decode('base64')
            return value
        except Exception:
            try:
                tmp = value.encode('utf-8').encode('bz2').encode('base64')
            except Exception:
                return value
            else:
                if len(tmp) > len(value):
                    return value

                return tmp

to_python 函数用于转化数据库中的字符到 Python的变量, get_prep_value 用于将Python变量处理后(此处为压缩)保存到数据库,使用和Django自带的 Field 一样。

Django 1.8 以上版本,可以用

#coding:utf-8
from django.db import models


class CompressedTextField(models.TextField):
    """
    model Fields for storing text in a compressed format (bz2 by default)
    """

    def from_db_value(self, value, expression, connection, context):
        if not value:
            return value
        try:
            return value.decode('base64').decode('bz2').decode('utf-8')
        except Exception:
            return value

    def to_python(self, value):
        if not value:
            return value
        try:
            return value.decode('base64').decode('bz2').decode('utf-8')
        except Exception:
            return value

    def get_prep_value(self, value):
        if not value:
            return value
        try:
            value.decode('base64')
            return value
        except Exception:
            try:
                return value.encode('utf-8').encode('bz2').encode('base64')
            except Exception:
                return value

Django 1.8及以上版本中,from_db_value 函数用于转化数据库中的字符到 Python的变量


2. 比如我们想保存一个 列表到数据库中,在读取用的时候要是 Python的列表的形式,我们来自己写一个 ListField

这个ListField继承自 TextField,代码如下:

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 unicode(value) # use str(value) in Python 3

    def value_to_string(self, obj):
        value = self._get_val_from_obj(obj)
        return self.get_db_prep_value(value)

使用它很简单,首先导入 ListField,像自带的 Field 一样使用:

class Article(models.Model):
    labels = ListField()

在终端上尝试(运行 python manage.py shell 进入):

>>> from app.models import Article
>>> d = Article()
>>> d.labels
[]
>>> d.labels = ["Python", "Django"]
>>> d.labels
["Python", "Django"]

示例代码:

zqxt_custom_fields_project.zip

下载上面的代码,解压,进入项目目录,输入 python manage.py shell 搞起

>>> from blog.models import Article

>>> a = Article()
>>> a.labels.append('Django')
>>> a.labels.append('custom fields')

>>> a.labels
['Django', 'custom fields']

>>> type(a.labels)
<type 'list'>

>>> a.content = u'我正在写一篇关于自定义Django Fields的教程'
>>> a.save()


参考网址:

https://djangosnippets.org/snippets/2014/

https://docs.djangoproject.com/en/dev/howto/custom-model-fields/

自强学堂 源代码下载:https://github.com/twz915/zqxt
服务承诺:2017年03月11日到12日出现了网站不可访问,不少同学发来了邮件关心,感谢大家对自强堂Django教程的支持与厚爱。自强学堂不会关闭,我向大家承诺,我依然会坚持每天答疑,看邮件回复邮件,服务器费用已经缴纳三年,后期会努力提高服务稳定性。我也还至少会再坚持做三年,直到2020年03月12日,我愿意坚持做这件事,是因为我认为这很有意义,2015年劳动节开始写这个教程的时候,我没有想到如今,每天会有5000人来自强学堂看Django教程,我希望能帮助到更多的人。—— 2017年03月12日于北京深夜 涂伟忠