GitDigger 0.1.0 开发日志

发表于2017年07月19日

2017-11-02

由于时间问题,暂时停止此项目的开发。除项目和个人页面外其它页面/功能都可以不做,毕竟这两个页面用处比较大,以后看能不能花些时间设计一下。

2017-08-21

pip install misaka 报错:

misaka\hoedown/buffer.h(9) : fatal error C1083: Cannot open include file: 'stdint.h': No such file or directory

Visual C++ for Python 没有带 stdint.h 文件,解决方法:C99 stdint.h header and MS Visual Studio,手动下载 stdint.h 文件复制到 C:\Users\<你的用户名>\AppData\Local\Programs\Common\Microsoft\Visual C++ for Python\9.0\VC\include 目录下。

2017-08-13

迁移数据库时想重命名,可以用 rename_table()

资讯的多主题搜索功能可以参考这个问答:Flask-SQLAlchemy query many-to-many tagging with multiple requred tags

2017-08-12

查询资讯列表时还要判断每条资讯是否被用户投过票,这个看上去比较复杂,以前学的 SQL 知识在现在还只记得 SELECT、FROM、WHERE、ORDER BY 这类简单的语句,找了相关资料,可以用 CASE 和 LEFT JOIN 语句。折腾了一下,SQL 代码算是完成了,接下来需要将它转换为适用于 SQLAlchemy 的 Python 代码。

Python 代码如下,然而 Issue 模型里的 user 属性却无法访问。

user_id = current_user.id if current_user.is_authenticated else 0
terms = Voter.target_id==Issue.id and Voter.target_type=='issue'
case = db.case([(Voter.user_id==user_id, True)], else_=False)
query = db.session.query(Issue, case.label('has_voted'))
feeds = query.outerjoin(Voter, terms).order_by(Issue.score.desc()).all()

原来查询到的列表的元素类型是元组,需要这样才能访问到 user 属性:

for feed, has_voted in feeds:
    print feed.user 
    print has_voted

然而又有问题,投过票的 Issue,会有会重复记录。看来在 SQL 上花太多时间会影响进度,还是优先把其它页面都弄出来吧。

尝试手写 SQL 去除重复记录,加了 Voter.user_id==user_id 条件后,结果正常。然而写成 SQLAlchemy 版的却没效果,打印出的 SQL 内容中并未追加新的条件。最后找到了这篇内容:sqlalchemy - join child table with 2 conditions,原来是需要调用 and_() 方法追加条件,修改后的代码如下:

user_id = current_user.id if current_user.is_authenticated else 0
terms = db.and_(Voter.target_id==Issue.id, Voter.user_id==user_id)
case = db.case([(Voter.user_id==user_id, True)], else_=False)
query = db.session.query(Issue, case.label('has_voted'))
query = query.order_by(Issue.score.desc(), Issue.created_at.desc())
query = query.outerjoin(Voter, terms)
feeds = query.all()

2017-08-08

刚开始还以为只需要启动 Celery 一个进程就够了,然而启动后预设的定时任务并没有执行,后来才发现启动的只是职程,需要发信号给这个进程它才会执行任务,也就是再开一个进程:

celery beat --app app.celery

2017-08-06

感觉 ExtractTextPlugin 和 expose-loader 有冲突,编辑保存 js 后,生成的 vendor.js 是正常的,app.js 里可以调用 $,如果再编辑一下 scss,生成的 vendor.js 中的 jQuery 并没有导出到全局。解决办法嘛,再新建个 common.js 文件专门引入 css 文件,与其它 js 文件独立开来,这样就不会影响到 vendor.js 的内容了。

2017-08-03

有些比较耗时的任务和定时任务可以异步执行,看来需要添加任务队列了,还要搞个管理后台页面,用来查看当前在跑哪些任务。

这打包总有问题,把 jQuery、Bootstrap 的 js 打包到 vendor.js 里,有时全局可以用 jQuery, 有时又不行。在 vendor.js 里加一些测试代码,有时生成出来的 vendor.js 里根本找不到这些测试代码。

