一探Bear熊笔记的客户端设计架构

我用来做笔记的应用是bear note(熊笔记),我喜欢这个应用有两个原因:漂亮;还有根据tag来给文章分类的设计,完全摒弃了文件夹的概念,这一点可以说是非常棒了。比如要实现类似这种通过日期和文章类别来给文章分类的,只需要添加如下tag即可。我真的是很佩服bear产品经理天才般的创意。

640?wx_fmt=jpeg

最近想做一个将bear写的文章自动转换为微信公众号、知乎等平台文章格式的项目。第一步需要做的,当然就是先看看熊笔记是怎么保存文章数据的,我原本以为就是简单的一些保存md和图片的目录而已。

然而并没有这么简单。

bear保存文章的目录在

~/Library/Group Containers/9K33E3U3T4.net.shinyfrog.bear/Application Data

目录结构为640?wx_fmt=jpeg可见,主数据全部都用sqlite数据库来保存了,然后把图片全部存在Note Images这个目录下面。 所以思路也就很清晰了,需要研究研究这个sqlite中的表、字段和文件之间的对应关系。

table概览

640?wx_fmt=jpeg从名字和字段可以推测,ZSFNOTE和ZSFNOTETAG是两个比较重要的table,分别存放的是正文和标签的数据。

用django处理sqlite数据 平时django用得比较多,看到这个sqlite,自然就想到了可以使用django啊,django的现成orm可以极大减少我们的开发量。而且这样还有一个好处就是,扩展性极强,可以很容易实现这样一个需求,上传一个你的sqlite文件,就可以从中提取出文章和标签内容,之后的想象力空间就很大很大了,比如实现一键同步其他内容平台,一键导出为md文件,一键生成pdf等等。

将sqlite文件导入django model

配置DATABASES:

BEAR_SQLITE_DATABASE = "/path/to/database.sqlite"	
DATABASES = {	
    'default': {	
        'ENGINE': 'django.db.backends.sqlite3',	
        'NAME': BEAR_SQLITE_DATABASE,	
    }	
}

新建一个app bear

python manage.py startapp bear

使用inspectdb命令从数据库中提取出model

python manage.py inspectdb > bear/models.py

这就会在bear/models.py创建相关的model:

  • 存放文章具体数据的model

class Zsfnote(models.Model):	
    z_pk = models.IntegerField(db_column='Z_PK', primary_key=True, blank=True, null=True)  # Field name made lowercase.	
    z_ent = models.IntegerField(db_column='Z_ENT', blank=True, null=True)  # Field name made lowercase.	
    z_opt = models.IntegerField(db_column='Z_OPT', blank=True, null=True)  # Field name made lowercase.	
    zarchived = models.IntegerField(db_column='ZARCHIVED', blank=True, null=True)  # Field name made lowercase.	
    zencrypted = models.IntegerField(db_column='ZENCRYPTED', blank=True, null=True)  # Field name made lowercase.	
    zhasfiles = models.IntegerField(db_column='ZHASFILES', blank=True, null=True)  # Field name made lowercase.	
    zhasimages = models.IntegerField(db_column='ZHASIMAGES', blank=True, null=True)  # Field name made lowercase.	
    zhassourcecode = models.IntegerField(db_column='ZHASSOURCECODE', blank=True, null=True)  # Field name made lowercase.	
    zlocked = models.IntegerField(db_column='ZLOCKED', blank=True, null=True)  # Field name made lowercase.	
    zorder = models.IntegerField(db_column='ZORDER', blank=True, null=True)  # Field name made lowercase.	
    zpermanentlydeleted = models.IntegerField(db_column='ZPERMANENTLYDELETED', blank=True, null=True)  # Field name made lowercase.	
    zpinned = models.IntegerField(db_column='ZPINNED', blank=True, null=True)  # Field name made lowercase.	
    zshownintodaywidget = models.IntegerField(db_column='ZSHOWNINTODAYWIDGET', blank=True, null=True)  # Field name made lowercase.	
    zskipsync = models.IntegerField(db_column='ZSKIPSYNC', blank=True, null=True)  # Field name made lowercase.	
    ztodocompleted = models.IntegerField(db_column='ZTODOCOMPLETED', blank=True, null=True)  # Field name made lowercase.	
    ztodoincompleted = models.IntegerField(db_column='ZTODOINCOMPLETED', blank=True, null=True)  # Field name made lowercase.	
    ztrashed = models.IntegerField(db_column='ZTRASHED', blank=True, null=True)  # Field name made lowercase.	
    zfolder = models.IntegerField(db_column='ZFOLDER', blank=True, null=True)  # Field name made lowercase.	
    zserverdata = models.IntegerField(db_column='ZSERVERDATA', blank=True, null=True)  # Field name made lowercase.	
    zarchiveddate = models.TextField(db_column='ZARCHIVEDDATE', blank=True, null=True)  # Field name made lowercase. This field type is a guess.	
    zconflictuniqueidentifierdate = models.TextField(db_column='ZCONFLICTUNIQUEIDENTIFIERDATE', blank=True, null=True)  # Field name made lowercase. This field type is a guess.	
    zcreationdate = models.TextField(db_column='ZCREATIONDATE', blank=True, null=True)  # Field name made lowercase. This field type is a guess.	
    zlockeddate = models.TextField(db_column='ZLOCKEDDATE', blank=True, null=True)  # Field name made lowercase. This field type is a guess.	
    zmodificationdate = models.TextField(db_column='ZMODIFICATIONDATE', blank=True, null=True)  # Field name made lowercase. This field type is a guess.	
    zorderdate = models.TextField(db_column='ZORDERDATE', blank=True, null=True)  # Field name made lowercase. This field type is a guess.	
    zpinneddate = models.TextField(db_column='ZPINNEDDATE', blank=True, null=True)  # Field name made lowercase. This field type is a guess.	
    ztrasheddate = models.TextField(db_column='ZTRASHEDDATE', blank=True, null=True)  # Field name made lowercase. This field type is a guess.	
    zconflictuniqueidentifier = models.TextField(db_column='ZCONFLICTUNIQUEIDENTIFIER', blank=True, null=True)  # Field name made lowercase. This field type is a guess.	
    zlasteditingdevice = models.TextField(db_column='ZLASTEDITINGDEVICE', blank=True, null=True)  # Field name made lowercase. This field type is a guess.	
    zsubtitle = models.TextField(db_column='ZSUBTITLE', blank=True, null=True)  # Field name made lowercase. This field type is a guess.	
    ztext = models.TextField(db_column='ZTEXT', blank=True, null=True)  # Field name made lowercase. This field type is a guess.	
    ztitle = models.TextField(db_column='ZTITLE', blank=True, null=True)  # Field name made lowercase. This field type is a guess.	
    zuniqueidentifier = models.TextField(db_column='ZUNIQUEIDENTIFIER', blank=True, null=True)  # Field name made lowercase. This field type is a guess.	
    zvectorclock = models.BinaryField(db_column='ZVECTORCLOCK', blank=True, null=True)  # Field name made lowercase.	
    class Meta:	
        managed = False	
        db_table = 'ZSFNOTE'
  • 存放标签信息的model

