编写一个弹出式菜单的shell程序并实现_如何在Django里面建立级联菜单呢? [1]

fc3294b663378e19b6adeba77b04e9da.png

这是上篇,下面在这里

所谓级联菜单, 最常见的应该就是省, 市这种地理位置选择的菜单了. 其实在我上网填表格的时候, 从来没有想过这后面能有什么复杂的东西. 但是真到自己上手做了以后, 发现并不是两三下能做的好的.

model定义与数据准备

现在让我们将问题简化一下, 整个project就只有一个app: locations. locations app中, model.py如下所示:

from django.db import models

class Province(models.Model):
    title = models.CharField(max_length=100)

    def __str__(self):
        return self.title


class City(models.Model):
    title = models.CharField(max_length=100)
    province = models.ForeignKey(
        Province,
        on_delete=models.CASCADE,
    )

    def __str__(self):
        return self.title

总共两个model, 分别是省和市的信息. 两个model都有title这个field, 用于记录名称, 而city这个model又额外有一个指向省(province)的外键.

假如说, 现在我有两个csv文件, 分别记录了市和省的信息, 使用pandas读取以后head输出如下所示:

| | code | name | provinceCode |

|---:|-------:|:---------|---------------:|

| 0 | 1101 | 市辖区 | 11 |

| 1 | 1201 | 市辖区 | 12 |

| 2 | 1301 | 石家庄市 | 13 |

| 3 | 1302 | 唐山市 | 13 |

| 4 | 1303 | 秦皇岛市 | 13 |

顺带一提, pandas 1.0 版本新增的这个 .to_markdown()真的是太好用了, 破乎的编辑器太难用了

而省的csv信息则如下表所示

| | code | name |

|---:|-------:|:-------------|

| 0 | 11 | 北京市 |

| 1 | 12 | 天津市 |

| 2 | 13 | 河北省 |

| 3 | 14 | 山西省 |

| 4 | 15 | 内蒙古自治区 |

可以看到两个表之间是依靠cities.provinceCode <--> provinces.code 相联系的. 当然了, 在我们Django的model定义里面没有用上这个关联, 毕竟添加记录的时候id都是自动计数的, csv表之间的关联有用, 但是也没必要照搬.

在写完model, 做完makemigrations以及migrate以后, 接下来就可以在shell里面往两个model添加记录了.

当然也可以用比如 django-import-export这样的包来帮忙实现导入导出, 但是对于当前这种超级简单的应用, shell就足够了
  1. 进入shell. 在terminal中输入下面的命令
python manage.py shell

然后就会进入类似ipython的环境, 不过这个时候django会替你完成诸多环境配置. 这个动作可以省去很多麻烦, 是非常有用的一个操作. 而且就算是在shell环境下, 仍旧还是能够通过exec(open('name_of_the_sript.py').read())这样的命令去打开外部python脚本的. 所以虽然shell没有pycharm的python console好用, 但是已经足够了. 另外如果想玩弄Django的各个组件, shell就是最好的环境.

在进入shell环境以后, 做好准备工作

from locations.models import City, Province
import pandas as pd
import os

比如说前面提到的cities.csv和province.csv都是保存在工作目录下的ref文件夹中的, 那接下来将两个表载入形成dataframe:

os.chdir('ref')
df_city = pd.read_csv('cities.csv')
df_prov = pd.read_csv('province.csv')

先自动录入province信息, 借用series的apply:

def prov_create(e):
    Province.objects.create(title=e)

df_prov['name'].apply(prov_create)

好, 上面的代码里,第二行create的kwargs要用title, 是因为Province这个model, 我们定义的时候省的名称用的就是title这个属性. 而第4行, df_prov['name'] 要用name, 是因为在provinces.csv中, 记录省的名称这一列, 表头就是name.

注: provinces.csv以及cities.csv均 来源于网络, 数据内容只包含 中国大陆省市信息, 尚未包含台湾省, 香港特别行政区以及澳门特别行政区的信息. 考虑到系统的实际需求, 这些数据也可以满足需要, 故暂未做进一步补充

可以通过df_prov.shapeProvince.objects.count()比对一下是否数量一致.

接下来就是给City这个model添加记录了:

def city_create(row):
    city_name = row['name']
    prov_code = row['provinceCode']
    prov_name = df_prov.loc[prov_code,'name']
    prov = Province.objects.get(title=prov_name)
    City.objects.create(title=city_name, province=prov)

df_city.apply(city_create, axis=1)

注意:

  1. 考虑到现在需要cities.csv的name列和provinceCode列, 所以直接遍历整个dataframe. 遍历dataframe的时候将axis定义为1才能逐行遍历.
  2. function里面从provinceCode到真正的省的记录包含以下几步:
    1. 利用改行的provinceCode从df_prov中查询省的名称(name): prov_name = df_prov.loc[prov_code,'name']
    2. 利用这个名称, 使用Province.objects.get(title=...), 利用queryset找到真正的Province记录
  1. 在City中建立记录, 给予title和province两个属性.

今天就暂时先到这里. 后面再说如何编写form, 以及url-view-template. 前后端通讯会用到一点ajax.

原文链接

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值