Django project practice (mall): 11. Supplement: Three-level linkage of addresses

Insert picture description here

(According to the content of teacher's live broadcast)

1. Preparation

  • Create an app: addresses
D:\pythonprogram\django_project\lgshop\apps> python ..\manage.py startapp addresses
  • Register the app
    Insert picture description here

2. Address three-level linkage database design

  • There are two ways to save addresses at the provincial, city, and county levels:
    • Method 1: The provinces, cities, and counties are stored in three tables, and are associated according to foreign keys
      Insert picture description here
    • Method 2: Store the provinces, cities, and counties in a table, and use foreign key associations to implement them
      Insert picture description here
  • The second method adopted this time: the provinces, cities and counties store in a table to achieve
# /apps/addresses/models.py
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
  • data migration
    Insert picture description here
python manage.py makemigrations
python manage.py migrate

Three, realization method

Insert picture description here

  • When the page is loaded, it will automatically initiate a query for province information to the backend and insert the result into the province drop-down list
  • When the province information is changed, the province id is sent to the backend to initiate a city/state query through ajax, and the result is inserted into the city/state drop-down list
  • When the city and state information is changed, the city id will be sent to the backend to initiate a district/county query through ajax, and the result will be inserted into the district/county drop-down list
  • So as to realize the three-level linkage of provinces, cities and counties

Fourth, get the list of provinces

1. Front-end implementation

  • When the page is loaded, automatically initiate a province query to the backend
    Insert picture description here
    Insert picture description here

2. Interface design and definition

2.1 Request method:

Options Program
Request method get
Request address /areas/

2.2 Request parameters:

parameter name Types of Must pass Description
area_id string no air

2.3 Response result: json

Response result Response content
code status code
errmsg Error message
province_list List, each element is a dictionary: {"id":province id, "name":province name}
  • Province data JSON
{
    
    
  "code":"0",
  "errmsg":"OK",
  "province_list":[
      {
    
    
          "id":110000,
          "name":"北京市"
      },
      {
    
    
          "id":120000,
          "name":"天津市"
      },
      {
    
    
          "id":130000,
          "name":"河北省"
      },
      ......
  ]
}

3. Back-end view implementation

  • Get parameters
  • If the parameter is empty, it means to query the province information
    • Through the Areas class, get the data set whose parent is empty
    • Read the data set cyclically to generate a list of province information
      • Province information dictionary: {"id":province id,"name":province name}
    • Return front-end json data
      Insert picture description here

4. Back-end routing definition

4.1 Total routing

  • lgshop/urls.py
    Insert picture description here

4.2 Sub-route

Insert picture description here

Fifth, get the city list

1. Front-end implementation

  • After the selected province information changes, send the province id to the backend to initiate a city query
    Insert picture description here

2. Interface design and definition

2.1 Request method:

Options Program
Request method get
Request address /areas/

2.2 Request parameters:

parameter name Types of Must pass Description
area_id string no Ministry id

2.3 Response result: json

Response result Response content
code status code
errmsg Error message
sub_data dictionary
  • City data JSON
{
    
    
	"code":"0",
	"errmsg":"OK",
	"sub_data":{
    
    
	  "id":130000,
	  "name":"河北省",
	  "subs":[
	      {
    
    
	          "id":130100,
	          "name":"石家庄市"
	      },
	      ......
	  ]
	}
}

3. Back-end view implementation

  • Get parameters
  • If the parameter is not empty, it means to query city or county information
    • Get the province information with id=province id through the Areas class
    • Get the city data set with parent__id=province id through the Areas class
    • Read the data set cyclically to generate a list of province information
      • City information dictionary: {"id":city id,"name":city name}
    • Generate subs_data data
    • Return front-end json data
      Insert picture description here

6. Get the list of counties

1. Front-end implementation

  • After the selected city information changes, send the city id to the backend to initiate county query
    Insert picture description here

2. Interface design and definition

2.1 Request method:

Options Program
Request method get
Request address /areas/

2.2 Request parameters:

parameter name Types of Must pass Description
area_id string no City id

2.3 Response result: json

Response result Response content
code status code
errmsg Error message
sub_data dictionary
  • County data JSON
{
    
    
	"code": "0", 
	"errmsg": "OK", 
	"sub_data": {
    
    
		"id": 130100, 
		"name": "石家庄市", 
		"subs": [
			{
    
    
				"id": 130102, 
				"name": "长安区"}, 
			},
			......
		]
	}
}

3. Back-end view implementation

  • Get parameters
  • If the parameter is not empty, it means to query city or county information
    • Get the city information with id=city id through the Areas class
    • Obtain the county data set with parent__id=city id through the Areas class
    • Read the data set cyclically to generate a list of county information
      • County information dictionary: {"id":county id,"name":county name}
    • Generate subs_data data
    • Return front-end json data
  • Code and city code reuse

Seven, code optimization

  • The data of provinces, cities and counties will basically not change, and can be stored in the cache to increase the number of mysql data reads and improve the response speed
    • This time saved in the default area of ​​CACHES
  • Exception capture and handling
  • Parameterize the expiration time of province, city and county data

1. Description

  • Get parameters
  • Determine whether the parameter is empty
    • If the parameter is empty, get the province information
    • If the parameter is not empty, get the city and county information according to area_id
  • Get province information:
  • Read province_model_list from CACHES
  • If the province_model_list is empty, the table request has no province information or the province information is invalid, and it needs to be read from the mysql database
  • Due to the need to access the database, there may be read failures or abnormal errors, and exception capture is required.
    • Through the Areas class, get the data set whose parent is empty
    • Read the data set cyclically to generate a list of province information
    • Save province information in CACHES
    • No need to return here, because province_model_list exists, it also needs to be returned
  • If an exception occurs, save the log and return JSON with error information
  • Return JSON containing province information
  • Get city and county information
    • Read sub_data+area_id information from CACHES
    • If the sub_data+area_id information is empty, the table request has no city or county information or the city and county information is invalid, and it needs to be read from the mysql database
    • Due to the need to access the database, there may be read failures or abnormal errors, and exception capture is required.
      • Get the province information with id=province id through the Areas class
      • Get the city data set with parent__id=province id through the Areas class
      • Read the data set cyclically to generate a list of province information
      • Generate subs_data data
      • Save the city and county information in CACHES: sub_data+area_id
    • If an exception occurs, save the log and return JSON with error information
    • Return JSON containing province information

2. Optimized code

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)  # parent 是外键  parent__null 判断此字段是否为空
                   # print(type(province_model_list),province_model_list)
                   """
                   # 返回省份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)

                   # 将数据保存到Redis中 默认的
                   # cache.set("province_list", province_list, 3600)
                   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:
           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)  # parent是Area的外键

                   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, 3600)
                   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})


Guess you like

Origin blog.csdn.net/laoluobo76/article/details/114274170