zoukankan      html  css  js  c++  java
  • Flask-爱家租房项目ihome-05-发布房源

    获取地区接口

    在发布房源页面/主页/搜索页都需要获取城市的地区信息, 而主页和搜索页都是访问频率比较高的, 所以这里需要将获取到的信息保存至redis缓存中

    后端逻辑

    ihome/api_1_0下添加房屋模块的视图文件houses.py

    # ihome/api_1_0/houses.py
    import json
    from flask import jsonify, current_app
    from . import api
    from ihome import redis_connect
    from ihome.models import Areas
    from ihome.utils.response_codes import RET
    from ihome.utils import constants
    
    @api.route('/areas')
    def get_areas():
        # 从缓存中获取城区信息
        try:
            areas = redis_connect.get('areas').decode()
        except Exception as e:
            current_app.logger.error(e)
            areas = None
    
        # 缓存中不存在则查询数据库
        if not areas:
            try:
                areas_obj_list = Areas.query.all()
            except Exception as e:
                current_app.logger.error(e)
                return jsonify(errno=RET.DBERR, errmsg='获取城区信息失败')
            # 将城区对象列表转换为字典
            areas_dict = {area.id: area.name for area in areas_obj_list}
            # 将字典转换为json字符串
            areas = json.dumps(areas_dict)
            # 将数据存入缓存
            try:
                redis_connect.setex('areas', constants.AREA_REDIS_EXPIRES, areas)
                print('设置areas缓存')
            except Exception as e:
                current_app.logger.error(e)
    
        return f'{{"errno": "0", "data": {areas}}}', 200, {'content-Type': 'application/json'}
    

    注:

    1. 由于城区接口访问频率是很高的, 所以将其json结果存入redis缓存中, 其中redis默认保存的是编码后的结果, 所以获取redis的数据后需要手动解码

    2. Areas.query.all()返回的是模型对象列表, 最终我们要提取到城区的id和名字

    3. 因为最终返回的是json, 因此直接将城区信息的json数据存入redis缓存中, 方便发送给前端, 且一定要设置缓存到期时间

    4. 列表通过字典生成式转换为字典, 再通过json.dumps转化为json字符串

    5. 返回时由于已经获取到了城区的json信息, 因此使用返回元组 (json内容, http状态码, response头信息) 的方式返回

      • 其中由于需要在城区json数据areas基础上添加errnodata键值对, 所以需要使用字符串格式化拼接的方式得到最后的json字符串, f-string的格式化字符串中, 一对大括号表示引用变量, 两对大括号表示显示一对大括号
      • response的返回值类型需要指明为application/json

    发布房源-选择城区的前台逻辑

    后端返回的是一个js对象, 类似于:

    {1: "东城区", 2: "西城区", 3: "朝阳区", 4: "海淀区", 5: "昌平区", 6: "丰台区", 7: "房山区", 8: "通州区", 9: "顺义区", 10: "大兴区", 11: "怀柔区", 12: "平谷区", 13: "密云区", 14: "延庆区", 15: "石景山区", 16: "门头沟区"}
    

    因此前端需要通过select+option动态获取数据并展示成列表选择, 有两种方式可以动态设置html

    使用jQuery设置html标签

    这一种方式也是之前代码常用的, 即获取到后端的json数据后, 通过jQuery设置标签的属性, 编辑前端发布房源页面对应的js文件newhouse.js, 页面一加载就发送ajax请求获取数据

    // newhouse.js
    $(document).ready(function(){
        // $('.popup_con').fadeIn('fast');
        // $('.popup_con').fadeOut('fast');
        //获取房屋信息
        $.get("api/v1.0/areas", function (resp) {
            if (resp.errno == '0'){
                //获取到城区数据
                var areas = resp.data;
                // 方法一:普通循环, 在select下面添加option标签
                for (var key in areas){
                    //<option value="1">东区</option>
                    $("#area-id").append('<option value="'+key+'">' + areas[key] + '</option>');
                }
            }else {
                //存在错误
                alert(resp.errmsg);
            }
        }, 'json')
    })
    

    注:

    1. 正常返回时resp就是城区的json数据, 当后台返回报错时resp.errno才有值
    2. js中可以使用for循环遍历js对象, key为索引, areas[key] 为值
    3. 使用.append()select标签添加option标签, 传入的值为需要option标签的html文本字符串

    使用前段模板: art-template

    前端中也有像django或者flask模板那样模板插件, art-template就是一种模板插件, 它需要基于jQuery.

    导入template.js源码

    先在官网下载js文件, 再在static/js下导入刚下载的js模板文件template.js

    在html文件中使用模板

    编辑房屋发布页面的html文件newhouse.html

    <div class="form-group">
        <label for="area-id">所在城区</label>
        <select class="form-control" id="area-id" name="area_id">
            <script type="text/html" id="area-option">
             {{ each areas }}
                 <option value = "{{ $index }}">{{ $value }}</option>
             {{ /each }}
            </script>
        </select>
    </div>
    ....
    <script src="/static/js/jquery.min.js"></script>
    <script src="/static/js/jquery.form.min.js"></script>
    <script src="/static/js/template.js"></script>
    

    注:

    1. 先在html文件中导入template.js的路径
    2. 把需要生成动态html文本的模板代码放在<script type="text/html" id="area-option"></script>标签中(id可以自定义), 并且这个script标签可以放在该html文件的任意位置, 不一定就要放在select标签中
    3. 这点和django或flask的模板语言不一样, django或flask模板语言需要放在具体需要替换的地方, 说明art-template这个插件只是用来生成html文本字符串的, 具体生成的html文本到底放在哪里, 还需要自己再指定
    4. 后面的js代码给html模板传入的变量参数名为areas, 这是地区的js对象, 我们需要遍历这个js对象获取其中的key和value, 并生成option文本.
    5. art-template中可以使用each遍历对象, 使用{{$index}}获取key值, {{$value}}获取value, {{$data}}获取对象本身

    在js中设置模板

    在对应的js文件newhouse.js

    $(document).ready(function(){
        // $('.popup_con').fadeIn('fast');
        // $('.popup_con').fadeOut('fast');
        //获取房屋信息
        $.get("api/v1.0/areas", function (resp) {
            if (resp.errno == '0'.data){
                //获取到城区数据
                var areas = resp;
                // 方法一:通过jQuery循环, 在select下面添加option标签
                // for (var key in areas){
                //     //<option value="1">东区</option>
                //     $("#area-id").append('<option value="'+key+'">' + areas[key] + '</option>');
                // }
                // 方法二:使用art-template前端模板
                // 给模板传值, 返回html文本
                html = template('area-option', {areas: areas});
                // 设置select中的文本对象
                $('#area-id').html(html);
            }else {
                //存在错误
                alert(resp.errmsg);
            }
        }, 'json')
    })
    

    注:

    1. 使用template()函数返回模板代码生成的html文本, 第一个参数为html模板中script标签的id属性值, 第二个参数为js对象格式, 表示传给模板的数据, key为参数名, val为传入的值
    2. 通过jQuery将得到的一连串option标签的html文件, 放到select的html文本中, 就指定了html的具体位置

    发布房源接口

    用户在我的房源页面点击发布新房源按钮, 可以进入发布新房源页面

    image-20200824232124136

    该页面有两个表单, 一个表单是用来发布房源的信息, 另一个是用来上传图片的, 这个表单是隐藏的, 需要成功发布房源之后才会显示出来.

    发布房源后端逻辑

    在房屋模块的视图文件houses.py中添加发布接口逻辑, url为/api/v1.0/houses

    @api.route('/houses', methods=['POST'])
    @login_required
    def create_house():
        # 接收数据
        data_dict = request.get_json()
        if not data_dict:
            return parameter_error()
        # 提取数据
        title = data_dict.get('title')
        price = data_dict.get('price')
        area_id = data_dict.get('area_id')
        address = data_dict.get('address')
        room_count = data_dict.get('room_count')
        acreage = data_dict.get('acreage')
        unit = data_dict.get('unit')
        capacity = data_dict.get('capacity')
        beds = data_dict.get('beds')
        deposit = data_dict.get('deposit')
        min_days = data_dict.get('min_days')
        max_days = data_dict.get('max_days')
        facility_ids = data_dict.get('facilities')
    
        # 校验数据
        if not all(
                [title, price, area_id, address, room_count, acreage, unit, capacity, beds, deposit, min_days, facility_ids]):
            return parameter_error()
    
        # 校验金额格式, 转化为两位小数
        try:
            price = round(float(price), 2)
            deposit = round(float(deposit), 2)
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.PARAMERR, errmsg='金额格式有误')
        
        # 校验数字类型
        try:
            room_count = int(room_count)
            acreage = int(acreage)
            capacity = int(capacity)
            min_days = int(min_days)
            max_days = int(max_days)
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.PARAMERR, errmsg='房屋面积/房屋数目/宜住人数/最少最多天数必须为数字')
        
        # area_id是否存在
        try:
            area = Areas.query.get(area_id)
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg='获取城区信息异常')
        if not area:
            return jsonify(errno=RET.PARAMERR, errmsg='城区ID不存在')
    
        # 最小最大入住日期
        if min_days > max_days | max_days >= 0:
            return jsonify(errno=RET.PARAMERR, errmsg='最小日期不能超过最大日期')
    
        # 创建房屋对象
        house = Houses(user_id=g.user.id, area_id=area_id, title=title, price=price, address=address,
                       room_count=room_count, acreage=acreage, unit=unit, capacity=capacity, beds=beds, deposit=deposit,
                       min_days=min_days, max_days=max_days)
    
        # 给房屋添加设施信息
    
        # 第一种: 循环校验每个设施, 然后通过append添加
        # for facility_id in facility_ids:
        #     # 循环校验设施ID
        #     try:
        #         facility = Facilities.query.get(facility_id)
        #     except Exception as e:
        #         current_app.logger.error(e)
        #         return jsonify(errno=RET.DBERR, errmsg='获取设施信息异常')
        #     if not facility:
        #         return jsonify(errno=RET.DBERR, errmsg=f'设施ID"{facility_id}"不存在')
        #     # 创建房屋设置数据
        #     house.facilities.append(facility)
    
        # 第二种: 不循环, 通过in_(list)查询设施, 但是这样不会处理错误的设施id
        try:
            facilities = Facilities.query.filter(Facilities.id.in_(facility_ids)).all()
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg='获取设施信息异常')
        if facilities:
            # 存在正确的设施ID, 则给房屋对象添加设施信息
            house.facilities = facilities
    	# 提交session
        try:
            db.session.add(house)
            db.session.commit()
        except IntegrityError as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.PARAMERR, errmsg='该房屋标题已存在')
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg='保存房屋信息异常')
    
        return jsonify(errno=RET.OK, data={'house_id': house.id})
    

    注:

    1. 提交的json数据格式为:

      {
      	"title": "test3",
      	"price": "110",
      	"area_id": "3",
      	"address": "上海小区",
      	"room_count": "3",
      	"acreage": "120",
      	"unit": "三室一厅",
      	"capacity": "4",
      	"beds": "2双人床",
      	"deposit": "100",
      	"min_days": "2",
      	"max_days": "-1",
      	"facilities": ["1","2","4"]
      }
      
    2. 房屋设施信息通过设施ID组成的列表facilities提交, 这里涉及到了房屋表和设施表的一对多关系, 在models文件中定义了多对多关系的中间表, 以及逻辑关系

    # 房屋和设置表属于多对多关系, 官方推荐db.table的方式建立多对多关系
    house_facilities = db.Table('ih_house_facilities',
                                db.Column('house_id', db.Integer, db.ForeignKey('ih_houses.id'), nullable=False),
                                db.Column('facility_id', db.Integer, db.ForeignKey('ih_facilities.id'), nullable=False))
    # 房屋模型类
    class Houses(BasicModel):
    	__tablename__ = 'ih_houses'
        .....
        # 在模型类中定义关系, 注意secondary参数传入中间表变量
        facilities = db.relationship('Facilities', secondary=house_facilities, backref='houses')
    
    1. 创建房屋数据时, 也要创建房屋设施中间表的数据, 不过不需要我们手动赋值, 只需要给house对象的facilities属性赋值就可以了, 类型为Facility对象组成的list, 有两种方法得到这个list
    • 第一种: 循环前端发送的设施ID列表facilities, 校验每个ID是否正确, 获取到ID对应的facility对象, 再把facility对象追加到house对象的facilities属性中:

      for facility_id in facility_ids:
          # 循环校验设施ID
          try:
              facility = Facilities.query.get(facility_id)
          except Exception as e:
              current_app.logger.error(e)
              return jsonify(errno=RET.DBERR, errmsg='获取设施信息异常')
          if not facility:
              return jsonify(errno=RET.DBERR, errmsg=f'设施ID"{facility_id}"不存在')
          # 创建房屋设置数据
          house.facilities.append(facility)
      
    • 第二种: 不循环ID列表, 直接使用in_方法查询ID列表中对应的facility, 获取到facility对象的列表, 再赋值给house对象的facilities属性

      try:
          facilities = Facilities.query.filter(Facilities.id.in_(facility_ids)).all()
      except Exception as e:
          current_app.logger.error(e)
          return jsonify(errno=RET.DBERR, errmsg='获取设施信息异常')
      if facilities:
          # 存在正确的设施ID, 则给房屋对象添加设施信息
          house.facilities = facilitie
      

    发布房源前段逻辑

    在房屋发布页面对应的js文件newhouse.js中添加以下逻辑

    //发布房源表单的提交
        $('#form-house-info').submit(function (e) {
            //阻止默认
            e.preventDefault();
            //自定义提交
            //获取数据
            var data = {};
            //获取form表单中的所有input提交项, 使用map循环每个input获取name和value
            $(this).serializeArray().map(function (item) {
                data[item.name] = item.value;
            })
            //获取复选框中勾选的设施项
            var facility_ids = [];
            $('input:checkbox:checked').each(function (index, item) {
                facility_ids[index] = $(item).val();
            })
            var data["facilities"] = facility_ids;
            //转为json
            var data = JSON.stringify(data);
    		//发送请求
            $.ajax({
                url: 'api/v1.0/houses',
                type: 'POST',
                contentType: 'application/json',
                data: data,
                headers: {'X-CSRFToken': getCookie('csrf_token')},
                dataType: 'json',
                success: function (resp) {
                    if (resp.errno == '0'){
                        //发布成功
                        //设置house_id
                        $('#house-id').val(resp.data.house_id);
                        //展示上传图片表单
                        $('#form-house-image').show();
                        alert('保存成功, 请上传房屋图片');
                    }else {
                        //发布失败
                        alert(resp.errmsg)
                    }
                }
            })
        })
    

    注:

    1. 该页面的表单中有很多input框需要提交, 显然不适合一个一个获取, 可以通过$('form选择器').serializeArray()获取form下所有的输入框, 返回的是所有输入框的name和value组成的对象列表, 如:

      > $('#form-house-info').serializeArray()
      < (16) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
      0: {name: "house_id", value: ""}
      1: {name: "title", value: "test"}
      2: {name: "price", value: "100"}
      3: {name: "area_id", value: "1"}
      4: {name: "address", value: "上海a小区"}
      5: {name: "room_count", value: "1"}
      6: {name: "acreage", value: "50"}
      7: {name: "unit", value: "一室一厅"}
      8: {name: "capacity", value: "2"}
      9: {name: "beds", value: "双人床:2x1.8x1张"}
      10: {name: "deposit", value: "100"}
      11: {name: "min_days", value: "1"}
      12: {name: "max_days", value: "2"}
      13: {name: "facility", value: "1"}
      14: {name: "facility", value: "2"}
      15: {name: "facility", value: "3"}
      length: 16
      __proto__: Array(0)
      

      我们最终需要的是列表中每个输入框的namevalue属性组成的键值对, 如:{title": "test", "price": "100"}

      因此先创建一个空js对象data, 然后使用map函数遍历列表, 取出每个item的name和value, 再添加到data对象中, map函数的参数item就是列表中的每个js对象

    2. 配套设施使用的是多个复选框的形式, 因此可以通过选择器$('input:checkbox:checked')获取到选中状态的checkbox, 其value值设计的就是对应数据库中设施表ih_facilities中的ID.

      同样获取到的是一个checkbox的列表, 但是列表中的元素是整个input框对象, 我们同样只需要每个input框的value属性值.

      因为最终想要的是每个checkboxvalue属性组成的数组, 如:["3", "4", "7"], 所以也预先定义一个空数组facility_ids.

      这里使用的是each遍历checkbox数组, each接收有两个参数: index是列表的索引, item是数组的元素值, 因此item代表的是整个checkbox元素对象, 所以想要使用jQuery的方式获取其value属性: $(item).val(), 然后将indexvalue追加到facility_ids中, 最后赋值给data的facilities属性

    3. 房源发布成功后, 展示上传房屋图片的表单, 同时接收新房源的ID并赋值给隐藏的输入框house-id中, 是为了在上传房屋图片接口判断上传的图片是属于哪一个房源.

    上传房屋图片接口

    房屋成功发布后, 就会展示上传图片的表单界面

    image-20200825162637011

    上传房屋图片后端逻辑

    在房屋模块的视图文件houses.py中添加上传房屋图片接口逻辑, url为/api/v1.0/house/images

    @api.route('house/images', methods=['POST'])
    @login_required
    def create_house_images():
        # 获取数据, 该图片数据由浏览器提交, 不是json格式的
        image_data = request.files.get('house_image')
        house_id = request.form.get('house_id')
    
        # 校验数据
        if not all([image_data, house_id]):
            return parameter_error()
        # 校验房屋Id
        try:
            house = Houses.query.get(house_id)
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg='获取房屋信息异常')
        if not house:
            return jsonify(errno=RET.PARAMERR, errmsg='房屋ID不存在')
    
        # 调用上传图片接口
        ret = storage(image_data)
        print(ret)
        if ret['status'] != 200:
            # 上传失败
            return jsonify(errno=RET.THIRDERR, errmsg=f'上传失败:{ret["errmsg"]}')
    
        # 上传成功, 创建图片数据
        house_image = HouseImages(house=house, image_url=ret['url'])
        db.session.add(house_image)
        # 保存房屋的默认图片
        if not house.default_image_url:
            house.default_image_url = ret['url']
            db.session.add(house)
        # 提交数据
        try:
            db.session.commit()
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg='保存图片信息异常')
    
        return jsonify(errno=RET.OK, data={'url': ret['url']})
    

    注:

    1. 和之前的上传用户头像接口类似, 前端数据不是通过json格式传入, 而是使用浏览器表单提交的方式传输数据, 除了request.files.get('house_image')获取文件数据外, 还需要获取表单中的house_id = request.form.get('house_id')

    2. 将七牛上传图片接口返回的url存入数据库中, 并返回给前端

    上传房屋图片前端逻辑

    在房屋发布页面对应的js文件newhouse.js中添加以下逻辑, 与之前的上传用户头像接口类似

    //上传房屋图片的表单
    $('#form-house-image').submit(function (e) {
        //阻止表单默认提交行为
        e.preventDefault()
        //自定义提交行为
        $(this).ajaxSubmit({
            url: 'api/v1.0/house/images',
            type: 'POST',
            headers: {'X-CSRFToken': getCookie('csrf_token')},
            dataType: 'json',
            success: function (resp) {
                if (resp.errno == '0'){
                    //上传成功, 展示图片
                    $('.house-image-cons').append('<img src="' + resp.data.url + '"></img>')
                }else {
                    //上传失败
                    alert(resp.errmsg)
                }
            }
        })
    })
    
    1. 阻止表单的完整提交行为, 因为发送的是文件数据, 用普通的ajax请求不好处理, 而使用.ajaxSubmit方法可以将发送的功能交给浏览器默认的表单提交, 而回调函数依旧可以自定义处理
    2. 上传成功后, 将图片展示出来, 使用appenddiv中添加img标签, 设置src属性为返回的图片url

    更新房屋信息接口

    这里做一个改进, 就是在成功发布房源信息之后, 将原来的按钮文字发布房源信息变成更新房源信息, 可以继续修改上面的房屋数据, 再点击更新按钮即可更新房屋数据.

    在发布新房源信息的html文件newhouse.html中的发布房源的form中也添加一个隐藏的input输入框, 用来保存第一次成功发布房源信息后的house_id, 用于第二次的更新操作

    <form id="form-house-info">
        ......
        <div class="form-group">
            <input type="hidden" name="house_id" id="new-house-id" value="">
            <label for="house-title">房屋标题</label>
            <input type="text" class="form-control" name="title" id="house-title" value="test" required>
        </div>
        ......
    

    后端逻辑修改

    @api.route('/houses', methods=['POST', 'PUT'])
    @login_required
    def create_or_update_house():
        # 接收数据
        data_dict = request.get_json()
        if not data_dict:
            return parameter_error()
        # 提取数据
        title = data_dict.get('title')
        price = data_dict.get('price')
        area_id = data_dict.get('area_id')
        address = data_dict.get('address')
        room_count = data_dict.get('room_count')
        acreage = data_dict.get('acreage')
        unit = data_dict.get('unit')
        capacity = data_dict.get('capacity')
        beds = data_dict.get('beds')
        deposit = data_dict.get('deposit')
        min_days = data_dict.get('min_days')
        max_days = data_dict.get('max_days')
        facility_ids = data_dict.get('facilities')
        house_id = data_dict.get('house_id')
    
        # 校验数据
        if not all(
                [title, price, area_id, address, room_count, acreage, unit, capacity, beds, deposit, min_days, facility_ids]):
            return parameter_error()
    
        # 校验金额格式, 转化为两位小数
        try:
            price = round(float(price), 2)
            deposit = round(float(deposit), 2)
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.PARAMERR, errmsg='金额格式有误')
    
        # 校验数字类型
        try:
            room_count = int(room_count)
            acreage = int(acreage)
            capacity = int(capacity)
            min_days = int(min_days)
            max_days = int(max_days)
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.PARAMERR, errmsg='房屋面积/房屋数目/宜住人数/最少最多天数必须为数字')
    
        # area_id是否存在
        try:
            area = Areas.query.get(area_id)
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg='获取城区信息异常')
        if not area:
            return jsonify(errno=RET.PARAMERR, errmsg='城区ID不存在')
    
        # 最小最大入住日期
        if min_days > max_days | max_days >= 0:
            return jsonify(errno=RET.PARAMERR, errmsg='最小日期不能超过最大日期')
    
        # 给房屋添加设施信息
    
        # 第一种: 循环校验每个设施, 然后通过append添加
        # for facility_id in facility_ids:
        #     # 循环校验设施ID
        #     try:
        #         facility = Facilities.query.get(facility_id)
        #     except Exception as e:
        #         current_app.logger.error(e)
        #         return jsonify(errno=RET.DBERR, errmsg='获取设施信息异常')
        #     if not facility:
        #         return jsonify(errno=RET.DBERR, errmsg=f'设施ID"{facility_id}"不存在')
        #     # 创建房屋设置数据
        #     house.facilities.append(facility)
    
        # 第二种: 不循环, 通过in_(list)查询设施, 但是这样不会处理错误的设施id
        try:
            facilities = Facilities.query.filter(Facilities.id.in_(facility_ids)).all()
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg='获取设施信息异常')
        if not facilities:
            return jsonify(errno=RET.PARAMERR, errmsg='无有效的设施ID')
    
        # POST则创建新房屋对象, PUT则更新房屋
        if request.method == 'POST':
            # 创建房屋对象
            house = Houses(user_id=g.user.id, area_id=area_id, title=title, price=price, address=address,
                           room_count=room_count, acreage=acreage, unit=unit, capacity=capacity, beds=beds, deposit=deposit,
                           min_days=min_days, max_days=max_days, facilities=facilities)
        else:
            # 获取房屋对象
            try:
                house = Houses.query.get(house_id)
            except Exception as e:
                current_app.logger.error(e)
                return jsonify(errno=RET.DBERR, errmsg='获取房屋信息异常')
            if not house:
                return jsonify(errno=RET.PARAMERR, errmsg='房屋ID不存在')
            # 重新设置房屋属性
            house.area_id = area_id
            house.title = title
            house.price = price
            house.address = address
            house.room_count = room_count
            house.acreage = acreage
            house.unit = unit
            house.capacity = capacity
            house.beds = beds
            house.deposit = deposit
            house.min_days = min_days
            house.max_days = max_days
            house.facilities = facilities
    
        # 提交房屋信息
        try:
            db.session.add(house)
            db.session.commit()
        except IntegrityError as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.PARAMERR, errmsg='该房屋标题已存在')
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg='保存房屋信息异常')
    
        return jsonify(errno=RET.OK, data={'house_id': house.id}
    

    注:

    1. 请求方法中新增PUT方法
    2. PUTPOST前面接收/校验数据逻辑都一样, 只是把之前的创建房屋house对象移到了设置facilities对象的后面, 再根据请求方式判断是创建house对象还是根据house_id查询并更新house对象

    前端逻辑修改

        //发布房源表单的提交
        $('#form-house-info').submit(function (e) {
            //阻止默认
            e.preventDefault();
            //自定义提交
            //获取数据
            var data = {};
            //获取form表单中的所有input提交项, 使用map循环每个input获取name和value
            $(this).serializeArray().map(function (item) {
                data[item.name] = item.value;
            })
            //获取复选框中勾选的设施项
            var facility_ids = [];
            $('input:checkbox:checked').each(function (index, item) {
                facility_ids[index] = $(item).val();
            })
            data["facilities"] = facility_ids;
            //转为json
            var data = JSON.stringify(data);
    
            //根据new_house_id判断是更新还是创建
            var newHouseID = $('#new-house-id').val();
            if (newHouseID){
                var type = 'PUT';
            }
            else{
                var type = 'POST';
            }
            $.ajax({
                url: 'api/v1.0/houses',
                type: type,
                contentType: 'application/json',
                data: data,
                headers: {'X-CSRFToken': getCookie('csrf_token')},
                dataType: 'json',
                success: function (resp) {
                    if (resp.errno == '0'){
                        //发布成功
                        //设置house_id
                        $('#house-id').val(resp.data.house_id);
                        $('#new-house-id').val(resp.data.house_id);
                        //修改按钮提示
                        $('.btn-commit').val('修改房源信息');
                        //展示上传图片表单
                        $('#form-house-image').show();
                        alert('保存成功, 请上传房屋图片');
                    }else {
                        //发布失败
                        alert(resp.errmsg)
                    }
                }
            })
        })
    

    注:

    1. 成功发布房源之后也要再设置一下new-house-id的值,

    2. 先获取new-house-id的值, 存在则说明需要更新, 请求方式为PUT, 不存在说明需要创建, 请求方式为POST

  • 相关阅读:
    leetcode 414
    Leetcode 495
    Leetcode 485题
    Python 24点(2)
    python 24点
    我的第一次作业
    Django
    multiprocessing模块
    遍历文档树
    shutil模块
  • 原文地址:https://www.cnblogs.com/gcxblogs/p/13566040.html
Copyright © 2011-2022 走看看