在Web开发中,省/市/区(县)是经常需要用到的数据,而省/市/区(县)是一种层级关系。在使用Django做Web开发时,此时Django-mptt是一个很有用的模块。

首先执行pip install django-mptt安装django-mptt模块如test-django中示例那样,建立area应用,在area的models.py里添加如下model

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#coding:utf-8
from __future__ import unicode_literals

from django.db import models
from mptt.models import MPTTModel, TreeForeignKey

# Create your models here.

class Area(MPTTModel):
name = models.CharField(max_length=50, unique=True)
parent = TreeForeignKey('self', verbose_name=u'上级区域', null=True, blank=True, related_name='children')

class MPTTMeta:
order_insertion_by = ['name']

class Meta:
db_table = 'area'
verbose_name = verbose_name_plural = (u'省/市/地区(县)')

def __unicode__(self):
return self.name

在area的admin.py里添加

1
2
3
4
5
6
7
8
9
from django.contrib import admin

# Register your models here.
from .models import Area


class AreaAdmin(admin.ModelAdmin):
list_display = ('id', 'name', 'parent', 'level')
admin.site.register(Area, AreaAdmin)

在项目的settings里INSTALLED_APPS里添加mptt和area,之后执行数据库操作。之后在admin后台中就可以按照层级关系添加省/市/区(县)数据。

当然最好的方式还是用程序导入。从统计局上爬取数据后导入到数据库中。

对于mptt要想深入理解的,可以参考这篇文章hierarchical-data-database

联系作者

当使用git reset回退到某个后,想再回到当前版本,而git log中看不到当前的版本,此时reflog就派上用场了。

  • git reflog 查看版本操作信息,在这里可以看到版本号,之后使用git reset进行版本切换

参考资料:

联系作者

reset命令用于重置到某个状态。

常用的命令如下

  • git reset
    将所有add到缓存区的操作撤销,如果需要对某个文件撤销,可以使用git reset 文件名

  • git reset –hard
    撤销所有的修改,可以在–hard后添加版本后,表示reset到某个版本

参考资料:

联系作者

在使用git时,checkout也是一个常用的命令。

  • git checkout foo 切换到foo分支
  • git checkout foo 当本地没有foo分支时,相当于同步远程分支,此时相当于执行git checkout -b <branch> --track <remote>/<branch>
  • git checkout -b foo 创建foo分支,其实想到与执行了git branch foogit checkout foo两条命令
  • git checkout – file 恢复file文件

常见问题

  • 在github上看到有远程分支,但git checkout feature_name无法切换到这个分支,此时可能的一个原因是没有拉取远程分支, 此时需要使用git fetch origin feature-name进行拉取。

参考资料:

联系作者

理解了fetchmerge后,之后再来看git pull就容易多了。在git的官方文档上,有git pull is shorthand for git fetch followed by git merge FETCH_HEAD,也就是说git pull是git fetch和git merge的结合,只是这里的merge是fast-forward方式。

依然在test-git仓库上进行测试,

使用`git log –graph –pretty=oneline –abbrev-commit`查看log,

1
2
3
4
5
6
7
8
9
10
11
*   dee871e Merge remote-tracking branch 'origin/master'
|\
| * d28cd1d add no-fast-forward in test-pull.md
|/
* 35bbd63 add fast-forward in test-pull.md
* 6ce6fab Merge branch 'feature-noff-merge'
|\
| * 710e832 add noff-merge.md
|/
* 5747a77 add merge.md
* d2adf39 Initial commit
  • 在结果中, add fast-forward in test-pull.md使用git pull直接拉取远程分支的变化得到的
  • 而add no-fast-forward in test-pull.md是通过执行 git fetch origin mastergit merge --no-ff origin/master两个命令后的结果。

从上面的结果可以看出,使用git fetchgit merge --no-ff更能保存仓库版本变化的轨迹,推荐使用这种方式。

参考资料:

联系作者

分支操作是一个常见的操作。当在某一分支开发完新功能后,需要合并到master分支,此时就需要使用merge命令。

