django商城项目中用户地址管理的增删改查

django商城项目中用户地址管理的增删改查

  • 前文
  • 先写后端逻辑
    • 要保存地址先设计Model模型
    • 然后就是怎么设置用户的默认收货地址
    • urls配置路径
    • view.py写增删改查的接口
    • 序列化器逻辑
  • 写前端逻辑
    • js怎么展示省市区select标签内容
    • js写展示地址、新增地址、删除地址
    • 修改地址

前文

先看下要实现的效果:
django商城项目中用户地址管理的增删改查_第1张图片

先写后端逻辑

要保存地址先设计Model模型

models.py写一个地址信息类

class AddressInfo(models.Model):
    # 需要写外键,对应用户
    user = models.ForeignKey(Users, on_delete=models.CASCADE, related_name='address', verbose_name='用户')
    receiver = models.CharField(max_length=20, verbose_name='收货人')
    # 导不是当前页面的外键
    province = models.ForeignKey('areas.Areas', on_delete=models.PROTECT, verbose_name='省份', related_name='province_address')
    city = models.ForeignKey('areas.Areas', on_delete=models.PROTECT, verbose_name='省份', related_name='city_address')
    district = models.ForeignKey('areas.Areas', on_delete=models.PROTECT, verbose_name='省份', related_name='district_address')
    detail_place = models.CharField(max_length=50, verbose_name='详细地址')
    postcode = models.CharField(max_length=6, verbose_name='邮编')
    phone = models.CharField(max_length=11, verbose_name='手机')
    # 设置是否为默认地址

    # 逻辑删除
    is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')

    class Meta:
        db_table = 'sh_user_address'
        verbose_name_plural = '地址管理'
  • 逻辑删除意思是实际上不删除,但是有个布尔值为真则代表删除,不展示
  • 写完注意数据库迁移makemigrations,migrate,然后admin界面注册模型
  • Address模型类中的外键指向Areas/models里面的Area,指明外键ForeignKey时,可以使用字符串应用名.模型类名来定义
  • related_name 在进行反向关联查询时使用的属性,如 city = models.ForeignKey(‘areas.Areas’,
    related_name=‘city_address’)表示可以通过Area对象.city_address属性获取所有相关的city数据。
  • ordering 表名在进行Address查询时,默认使用的排序方式

然后就是怎么设置用户的默认收货地址

可以有两种方法,一是在收货地址这个模型类中多加一个字段,证明是默认收货地址,但是这个方法在设置默认地址和取消默认地址的时候,会很麻烦,取消默认地址的时候,需要先查哪个是默认地址,然后取消那个标记,然后再设置另外一个标记,这样多增加了数据库的操作。

第二种方法是在用户表中多加一个字段,外键关联到要设置默认地址的那条记录上,这里采用这种方法

为User模型类添加默认地址

class User(AbstractUser):
    ...
    default_address = models.ForeignKey('Address', related_name='users', null=True, blank=True, on_delete=models.SET_NULL, verbose_name='默认地址')
    ...

这次暂时没写这个默认地址,下次补齐

urls配置路径

from .views import *
from rest_framework.routers import DefaultRouter

# 路由器
router = DefaultRouter()
router.register(r'^addressinfo', AddressInfoView, base_name='addressinfo')

urlpatterns = []
urlpatterns += router.urls

view.py写增删改查的接口

class AddressInfoView(ModelViewSet):
    # 地址增删改查
    serializer_class = AddressSerCLass
    # 权限
    permission_classes = (IsAuthenticated, )

    def get_queryset(self):
        print('inner')
        print(self.request.user.address.filter(is_delete=False))
        return self.request.user.address.filter(is_delete=False)

    def list(self, request, *args, **kwargs):
        query_set = self.get_queryset()
        ser = self.get_serializer(query_set, many=True)
        return Response({
            'address': ser.data
        })

    def create(self, request, *args, **kwargs):
        # 检查用户地址数据的数量不能超过上限
        # 获取用户地址的数量
        count = request.user.address.count()
        if count >= 10:
            return Response({'errmsg': '不能超过10条'})

        return super().create(request, *args, **kwargs)

    def destroy(self, request, *args, **kwargs):
    	# 删除把逻辑删除置为真即可
        add_obj = self.get_object()
        add_obj.is_delete = True
        add_obj.save()

        return Response('删除成功')

序列化器逻辑

因为省市区三个是外键所以自动会变成_id后缀

class AddressSerCLass(serializers.ModelSerializer):
    province_id = serializers.IntegerField(required=True)
    city_id = serializers.IntegerField(required=True)
    district_id = serializers.IntegerField(required=True)

    province = serializers.StringRelatedField(read_only=False)
    city = serializers.StringRelatedField(read_only=False)
    district = serializers.StringRelatedField(read_only=False)

    class Meta:
        model = AddressInfo
        exclude = ('user', 'is_delete')

    def create(self, validated_data):
        print('#####################')
        print(self.context['request'].user)  # 取得user
        validated_data['user'] = self.context['request'].user

        return super().create(validated_data)
  • exclude是除什么外的值都要
  • 重写create方法保存用户的地址
  • view.py中的get_serializer(self, args, *kwargs)方法:
    返回序列化器对象,主要用来提供给Mixin扩展类使用,如果我们在视图中想要获取序列化器对象,也可以直接调用此方法。

*注意,get_serializer(self, args, kwargs)方法在提供序列化器对象的时候,会向序列化器对象的context属性补充三个数据:request、format、view,这三个数据对象可以在定义序列化器时使用。

  • request 当前视图的请求对象
  • view 当前请求的类视图对象
  • format 当前请求期望返回的数据格式
  • 通过一段伪代码表现context获取参数数据
