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

posted @ 2020-08-26 16:38  Alex-GCX  阅读(207)  评论(0编辑  收藏  举报