merge有两种方式,一种是fast-forward, 一种是非fast-forward方式。

  • git merge feature 使用fast-forward方式合并feature分支
  • git merge –no-ff feature 使用非fast-forward方式合并。

这两种方式的差别在于是否保留分支合并的信息。为此特意在github上建了一个test-git仓库。

使用git log --graph在master分支上查看log时,可以很方便的看出两种方式的区别。这里添加了一些参数,使结果更简洁
`git log –graph –pretty=oneline –abbrev-commit`

1
2
3
4
5
6
*   6ce6fab Merge branch 'feature-noff-merge'
|\
| * 710e832 add noff-merge.md
|/
* 5747a77 add merge.md
* d2adf39 Initial commit
  • 图中merge.md是在feature-merge分支中添加的,使用fast-forward方式merge
  • noff-merge.md是在feature-noff-merge中添加的,使用非fast-forward方式merge

参考资料:

联系作者

在开发新功能时,需要创建分支,此时branch命令派上用场了。branch的一些常用命令如下

  • git branch foo 创建foo分支

  • git branch -d foo 删除foo分支

  • git branch 查看本地分支
  • git branch -r 查看远程分支

当只是想拉取远程分支时,则需要添加参数, git branch foo --track origin/foo 同步远程foo分支。但是,拉取远程分支有更常用的命令git checkout foo

常见问题

  • 在开发的过程中会遇到的问题是,明明github的仓库上有某个分支,使用git branch -r却看不到这个分支,这是因为还没有拉取这个分支到本地,此时使用git fetch origin feature_name拉取分支后,再次执行git branch -r即可看到分支

参考资料:

联系作者

有些时侯我们想知道一个文件的某一行在哪一个版本里被谁修改的,此时git blame就派上用场了。

官方文档里描述如下

1
git-blame - Show what revision and author last modified each line of a file

  • git blame foo 查看foo文件的修改记录
  • git blame -L 20, 30 foo 查看foo文件从20行到30行的修改记录
  • git blame -L 20, +30 foo 查看foo文件20行开始的30行修改记录

参考资料:

联系作者

在使用git的过程中经常遇到这个问题。明明使用git status看到Your branch is up-to-date with 'origin/dev'. , 但添加自己的修改,提交之后,发现远程分支已经有了修改。这是为何?现在终于明白这个原因。

这里设计到三个概念,本地的dev, 本地的origin/dev, 远程的dev。上面提示中的origin/dev指的是本地的origin/dev,而不是远程的dev. 虽然本地的dev is up-to-date with本地的origin/dev但,origin/dev并没有与远程的dev同步。所以当我们向远程dev push时,才会提示有冲突。

要想让本地的origin/dev与远程的dev同步,可以执行 git fetch origin dev, 发现有了更新

1
2
* branch            dev        -> FETCH_HEAD
078c7d1..d71d504 dev -> origin/dev

此时再次执行git status, 就会提示已经落后了, Your branch is behind 'origin/dev' by 8 commits, and can be fast-forwarded.

之后使用merge命令将本地的origin/dev合并到本地的dev中git merge --no-ff origin/dev

参考资料:

联系作者

当你在一个分支中进行修改时,想切换到另外一个分支,但你目前的修改还不能commit, 因为是不完整的,此时stash命令就可以派上用场。

使用git stash操作将目前的操作保持起来,然后切换到另外一个分支,干活完成后再切回来。此时使用git stash apply将之前的操作恢复。

此外还有一些stash操作如

  • git stash list 列出所有储藏
  • git stash drop 丢弃储藏
  • git stash pop 应用并丢弃储藏

有一个需要注意的是,在一个分支中stash起来的修改,也可以应用于其它分支。所以git stash apply时一定要注意分支是否匹配。

其实这也隐藏了stash的一个功能。当你在一个分支上进行修改时,发现你想修改的是另外一个分支,此时你不想reset掉修改。stash派上用场了,先git stash将修改保存起来,然后切换到另外一个分支,之后git stash apply, 这样修改就应用与另外一个分支了。

参考资料:

联系作者