(先生の生放送の内容によると)
1.準備
D:\pythonprogram\django_project\lgshop\apps> python ..\manage.py startapp addresses
- アプリを登録する
2.3レベルのリンケージデータベース設計に対応
- 州、市、郡のレベルで住所を保存するには、次の2つの方法があります。
- 方法1:州、市、郡は3つのテーブルに格納され、外部キーに従って関連付けられます
- 方法2:州、市、郡をテーブルに保存し、外部キーの関連付けを使用してそれらを独自に実装します
- 今回採用した2番目の方法:州、市、郡はテーブルに保存して達成します
from django.db import models
class Area(models.Model):
name=models.CharField(max_length=20,verbose_name="名称")
parent=models.ForeignKey("self",on_delete=models.SET_NULL,null=True,blank=True,verbose_name="上级",related_name="subs")
class Meta:
db_table="tb_areas"
verbose_name="省市区"
verbose_name_plural=verbose_name
def __str__(self):
return self.name
- データ移行
python manage.py makemigrations
python manage.py migrate
三、実現方法
- ページが読み込まれると、バックエンドへの州情報のクエリが自動的に開始され、その結果が州のドロップダウンリストに挿入されます。
- 州情報が変更されると、州IDがバックエンドに送信され、ajaxを介して都市/州のクエリが開始され、結果が都市/州のドロップダウンリストに挿入されます。
- 市と州の情報が変更されると、市IDがバックエンドに送信され、ajaxを介して地区/郡のクエリが開始され、結果が地区/郡のドロップダウンリストに挿入されます。
- 州、市、郡の3レベルの連携を実現するために
第四に、州のリストを取得します
1.フロントエンドの実装
- ページが読み込まれると、バックエンドへの州のクエリが自動的に開始されます
2.インターフェースの設計と定義
2.1リクエスト方法:
オプション |
プログラム |
リクエスト方法 |
取得する |
リクエストアドレス |
/ areas / |
2.2リクエストパラメータ:
パラメータ名 |
の種類 |
合格する必要があります |
説明 |
area_id |
ストリング |
番号 |
空気 |
2.3応答結果:json
回答結果 |
回答内容 |
コード |
ステータスコード |
errmsg |
エラーメッセージ |
Province_list |
リスト、各要素は辞書です:{"id":province id、 "name":province name} |
{
"code":"0",
"errmsg":"OK",
"province_list":[
{
"id":110000,
"name":"北京市"
},
{
"id":120000,
"name":"天津市"
},
{
"id":130000,
"name":"河北省"
},
......
]
}
3.バックエンドビューの実装
- パラメータを取得する
- パラメータが空の場合は、州の情報を照会することを意味します
- Areasクラスを介して、親が空のデータセットを取得します
- データセットを周期的に読み取り、州情報のリストを生成します
- 州情報辞書:{"id":州ID、 "名前":州名}
- フロントエンドのjsonデータを返す
4.バックエンドルーティングの定義
4.1トータルルーティング
- lgshop / urls.py
4.2サブルート
第五に、都市リストを取得します
1.フロントエンドの実装
- 選択した都道府県情報が変更されたら、都道府県IDをバックエンドに送信して市区町村のクエリを開始します
2.インターフェースの設計と定義
2.1リクエスト方法:
オプション |
プログラム |
リクエスト方法 |
取得する |
リクエストアドレス |
/ areas / |
2.2リクエストパラメータ:
パラメータ名 |
の種類 |
合格する必要があります |
説明 |
area_id |
ストリング |
番号 |
省id |
2.3応答結果:json
回答結果 |
回答内容 |
コード |
ステータスコード |
errmsg |
エラーメッセージ |
sub_data |
辞書 |
{
"code":"0",
"errmsg":"OK",
"sub_data":{
"id":130000,
"name":"河北省",
"subs":[
{
"id":130100,
"name":"石家庄市"
},
......
]
}
}
3.バックエンドビューの実装
- パラメータを取得する
- パラメータが空でない場合は、市または郡の情報を照会することを意味します
- Areasクラスを介してid = Provinceidで州情報を取得します
- Areasクラスを介してparent__id = Provinceidで都市データセットを取得します
- データセットを周期的に読み取り、州情報のリストを生成します
- 都市情報辞書:{"id":city id、 "name":city name}
- subs_dataデータを生成する
- フロントエンドのjsonデータを返す
6.郡のリストを取得します
1.フロントエンドの実装
- 選択した都市情報が変更されたら、都市IDをバックエンドに送信して、郡のクエリを開始します
2.インターフェースの設計と定義
2.1リクエスト方法:
オプション |
プログラム |
リクエスト方法 |
取得する |
リクエストアドレス |
/ areas / |
2.2リクエストパラメータ:
パラメータ名 |
の種類 |
合格する必要があります |
説明 |
area_id |
ストリング |
番号 |
都市ID |
2.3応答結果:json
回答結果 |
回答内容 |
コード |
ステータスコード |
errmsg |
エラーメッセージ |
sub_data |
辞書 |
{
"code": "0",
"errmsg": "OK",
"sub_data": {
"id": 130100,
"name": "石家庄市",
"subs": [
{
"id": 130102,
"name": "长安区"},
},
......
]
}
}
3.バックエンドビューの実装
- パラメータを取得する
- パラメータが空でない場合は、市または郡の情報を照会することを意味します
- Areasクラスを介してid = cityidで都市情報を取得します
- Areasクラスを介してparent__id = cityidの郡データセットを取得します
- データセットを周期的に読み取り、郡情報のリストを生成します
- 郡情報辞書:{"id":郡ID、 "名前":郡名}
- subs_dataデータを生成する
- フロントエンドのjsonデータを返す
- 都市コードによるコードの再利用
7、コードの最適化
- 州、市、郡のデータは基本的に変更されず、キャッシュに保存してmysqlデータの読み取り回数を増やし、応答速度を向上させることができます。
- 今回はCACHESのデフォルト領域に保存されました
- 例外のキャプチャと処理
- 州、市、郡のデータの有効期限をパラメータ化します
1.説明
- パラメータを取得する
- パラメータが空かどうかを確認します
- パラメータが空の場合は、州の情報を取得します
- パラメータが空でない場合は、area_idに従って市と郡の情報を取得します
- 州の情報を取得する:
- CACHESからprovince_model_listを読み取ります
- Province_model_listが空の場合、テーブルリクエストに州情報がないか、州情報が無効であるため、mysqlデータベースから読み取る必要があります。
- データベースにアクセスする必要があるため、読み取りエラーまたは異常エラーが発生する可能性があり、例外キャプチャが必要です。
- Areasクラスを介して、親が空のデータセットを取得します
- データセットを周期的に読み取り、州情報のリストを生成します
- CACHESに州情報を保存する
- ここに戻る必要はありません。province_model_listが存在するため、これも返す必要があります。
- 例外が発生した場合は、ログを保存し、エラー情報を含むJSONを返します
- 州情報を含むJSONを返す
- 市と郡の情報を取得する
- CACHESからsub_data + area_id情報を読み取ります
- sub_data + area_id情報が空の場合、テーブルリクエストに市または郡の情報がないか、市および郡の情報が無効であるため、mysqlデータベースから読み取る必要があります。
- データベースにアクセスする必要があるため、読み取りエラーまたは異常エラーが発生する可能性があり、例外キャプチャが必要です。
- Areasクラスを介してid = Provinceidで州情報を取得します
- Areasクラスを介してparent__id = Provinceidで都市データセットを取得します
- データセットを周期的に読み取り、州情報のリストを生成します
- subs_dataデータを生成する
- 市と郡の情報をCACHESに保存します:sub_data + area_id
- 例外が発生した場合は、ログを保存し、エラー情報を含むJSONを返します
- 州情報を含むJSONを返す
2.最適化されたコード
logger = logging.getLogger('django')
class AreasView(View):
"""省市区三级联动"""
def get(self,request):
area_id=request.GET.get("area_id")
if not area_id:
province_list = cache.get('province_list')
if not province_list:
try:
province_model_list = Area.objects.filter(parent__isnull=True)
"""
# 返回省份json数据格式
{
"code":"0",
"errmsg":"OK",
"province_list":[
{
"id":110000,
"name":"北京市"
},
{
"id":120000,
"name":"天津市"
}
]
}
"""
province_list=[]
for province_model in province_model_list:
province_dict={
"id":province_model.id,
"name":province_model.name,
}
province_list.append(province_dict)
cache.set("province_list", province_list, AREA_REDIS_EXPIRES)
except Exception as e:
logger.error(e)
return http.JsonResponse({
"code": RETCODE.DBERR, "errmsg": "查询省份数据错误"})
return http.JsonResponse({
"code": RETCODE.OK, "errmsg": "OK", "province_list": province_list})
else:
sub_data = cache.get("sub_data_" + area_id)
if not sub_data:
"""
# 返回市、县json数据格式
{
"code":"0",
"errmsg":"OK",
"sub_data":{
"id":130000,
"name":"河北省",
"subs":[
{
"id":130100,
"name":"石家庄市"
},
......
]
}
}
或
{
"code": "0",
"errmsg": "OK",
"sub_data": {
"id": 130100,
"name": "石家庄市",
"subs": [
{
"id": 130102,
"name": "长安区"},
},
......
]
}
}
"""
try:
parent_model=Area.objects.get(id=area_id)
sub_model_list = Area.objects.filter(parent__id=area_id)
subs=[]
for sub_model in sub_model_list:
sub_dict={
"id":sub_model.id,
"name":sub_model.name,
}
subs.append(sub_dict)
sub_data={
"id":parent_model.id,
"name":parent_model.name,
"subs":subs,
}
cache.set("sub_data_" + area_id, sub_data, AREA_REDIS_EXPIRES)
except Exception as e:
logger.error(e)
return http.JsonResponse({
"code": RETCODE.DBERR, "errmsg": "查询城市或区县数据错误"})
return http.JsonResponse({
"code": RETCODE.OK, "errmsg": "OK", "sub_data": sub_data})