2017-08-02

Bootstrap 的下拉框不支持 hover 时显示,好吧,就这样吧。

Dropdowns are toggleable, contextual overlays for displaying lists of links and more. They’re made interactive with the included Bootstrap dropdown JavaScript plugin. They’re toggled by clicking, not by hovering; this is an intentional design decision.

2017-07-29

改用了 PostgreSQL 数据库。

完善了 GitHub 账号登录,GitHub 账号快速注册功能暂时不做。

作为 GitHub 应用被安装后,只需要提供一个 webhook 给 GitHub 调用就能接收到各种事件数据,还可以在网页端配置需要哪些类型的事件,方便了很多。之前看文档还以为要调用项目的 webhooks 去发请求为项目创建 webhook。

2017-07-25

自己写了个装饰器,然而 Flask 报错说视图函数覆盖了现有的 endpoint 函数:

View function mapping is overwriting an existing endpoint function: repos.wrapper

看上去函数在加上装饰器后 Flask.route() 得到的视图函数的名称都是 wrapper ,网上搜索了装饰器相关的文章,据说可以用 functools.wraps 保留函数元信息。

2017-07-24

每为仓库添加一个接口都要写重复的代码,例如:

@repos.route('/<string:username>/<string:name>/settings', methods=['GET'])
def settings(username, name):
    repo = get_repo(username, name)
    if repo is None:
        return abort(404)
    return render_template('repositories/settings/index.html', repo=repo)

@repos.route('/<string:username>/<string:name>', methods=['GET'])
def show(username, name):
    repo = get_repo(username, name)
    if repo is None:
        return abort(404)
    return render_template('repositories/show.html', repo=repo)

感觉好麻烦,要是能写个装饰器简化操作就好了。

@repo_route('/settings', methods=['GET'])
def settings(repo):
    pass

@repo_route('/', methods=['GET'])
def show(repo):
    pass

如何设置 Flask 的蓝图(Blueprint)的默认模板查找位置?看文档说可以设置 template_folder 参数,然而总报错说找不到模板。

添加仓库的设置页面,导航菜单的选项连接是用 url_for() 函数获取的,然而要写全参数才行:

url_for('repos.settings', username=repo.owner.username, name=repo.name)

要是能像 Rails 那样写成 url_for_repo_settings(repo) 就好了。或者自己预先定义好这些变量,然后当参数传进模板里?

感觉上面几个功能可以写成一个模块,命名为 repo_helper.py,然后代码就可以简化成这样:

<a href="{{ url_for_repo }}">Home</a>
<a href="{{ url_for_repo_settings }}">Settings</a>
@repo_hepler.route('/settings', methods=['GET'])
def settings(repo):
    return repo_hepler.render('settings/index.html')

@repo_hepler.route('/', methods=['GET'])
def show(repo):
    return repo_hepler.render('show.html')

@repo_hepler.route('/hooks/<string:hookid>', methods=['GET'])
def hooks(repo, hookid):
    return repo_hepler.render('hooks/show.html')

自动为模板添加 repourl_for_repo_settingsurl_for_repo 参数,不用再手动传递,方便了很多。

访问 hello/hello 这两个路径的效果居然不一样,访问 hello 时浏览器会自动跳转到 hello/,然而 Flask 并未找到与 hello/ 绑定的函数,返回 404,有什么办法让 Flask 自动重定向,将地址末尾的斜杠去掉?

2017-07-23

完成了:

修改表结构后,SQLAlchemy 升级失败,报错:

sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) near "ALTER": syntax error [SQL: u'ALTER TABLE repository ALTER COLUMN name SET NOT NULL']

懒得折腾了,直接删库重建。

2017-07-22

完成了:

2017-07-19

买入了 gitdigger.com 和 gitdigger.io 两个域名,准备搞个网站,设计文档还在完善中,到时候再贴出来。欢迎各位 Python 大佬提供技术支持。