博客

django 1.9 i18n 国际化和本地化

网上一堆讲 django 国际化与本地化的文档。不说太多。

django 1.9 以后(也有可能是 1.8 以后),zh_CN/zh_TW 不推荐用了,改为 zh_Hans/zh_Hant,这个作为 locale 下的文件夹名。

在 settings.py 文件里,用 LANGUAGE_CODE = 'zh-hans' 或 LANGUAGE_CODE = 'zh-hant' 似乎是官方推荐的。(注意这里是连字符,文件夹是下划线)

我碰到的问题是,用 django-admin makemessages -l zh_Hans 后,能够在 app_name/locale 下面生成 zh_Hans 文件夹及对应的 po 文件。编辑文件后,用 django-admin compilemessages,能把 po 文件编译出对应的 mo 文件,但是网页上死活出不来中文。

settings.py 里 'django.middleware.locale.LocaleMiddleware', 这句也加在 MIDDLEWARE_CLASSES 里了,USE_I18N、USE_L10N 默认就设为 True,也没改过。折腾半天,有个网页说有可能是 django 找不到 locale 的位置,需要在 settings.py 里写出来,于是加上:

LOCALE_PATHS = [
    os.path.join(BASE_DIR, 'app_name/locale'),
]

搞定!

另外目前 Django REST Framework 好像还不支持 zh-hans 这样写。

Topic: 技术

dup2.com 上线 LDAP 全局地址簿功能

1. 必须认证后才能访问
2. 仅仅支持 SSL or TLS 访问
3. 认证后可搜索本域的子树

4. 在 iOS 和 outlook 上测试通过;EI Capitan 对认证模式的访问有 bug,之前的版本应该没问题

Topic: 电子邮件

dup2.com 上线全局邮件存档功能

邮箱管理员可以给自己管理的域设一个用来存档的 email 地址。

当这个 email 地址验证通过并开启存档开关后,这个域所有的出入 email 都会被密送(暗送)到这个用来存档的 email 地址上去,达到全局邮件存档的效果。

Topic: 电子邮件

Django REST framwork 报 NOT NULL constraint failed 的处理

我碰到这个问题由来是,在某个 model 里,foo_id、bar_id 两个字段都是别的表里的外键,但是在 serializer 里我又不想显示 foo_id,而想显示 foo_id 所代表的真正的意义

  1. class FooBarRelationshipSerializer(serializers.HyperlinkedModelSerializer):
  2.     foo = serializers.SerializerMethodField()
  3.     bar = serializers.CharField(write_only=True, required=False)
  4.     def get_foo(self, obj):
  5.         return Foo.objects.get(pk=obj.foo_id).name  # foo_id 来自 urls.py 里的相关 router 的定义
  6.     def validate(self, data):
  7.         del data['bar']
  8.         return data
  9.     class Meta:
  10.         model = FooBarRelationship
  11.         fields = ('foo', 'bar')

通过上面这段代码能很好地达到我的目的。好,问题来了,我想把 foo_id 和 bar_id 的关系存入表中,如果用 foo_id 和 bar_id 的话,request.data 里必然存在输入的 bar_id,但是我的实际输入是 bar,我必须要重载 validate 方法,把 bar 去掉,那么我在 views.py 里手动把 bar 对应的 bar_id 取到,然后塞进 request.data 里好了。然后

  1. serializer = self.get_serializer(data=request.data)
  2. if serializer.is_valid(raise_exception=True):
  3.         serializer.save(foo_id=foo_id)

想得挺好,运行时却报了 NOT NULL constraint failed 的错!!!

网上搜了半天,没有什么结果,提供的答案都是告诉你检查一下是不是有必填的字段没有给数据。但真正碰到这个问题的,而且还寄望通过搜索解决问题的,基本上都会先保证必填的字段里有数据,可现在数据都有了,为什么还会报这个错???

我打印了 FooBarRelationshipSerializer 里用 foo_id 和 bar_id 时的 request.data 和现在的 request.data,里面的数据一模一样!!!但是就是前者的 serializer.save 能成功,后者报错。。。

思来想去,可能同样的 request.data,但经过 serializer = self.get_serializer(data=request.data) 后,serializer 会不同,谁知道 get_serializer 里有什么鬼(不看源码了)。尝试直接把 bar_id 作为参数传给 save 方法,就像这样 serializer.save(foo_id=foo_id, bar_id=bar_id),结果当然是成功存入数据库。哈哈。

Topic: 技术

Django REST framework serializer 跟 model 无关的只写(write_only) field 的处理

有时候想在 DRF 的 api 里塞一些跟 model 无关的,但又是必须要处理的数据,比如设密码时,为了保证输入无误第二次输入的 password,这种信息一般设为只写。
这个时候 serializers.py 里,把 validate 方法重载一下,在里面删掉 request.data 里实际上 model 不需要的数据就 ok 了。

  1. class AccountListSerializer(serializers.HyperlinkedModelSerializer):
  2.     password = serializers.CharField(write_only=True, style={'input_type': 'password'})
  3.     confirm_password = serializers.CharField(write_only=True, style={'input_type': 'password'})
  4.     def validate(self, data):
  5.         del data['confirm_password']
  6.         return data
  7.     class Meta:
  8.         model = Account
  9.         fields = ('password', 'confirm_password')

当然,在 views.py 里,需要校验一下 password 和 confirm_password 是否输入了,如果输入了,是否一致

  1. if not request.data.get('password') or not request.data.get('confirm_password'):
  2.     raise serializers.ValidationError("Please input password and confirm it!")
  3. if request.data.get('password') != request.data.get('confirm_password'):
  4.     raise serializers.ValidationError("Passwords do NOT match!")
Topic: 技术

Django REST framework serializer 跟 model 无关的只读(read_only)field 的处理

有时候想在 DRF 的 api 里塞一些跟 model 无关的信息,比如一些提示的信息,这种信息本身跟业务没有关系,设为只读。
这个时候 serializers.py 里:

  1. class FooSerializer(serializers.HyperlinkedModelSerializer):
  2.     foo = serializers.CharField(read_only=True)
  3.     tips = serializers.CharField(source='get_tips', read_only=True)
  4.     class Meta:
  5.         model = Foo
  6.         fields = ('foo', 'tips')

这个时候 models.py 里:

  1. class Foo(models.Model):
  2.     foo_id = models.AutoField(primary_key=True)
  3.     foo = models.CharField(max_length=128)
  4.     def get_tips(self):
  5.         return 'Please foo bar.’
  6.     class Meta:
  7.         db_table = 'foo'
Topic: 技术

dup2.com 上线邮件组功能

邮件组的可投递级别分为 4 个级别:
0 - 无限制(任何人都能往邮件组发信)
1 - 同一域名内的 email 地址和白名单中的 email 地址可以往邮件组发信
2 - 邮件组内 email 地址和白名单中的 email 地址可以往邮件组发信

3 - 仅白名单中的 email 地址可以往邮件组发信

Topic: 电子邮件

dup2.com 上线自动回复功能

仅仅针对本域内的邮件传送进行自动回复

用户可以设置自动回复生效的时间段

当前每个发件人只会收到一封自动回复

Topic: 电子邮件

dup2.com 昨晚上线查看"邮件投递报告"功能

目前该功能仅邮件用户可用,可查看自己最近50封发出的邮件,和50封从外部送达的邮件;暂时还不提供管理员查询域下来往邮件的功能

PS: 东京机房正在进一步测试中,预计将于一个月内搬迁过去

Topic: 电子邮件
订阅 RSS - 博客 | BT的花