class Zsfnotetag(models.Model):	
    z_pk = models.IntegerField(db_column='Z_PK', primary_key=True, blank=True, null=True)  # Field name made lowercase.	
    z_ent = models.IntegerField(db_column='Z_ENT', blank=True, null=True)  # Field name made lowercase.	
    z_opt = models.IntegerField(db_column='Z_OPT', blank=True, null=True)  # Field name made lowercase.	
    zmodificationdate = models.TextField(db_column='ZMODIFICATIONDATE', blank=True, null=True)  # Field name made lowercase. This field type is a guess.	
    ztitle = models.TextField(db_column='ZTITLE', blank=True, null=True)  # Field name made lowercase. This field type is a guess.	
    class Meta:	
        managed = False	
        db_table = 'ZSFNOTETAG'
  • views.py

def notelist(request):	
    notes_obj = Zsfnote.objects.all()	
    notes = []	
    for note in notes_obj:	
        notes.append({	
            'title': note.ztitle,	
            'subtitle': note.zsubtitle,	
            'text': note.ztext,	
            'lasteditingdevice': note.zlasteditingdevice,	
            'uniqueidentifier': note.zuniqueidentifier,	
            'deleted': note.zpermanentlydeleted,	
            'created_at': note.zcreationdate,	
            'updated_at': note.zmodificationdate	
        })	
    return render(request, 'bear/notelist.html', {	
        'notes': notes,	
    })
  • 模板文件:nodelist.html

 <table class="ui celled table">	
        <thead>	
        <tr>	
            <th>更新于</th>	
            <th>创建于</th>	
            <th>上次编辑设备</th>	
            <th>标题</th>	
            <th>副标题</th>	
        </tr>	
        </thead>	
        <tbody>	
        {% for note in notes %}	
            <tr>	
                <td data-label="更新于">{{ note.updated_at }}</td>	
                <td data-label="创建于">{{ note.created_at }}</td>	
                <td data-label="上次编辑设备" style="min-width: 140px">{{ note.lasteditingdevice }}</td>	
                <td data-label="标题">{{ note.title }}</td>	
                <td data-label="副标题">{{ note.subtitle }}</td>	
            </tr>	
        {% endfor %}	
        </tbody>	
    </table>

最后渲染出的结果图

640?wx_fmt=jpeg

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值