Python+Django+小程序API的编写

在学习这个之前,首先要求是你们会Django框架的基础之上,如果不会可以点击这里学习有关Django框架的一些使用方案,在下面我将会讲出有关api的简单编写和json数据处理过程。

api结构主要包括请求链接,入参,Django的业务逻辑处理,返回参数。一般情况下尽量使用POST请求,数据比较安全。

  1. Django的业务逻辑

    1. urls的编写

      两种方法的原因是1.7以前不支持path来编写

      Django2.0.4可以使用以下方法
      from django.urls import path
      urlpatterns = [
          path('depot/', get_depot),
          path('depot_list/', get_depot_list)
          ]
      
      Django1.7.0可以使用以下方法
      from django.conf.urls import url
      urlpatterns = [
          url(r'depot/$', get_depot),
          url(r'depot_list/$', get_depot_list)
          ]
      
    2. models创建

      就举个简单的栗子吧,这样更加明确直白,这三个表个栗子,可以解决以后的多表联合查询问题。

      # 停车场表
      class TB_DEPOT(models.Model):
          DE_ID = models.CharField(max_length=18, verbose_name="停车场编码", primary_key=True)
          NAME = models.CharField(max_length=11, verbose_name="停车场名称")
          ADDRESS = models.CharField(max_length=64, verbose_name="停车场地址")
          LATITUDE = models.CharField(max_length=18, verbose_name="坐标(纬度)")
          LONGITUDE = models.CharField(max_length=18, verbose_name="坐标(经度)")
          COST_1 = models.CharField(max_length=6, verbose_name="停车费用_1")
          COST_2 = models.CharField(max_length=6, verbose_name="停车费用_2",null=True)
          MAN_COST = models.CharField(max_length=6, verbose_name="日最高消费",null=True)
          FREE_TIME = models.CharField(max_length=6, verbose_name="免费时长",null=True)
          MODE_PAY = models.CharField(max_length=11, verbose_name="支付方式")
          START_DATE = models.TimeField(verbose_name="营业开始时间")
          END_DATE = models.TimeField(verbose_name="营业结束时间")
          STATE = models.IntegerField(verbose_name="停车场状态")
          IMAGE_1 = models.ImageField(verbose_name="图片一", upload_to=image_upload_to)
          IMAGE_2 = models.ImageField(verbose_name="图片二", null=True, upload_to=image_upload_to)
          IMAGE_3 = models.ImageField(verbose_name="图片三", null=True, upload_to=image_upload_to)
          IMAGE_4 = models.ImageField(verbose_name="图片四", null=True, upload_to=image_upload_to)
          BUSI_ID = models.ForeignKey(TB_BUSINESSMAN, verbose_name="商户编码", on_delete=models.CASCADE)
          def __str__(self):
              return self.DE_ID
      
          class Meta:
              db_table = "TB_DEPOT"
              verbose_name = '停车场'
              verbose_name_plural = verbose_name
      
      #   预约表(TB_APPOINTMENT)
      class TB_APPOINTMENT(models.Model):
          APPO_ID = models.CharField(max_length=18, verbose_name="预约编码", primary_key=True)
          USER_ID = models.CharField(max_length=18, verbose_name="预约人编码")
          DATE = models.DateField(verbose_name='预约时间')
          PL_NUM = models.CharField(max_length=10, verbose_name='预约车牌', default='')
          APPO_TIME = models.CharField(max_length=4, verbose_name="预约时长")
          COST = models.CharField(max_length=4, verbose_name="预约费用")
          STATE = models.IntegerField(verbose_name="预约付款状态")
          APPO_STATE = models.IntegerField(verbose_name='预约过期状态', default='1')
          OUTPUT = models.IntegerField(verbose_name='是否入场', default='0')
          DEPOT = models.ForeignKey(TB_DEPOT, verbose_name="停车场编码", on_delete=models.CASCADE)
          def __str__(self):
              return self.APPO_ID
          class Meta:
              db_table = "TB_APPOINTMENT"
              verbose_name = '预约'
              verbose_name_plural = verbose_name
      
      # 用户表(TB_USER)
      class TB_USER(models.Model):
          OPEN_ID = models.CharField(max_length=64, verbose_name='微信唯一标识')
          USER_ID = models.CharField(max_length=32, verbose_name='用户编码')
          PHONE = models.CharField(max_length=11, verbose_name='用户手机号', null=True, default='')
          USER_NAME = models.CharField(max_length=32, verbose_name='用户微信名称')
          USER_STATE = models.IntegerField(verbose_name='用户状态')
          def __str__(self):
              return self.OPEN_ID
          class Meta:
              db_table = "TB_USER"
              verbose_name = '用户'
              verbose_name_plural = verbose_name
      
    3. api方法的编写

      先看一个简单的查询业务案例,停车场表信息查询

      from django.http import JsonResponse
      from django.views.decorators.csrf import csrf_exempt
      
      #请求参数设置
      #http://localhost:8000/Api/depot/
      # 入参 无
      # 返回json数据
      
      def get_depot(request):
          if request.method == 'GET':
              try:
                  data = {}
                  depot = TB_DEPOT.objects.values()
                  data['depot'] = list(depot)
                  print(data['depot'])
                  return JsonResponse({'success': True, 'data': data['depot']})
              except Exception as e:
                  return JsonResponse({'success': False, 'data': str(e)})
      

      主要问题就是如何把把QuerySet,数据转化成json数据,也就是Python中的字典,根据depot = TB_DEPOT.objects.values()获取到数据对象,然后使用下面这种简单的方法来把数据转化成json数据,data['depot'] = list(depot),这种方法给大家解释一下他就是把获取到的数据对象转化成list对象,然后反身存储到data['depot']中,完成一个简单的转化。

      下面这个栗子稍微有点复杂通过请求链接传参,进行获取数据,进行数据查询,拼接,返回json对象。

      # 用户预约信息查询 根据用户唯一标识openid进行查询
      # 请求示例
      # 请求示例:http://localhost:8000/Api/get_appo_over/?openId=******
      # 入参设置,需要进行openid标识传入
      # 可选参数:STATE、PPO_STATE、OUTPUT
      # 返回用户预约的记录
      def get_appo_over(request):
          data = {}
          if request.method == 'GET':
              openid = request.GET.get('openId')
              state = request.GET.get('state')
              output = request.GET.get('output')
              appo_state = request.GET.get('appo_state')
              try:
                  userid = TB_USER.objects.get(OPEN_ID=openid).USER_ID
                  print(userid)
                  appo = {}
                  if state:
                      appo = TB_APPOINTMENT.objects.filter(Q(USER_ID=userid) & Q(STATE=state))
                  elif appo_state:
                      appo = TB_APPOINTMENT.objects.filter(Q(USER_ID=userid) & Q(APPO_STATE=appo_state))
                  elif output:
                      appo = TB_APPOINTMENT.objects.filter(Q(USER_ID=userid) & Q(OUTPUT=output))
                  else:
                      appo = TB_APPOINTMENT.objects.filter(Q(USER_ID=userid))
                  data['appo'] = list(appo.values())
                  i = 0
                  for a in appo:
                      print(a.DEPOT.DE_ID)
                      depot = TB_DEPOT.objects.filter(DE_ID=a.DEPOT.DE_ID).values()
                      data['depot'] = list(depot)
                      print(data['depot'])
                      data['appo'][i].update(data['depot'][0])
                      i = i + 1
                  return  JsonResponse({'success': True, 'data': data['appo']})
              except Exception as e:
                  return JsonResponse({'success': False, 'data': 0})
      

      这个接口,主要是进行预约和相对应的停车场进行查询简单解释一下一些语句的用途

      openid = request.GET.get('openId')

      使用该代码来获取请求链接中的参数;

         i = 0
          for a in appo:
              print(a.DEPOT.DE_ID)
              depot = TB_DEPOT.objects.filter(DE_ID=a.DEPOT.DE_ID).values()
              data['depot'] = list(depot)
              print(data['depot'])
              data['appo'][i].update(data['depot'][0])
              i = i + 1
      

      这块代码主要是对预约记录进行解析出来,根据对应的a.DEPOT.DE_ID标识去进行停车场查询,将得到的数据转化,然后拼接到appo数据中,因为data['depot']和data['appo']都属于是dict类型的对象,可以使用update直接把数据更新到另一个里面注意的是如果直接更新,相同索引的值都会被替换掉,所以使用之前先对数据进行处理。

    4. 小程序端的请求方法

      var that = this
          wx.request({
            url: 'http://127.0.0.1:8000/Api/get_appo_over/?openId=' + app.gloabData.openid + '&state=0', method: 'GET',
            // url: 'https://api.songshao.site/Api/get_appo_over/?openId=' + app.gloabData.openid + '&state=0', method: 'GET',
            header: { 'content-type': 'application/json,charset=utf-8' },
            success: function (res) {
              console.log(res.data.data)
              if (res.data.data.length == 0) {
                that.setData({
                  num: 0
                })
              } else {
                that.setData({
                  num: 1,
                  appo: res.data.data,
                })
              }
      
            }, fail: function (res) {
              wx.showToast({
                title: '服务器开了小差,下拉刷新一下',
                icon: 'waring',
                duration: 3000
              })
            }
          })
      

       

      小程序使用wx.request来请求api,在url中编写链接地址和对应的参数,请求method一般尽量使用post,请求头设置 header: { 'content-type': 'application/json,charset=utf-8' },成功之后返回数据处理请求成功数据如下:

      {"success": true, "data": [{"APPO_ID": "684407", "USER_ID": "8208225", "DATE": "2018-12-25", "PL_NUM": "\u9655A88888", "APPO_TIME": "10", "COST": "0.5", "STATE": 1, "APPO_STATE": 1, "OUTPUT": 0, "DEPOT_id": "20181215002", "DE_ID": "20181215002", "NAME": "\u5c1a\u54c1\u7f8e\u5730\u57ce\u4e8c\u671f", "ADDRESS": "\u9655\u897f\u7701\u897f\u5b89\u5e02\u96c1\u5854\u533a\u9526\u4e1a\u8def92\u53f7", "LATITUDE": "34.34627", "LONGITUDE": "108.93984", "COST_1": "5", "COST_2": "6", "MAN_COST": "50", "FREE_TIME": "0.5", "MODE_PAY": "\u7535\u5b50\u652f\u4ed8", "START_DATE": "00:00:00", "END_DATE": "23:59:00", "IMAGE_1": "index/static/upload_image/47735b874b494483b1ab1149b1b6d84d/\u5c1a\u54c1.jpg", "IMAGE_2": "index/static/upload_image/d03235beb44548de9cab02041ba2d511/\u5c1a\u54c1.jpg", "IMAGE_3": "index/static/upload_image/14545c2c9f4a4e2ebf392a3fe04bc1af/\u5c1a\u54c1.jpg", "IMAGE_4": "index/static/upload_image/4bb82db280584fa6a6e4f91fde65f7e5/\u5c1a\u54c1.jpg", "BUSI_ID_id": "20181215001"}, {"APPO_ID": "9276129", "USER_ID": "8208225", "DATE": "2018-12-25", "PL_NUM": "\u9655E88888", "APPO_TIME": "10", "COST": "0.5", "STATE": 1, "APPO_STATE": 0, "OUTPUT": 0, "DEPOT_id": "20181215002", "DE_ID": "20181215002", "NAME": "\u5c1a\u54c1\u7f8e\u5730\u57ce\u4e8c\u671f", "ADDRESS": "\u9655\u897f\u7701\u897f\u5b89\u5e02\u96c1\u5854\u533a\u9526\u4e1a\u8def92\u53f7", "LATITUDE": "34.34627", "LONGITUDE": "108.93984", "COST_1": "5", "COST_2": "6", "MAN_COST": "50", "FREE_TIME": "0.5", "MODE_PAY": "\u7535\u5b50\u652f\u4ed8", "START_DATE": "00:00:00", "END_DATE": "23:59:00", "IMAGE_1": "index/static/upload_image/47735b874b494483b1ab1149b1b6d84d/\u5c1a\u54c1.jpg", "IMAGE_2": "index/static/upload_image/d03235beb44548de9cab02041ba2d511/\u5c1a\u54c1.jpg", "IMAGE_3": "index/static/upload_image/14545c2c9f4a4e2ebf392a3fe04bc1af/\u5c1a\u54c1.jpg", "IMAGE_4": "index/static/upload_image/4bb82db280584fa6a6e4f91fde65f7e5/\u5c1a\u54c1.jpg", "BUSI_ID_id": "20181215001"}]}
      

      首先需要说明小程序请求之后会把json数据默认存放方到data里面,这块本省还有一个data,所以定位时就需要用res.data.data定位数据,像这个json数据有两条,在页面显示时可以用for循环输出数据

      <view class='content_view' wx:for='{{appo}}' wx:key>
            <view class='header'>
              <text class='l_text'>{{item.DATE}}</text>
              <text class='r_text'>未进场</text>
            </view>
            <view class='header_content'>
              <view  class='header_text'>
                <text>{{item.NAME}}停车场</text>
              </view>
              <view class='text_view'>
                <image class='image_style' src='../../resource/image/ding_wei_1.png'/>
              <text class='text_view_text'>{{item.ADDRESS}}</text>
                </view>
              <view class='text_view'>
                <image class='image_style' src='../../resource/image/car.png'/>
                <text class='text_view_text'>预约车牌为:{{item.PL_NUM}}</text>
              </view>
              <view class='text_view'>
                <image class='image_style' src='../../resource/image/time.png'/>
                <text class='text_view_text'>剩余时长:{{item.APPO_TIME}}</text>
              </view>
              <button class='btn'>续费</button>
            </view>
      
          </view>
      

      在循环中可以通过定义的数据对象appo,去循环,因为循环使用的是它的array(),因为json对象有两条所以循环两次,输出,每次遍历数组对象是可以使用item.属性名,来获取相应的数据,显示结果如下图所示

      xiaochengx_list1

      如果出现这种结果就说明你的小程序成功了!