# 判断用户是否在60s内使用同一个手机号码获取短信,mobile为手机号。通过context来获取当前类视图对象,通过kwargs来获取mobile。
mobile = self.context['view'].kwargs['mobile']
send_flag = redis_conn.get('send_flag_%s' % mobile)

if send_flag:
       raise serializers.ValidationError('频繁发送短信')

写前端逻辑

也可以用postman模拟

js怎么展示省市区select标签内容

效果大概是这样
django商城项目中用户地址管理的增删改查_第2张图片

/**
 * Created by python on 19-6-24.
 */
// 这个js是写展示省市区
var token = localStorage.token;

function get_son_areaid(select_name, father_id) {
    // 显示下一级区域的方法
    $.ajax({
        type: 'GET',
        url: 'http://127.0.0.1:8000/areas/info/' + father_id,
        success: function(data) {
            $(select_name).empty();
            console.log(data);
            var arr=data.addinfo;
            $.each(arr, function(index, value) {
                $(select_name).append(" value.id + '>' + value.name + '')
            });
            if (select_name == "#select_cities"){
                console.log('xiangtong', arr[0].id);
                get_son_areaid('#select_district', arr[0].id)
            }
        },
        error: function() {
            alert('读取失败')
        }
    })
}

$(function () {
    // 显示省份
    $.ajax({
        type: 'GET',
        url: 'http://127.0.0.1:8000/areas/info/',

        success: function(data) {
            console.log(data);
            $("#select_provinces").empty();
            $.each(data, function(index, value) {
                // $("#select_provinces").append("")
                //为Select追加一个Option(下拉项)
                $("#select_provinces").append(" value.id + '>' + value.name + '');
            })
        },
        error: function() {
            alert('读取省份失败')
        }
    });
    // 选择省份显示市
    $('#select_provinces').change(function() {
        var check_val= $(this).val();
        get_son_areaid("#select_cities", check_val);

    });
    // 选择市显示区
    $('#select_cities').change(function() {
        var check_val= $(this).val();
        get_son_areaid("#select_district",check_val)
    });

});

js写展示地址、新增地址、删除地址

/**
* Created by python on 19 - 6 - 21.
*/
var token = localStorage.token;

$(function() {
    // 展示所有地址
    $.ajax({
        url: 'http://127.0.0.1:8000/users/addressinfo/',
        headers: {
                'Authorization': 'JWT ' + token
            },
        type: 'GET',
        dataType:'json',
        contentType: 'application/json',
        success:function (data) {
            console.log(data);
            // 张小泉江苏南京雨花台区大件路4号软件大厦B栋102室21000012343323221个人修改 | 删除
            $('#show_address').html('');
            $.each(data, function (add, arr) {
                for (var i=0; i<arr.length;i++){
                    add_obj = arr[i];
                    add_id = add_obj['id'];
                    $('#show_address').append(""+add_obj['receiver']+""+add_obj['province']+add_obj['city']+add_obj['district']+""+add_obj['detail_place']+""+add_obj['postcode']+""+add_obj['phone']+"个人修改 | 删除");
                }
            })
        },
        error:function (data) {
            alert('展示地址失败');
            console.log(data)
        }
    })

});
// 保存地址,拼接内容,用户名,地址,手机号,邮编,是否默认
function click_save_address() {
    var receiver = $('#receiver').val();
    var province = $('#select_provinces').val();
    var city = $('#select_cities').val();
    var district = $('#select_district').val();
    var detail_place = $('#detail_place').val();
    var postcode = $('#postcode').val();
    var phone = $('#phone').val();
    console.log(token);
    var send_data = {
        'receiver': receiver,
        'province_id': province,
        'city_id': city,
        'district_id': district,
        'detail_place': detail_place,
        'postcode': postcode,
        'phone': phone
    };
    send_data = JSON.stringify(send_data);

    $.ajax({

        url: 'http://127.0.0.1:8000/users/addressinfo/',
        headers: {
                'Authorization': 'JWT ' + token
            },
        type: 'POST',
        data: send_data,
        dataType:'json',
        contentType: 'application/json',
        success:function (data) {
            console.log(data)
        },
        error:function (data) {
            alert('保存地址失败');
            console.log(data)
        }
    })
}
// 删除一个地址
function delete_address(add_id) {
    alert(add_id);
    $.ajax({

        url: 'http://127.0.0.1:8000/users/addressinfo/' +add_id +'/',
        headers: {
                'Authorization': 'JWT ' + token
            },
        type: 'DELETE',
        dataType:'json',
        contentType: 'application/json',
        success:function (data) {
            console.log(data)
        },
        error:function (data) {
            alert('删除地址失败');
            console.log(data)
        }
    })
}

修改地址

重点是a标签跳转网页时带上id参数:

<a href='user_updateadd.html?id="+add_id+"'>修改</a>

然后是在修改网页如何用Jq获取到这个参数

// 取得当前的id值
function GetRequest() {
    var url = location.search; //获取url中"?"符后的字串
    var theRequest = new Object();
    if (url.indexOf("?") != -1) {
        var str = url.substr(1);
        strs = str.split("&");
        for (var i = 0; i < strs.length; i++) {
            theRequest[strs[i].split("=")[0]] = decodeURIComponent(strs[i].split("=")[1]);
        }
    }
    return theRequest;
}
var a=GetRequest();
console.log("id:"+a['id']);

最后发送一个请求类型为PUT的ajax请求即可,带上修改的数据,验证用户信息请求头

你可能感兴趣的:(Django)