跬步 On Coding

Django-Elasticsearch实现搜索功能

在项目中实现了资讯搜索功能,用到了Django Tastypie haystack Elasticsearch ik分词,覆盖了我对搜索了解的所有姿势。其实也就了解一些简单的概念,不过haystack+elasticsearch并不需要太多搜索基础,只要看看haystack文档就就能实现简单的搜索需求了。

搭建Elasticsearch环境

http://www.sojson.com/blog/81

参考以上文档搭建了自己的ES环境,然后再安装Django实现搜索的相关库:

django-haystack==2.4.1
elasticsearch==2.3.0
elasticstack==0.4.1

haystack不用说,在Django中实现搜索基本上都会用到,因为要用到Elasticsearch的BackEnds,所以要装elasticsearch,最后elasticstack会在下面说到。

haystack使用ik分词

在elasticsearch中可以在创建了indexs后可以在settings中自定义analyzer,在创建types时可以设置各个field使用的analyzer,但是在haystack中就比较麻烦了。

https://github.com/django-haystack/django-haystack/issues/639

从上面的issues中可以看出,如果需要解决这个问题,需要重写elasticsearch backends中相关设置,在查看了elasticsearch backends代码后,发现除了DEFAULT_SETTINGS中配置自定义analyzer,DEFAULT_FIELD_MAPPINGFIELD_MAPPINGS分别用于设置field在mapping中analyzer,重写相关配置与方法可达到定义不同字段的分词器。

但是重写配置方法还是太麻烦了,能不能更简单点呢,所以找到了elasticstack,用上了这个工具后,配置默认的analyzer就非常简单了。

HAYSTACK_CONNECTIONS = {
    'default': {
        'ENGINE': 'elasticstack.backends.ConfigurableElasticSearchEngine',
        'URL': 'http://127.0.0.1:9200/',
        'INDEX_NAME': 'haystack',
    },
}

ELASTICSEARCH_DEFAULT_ANALYZER = 'ik' # 设置默认分词器为ik

Django save方法的update_fields参数

在Django中对Model对象的属性赋值,并使用save方法,save方法并不会检测Model对象变更了什么属性,而是会使用update语句set所有的field为当前的值,也就是说只修改了部分字段,也会update所有字段的值,这样会导致2个问题:

  1. SQL语句过大,导致SQL执行慢(一般也不会有什么影响)
  2. 如果同时操作同一个Model对象,更新不同的字段,后save的操作会用老的值覆盖掉早点操作的值

所以推荐在调用save方法的时候传update_fields参数,但是这样就要求我们必须对每次save的fields都在代码中记下来,不是很方便,所以开发一个通用的专门用来处理update_fields参数的Mixin类来解决这个问题。

Tastypie实现accesstoken认证

Tastypie提供了几种基本的认证方式比如SessionAuthentication,Django实现的web站点一般都是基于cookie-session的认证方式,在Django中使用中间件的方式处理cookie与session,以及用户认证。使用起来是很方便的。

但是在api中就不能继续使用cookie了,我们会使用accesstoken的方式来实现认证。之前同事使用redis实现了一版accesstoken的认证,但是由于考虑不周全,导致在使用过程中出现了很多bug,然后为了解决bug又写了很多恶心的兼容代码,所以抽空直接使用熟悉的session重构了认证过程。

Django验证码实现与登录验证码展示策略

Django实现验证码有很多现成可用的库,Google后选择Django Simple Captcha,需要做一些展示与表单验证方面的定制。

验证码展示

默认的验证码展示形式不是很适合我们网站的样式,所以在settings中做了一些定制。

# 验证码设置
CAPTCHA_FOREGROUND_COLOR = '#d83a46' # 验证码字体颜色
CAPTCHA_BACKGROUND_COLOR = '#f5f5f5' # 验证码背景颜色
CAPTCHA_NOISE_FUNCTIONS = ('captcha.helpers.noise_dots',) # 验证码混淆配置,这里设置的点点
CAPTCHA_CHALLENGE_FUNCT = 'random_char_challenge' # 验证码生成函数配置

为了提供验证码的识别率,定制了一个随机字符串生成函数来生成验证码。

# coding: utf-8

import random
from captcha.conf import settings
from six import u

def random_char_challenge():
    chars, ret = u('acefghkprtuvwxy34679'), u('')
    for i in range(settings.CAPTCHA_LENGTH):
        ret += random.choice(chars)
    return ret.upper(), ret

python玩转数据笔记:数据处理

时间索引

>>> import pandas as pd
>>> index = pd.date_range('20160503', periods=5)
>>> index
DatetimeIndex(['2016-05-03', '2016-05-04', '2016-05-05', '2016-05-06',
               '2016-05-07'],
              dtype='datetime64[ns]', freq='D')