Django 1.6 最佳实践: Django项目中的小工具

在我们的博客中, 记录了我们在开发过程中所使用的技术和遇到的问题, 希望作为其他开发和设计者的一个学习交流平台.

Django 1.6 最佳实践: Django项目中的小工具


1. 自定义工具

有时为了完成Django项目, 我们不得不自己写一些通用的function, class等工具. 这些临时工具不属于任何一个特定的app, 而我们又不希望将这些工具放在其他相关的app中, 而变得难以查找到和再次利用.

我们的方式是将他们放入一个名字为core的django app中(也可以叫utils, generic等):

    core/
        __init__.py
        managers.py # 包含自定义的model manager
        models.py
        views.py # 包含自定义的view mixin

注意, 不要漏掉models.py, 为了是core app成为django app, models.py是必须的.

2. Django自带工具

在django中, 包含了许多自带的工具:

django.contrib.humanize

提供了一系列用于本地化的template filter, 例如intcomma可以将整数转化为带有逗号或点的字符串. 你也可以单独引入其中的工具作为function使用.

django.utils.encoding.force_text(value)

该util可以将任何东西转为文本字符串, 避免了显示django.utils.functional.__proxy__.

django.utils.functional.cached_property

作为decorator使用, 可以将单个method的结果进行cache, 具体使用方法见https://docs.djangoproject.com/en/dev/ref/utils/#module-django.utils.functional.

django.utils.html.format_html(format_str. *args, **kwargs)

类似于Python的str.format(), 但专为html设计. 所有的args和kwargs中的HTML tag都会自动去除后再传到str.format().

django.utils.html.remove_tags(value, tags)

当我们需要从用户那边接受内容, 但有希望过滤掉特定tag时, 可以使用.

django.utils.html.strip_tags(value)

当我们需要从用户那边接受内容, 但有希望过滤掉所有html tag时, 可以使用.

django.utils.six

six是一个python2和python3兼容库.

django.utils.timezone

最好开启django的timezone功能, 因为我们的用户可能住在不同的时区. 但我们开启timezone支持后, 时间信息将会以UTC形式储存在数据库中, 并在显示时自动转为当地时间.

3. Exception

django自带了许多exception, 大多数是供内部使用的, 但还有一些exception则可以被狠和好的利用.

django.core.exceptions.ImproperlyConfigured

用于设置错误抛出错误, 我们在之前的博文中讨论过: Django 1.6 最佳实践: 如何设置django项目的设置(settings.py)和部署文件(requirements.txt).

django.core.exceptions.ObjectDoesNotExist

这是所有DoesNotExist exception的最基本class, 当我们获取未知类型model时十分有用:

    from django.core.exceptions import ObjectDoesNotExist

    class BorkedObject(object):
        loaded = False

    def generic_load_tool(model, pk):
        try:
            instance = model.objects.get(pk=pk)
        except ObjectDoesNotExist:
            return BorkedObject()
        instance.loaded = True
        return instance

django.core.exceptions.PermissionDenied

这一exception用于用户未被授权执行某一操作时抛出, view则会自动返回django.http.HttpResponseForbidden.

4. Serializer 和 Deserializer

当用到JSON, Python, YAML或XML数据时, 我们都可以使用django自带的Serializer和Deserializer:

    from django.core.serializers import get_serializer

    from favorites.models import Favorite

    # json可以替换成python或xml, 如果装了pyyaml, 也可替换成pyyaml
    JSONSerializer = get_serializer("json")
    serializer = JSONSerializer()

    favs = Favorite.objects.filter()[0:5]

    serialized_data = serializer.serialize(favs)

    with open("data.json", "w") as f:
        f.write(serialized_data)
    from django.core.serializers import get_serializer

    from favorites.models import Favorite

    favs = Favorite.objects.filter()[0:5]

    # json可以替换成python或xml, 如果装了pyyaml, 也可替换成pyyaml
    JSONSerializer = get_serializer("json")
    serializer = JSONSerializer()

    with open("data.txt") as f:
        serialized_data = f.read()

    # deserialize model 数据
    python_data = serializer.deserialize(serialized_data)

    for element in python_data:
        print(type(element))

        print(
            element.object.pk
            element.object.created
        )

Python自带的JSON模块无法处理date/time 和 decimal类型, 但django提供了一个JSONEncoder class:

    import json

    from django.core.serializers.json import DjangoJSONEncoder
    from django.utils import timezone
    
    data = {"date": timezone.now()}
    
    # 如果不使用DjangoJSONEncoder, 则会出错
    json_data = json.dumps(data, cls=DjangoJSONEncoder)
    
    print(json_data)

django的YAML serializer由pyyaml支持, 但又解决了python到yaml中时间转换的问题. yaml 的deserialization使用的是yaml.safe_load(), 因此避免了code injection.

django的XML serializer使用的是Python自带的XML模块, 但结合了defusedxml库, 防止了xml bomb攻击.


原文链接: http://weiguda.com/blog/39/