跬步 On Coding

python玩转数据笔记:数据结构

想储备点数据分析相关知识,所以抽了1天时间上了1门数据分析入门的公开课,记录一下学到的东西。

python玩转数据

ndarray 多维数组

>>> import numpy as np
>>> np.ones((3,4)) # 自动生成3*4的二维数组,全为1
array([[ 1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.]])
>>> np.array([[1,2], [3,4]])
array([[1, 2],
       [3, 4]])
>>> np.zeros((1,2)) # 生成全为0
array([[ 0.,  0.]])
>>> np.arange(1,10,1) # 类似于range生成列表
array([1, 2, 3, 4, 5, 6, 7, 8, 9])

网站账号绑定微信方案

一般面向用户的网站都会有一些通知用户的需求,传统的方式会通过email,短信等等方式,鉴于微信的流行,像拉勾会使用微信来做通知。通过微信通知就需要把网站内部的账户体系与微信关联起来,目前体验比较好的绑定方式是通过微信扫描二维码来绑定用户账号。
从用户的角度来看,扫一扫绑定,很简单的功能,但是在研究了微信开发文档后,从开发的角度来看,其实流程还是比较复杂的,所以这里整理一下实现思路。

博客迁移到github

为什么迁移

blog算是我正式的第一个Python项目,是我入门Python的基石,一直稳定的运行在SAE上,上个月我还进行过一次升级,但是SAE的MySQL服务收费来得太突然,每年大概要花200软妹币,对于一个PaaS平台来说,我认为是不划算的,鉴于静态博客的流行,所以痛下决心迁移到github pages上来。

静态博客生成器的选择

  • Jekyll
    Jekyll是静态博客生成器的鼻祖,拥有大量的模版,但是基于ruby导致文章较多的情况下会比较慢
  • pelican
    python是工作语言,所以本来是最可能选择的就是pelican,直到我找到hugo
  • hugo
    golang实现,最大的优点就是快,而且golang可以编译为二进制文件,所以安装起来非常方便

Django Model Trace 模型变更跟踪

在公司业务中有很多模块需要记录模型的变更历史,刚开始的时候会针对需要变更记录的表增加一个变更记录表,然后做针对性的开发。后来类似的需求多了,而且不需要很详细的记录,所以单独提取了一个比较简单的模型跟踪模块出来。

原理

使用Django自己的信号实现,创建了一个公用的model跟踪表,所有配置跟踪的model变更记录都会保存到这张表中,通过一个公用的trace_model函数来保存变更的新老数据,而且只保存修改的字段。

# coding=utf-8

import inspect, json
from django.conf import settings
from django.db.models import ManyToManyField, ManyToOneRel
from django.db.models.fields.related import ForeignKey
from raven.contrib.django.models import client
from models import ModelRecord


def trace_model(sender, instance, raw, using, update_fields, **kwargs):
    try:
        if instance._state.adding is True:
            return
        obj = sender.objects.get(pk=instance.pk)
        change_fields = {}
        for name in sender._meta.get_all_field_names():
            if name in ('add_by', 'add_dt', 'update_by', 'update_dt', 'update_by_id'): # 更新人,添加人,时间不记录
                continue
            field = sender._meta.get_field(name)
            if field.auto_created or field.hidden or field.__class__ in (ManyToManyField, ManyToOneRel): # 特殊的字段不记录
                continue
            old = getattr(obj, name, None)
            new = getattr(instance, name, None)
            if str(old) == str(new): # 不同类型的字段转为字符串,相等的不记录
                continue
            if isinstance(field, ForeignKey):# 如果是外键
                if name != field.name and not field.name in change_fields:
                    if old:
                        old = field.related_model.objects.filter(pk=old).first()
                    if new:
                        new = field.related_model.objects.filter(pk=new).first()
                elif name == field.name and not name+'_id' in change_fields:
                    pass # 判断避免同时对外键赋值的清空
                else:
                    continue
            if field.choices:
                if old:
                    old = getattr(obj, 'get_'+field.name+'_display', old)
                if new:
                    new = getattr(instance, 'get_'+field.name+'_display', new)
                if callable(old):
                    old = old()
                if callable(new):
                    new = new()
            old = str(old) if old is not None else '空'
            new = str(new) if new is not None else '空'
            verbose_name = getattr(field, 'verbose_name', name)
            change_fields[name] = {
                'name': verbose_name,
                'new': new,
                'old': old
            }
        dbname = getattr(sender, '_database', settings.DATABASES['default']['NAME'])
        for frame_record in inspect.stack():
            if frame_record[3] == 'get_response':
                request = frame_record[0].f_locals['request']
                user = request.user
                break
        # 数据入库
        if change_fields and 'user' in locals():
            ModelRecord.objects.create(dbname=dbname,
                                       table_name=sender._meta.db_table,
                                       table_pk = instance.pk,
                                       content=json.dumps(change_fields),
                                       add_by=user)
    except Exception:
        client.captureException()

Tastypie入门小结

Tastypie是什么

Tastypie是基于Django的RESTful api开发框架,如果你有一个通过Django实现的网站,那么通过Tastypie写少许的代码就能实现一个全功能的REST api。

我要写些什么

这不是一篇Tastypie的入门教程,如果需要教程,可以从官方文档开始,我写的只在探索Tastypie的过程中我认为值得记录的地方。

Getting Started with Tastypie