一、设计用户地址数据表
1、models中添加Address模型
-
Address模型类中的外键指向Areas/models里面的Area,指明外键ForeignKey时,可以使用字符串
应用名.模型类名
来定义 -
related_name 在进行反向关联查询时使用的属性,如
city = models.ForeignKey('areas.Area', related_name='city_addresses')
表示可以通过Area对象.city_addresses属性获取所有相关的city数据。 -
ordering 表名在进行Address查询时,默认使用的排序方式
class Address(BaseModel):
"""
用户地址
"""
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='addresses', verbose_name='用户')
title = models.CharField(max_length=20, verbose_name='地址名称')
receiver = models.CharField(max_length=20, verbose_name='收货人')
province = models.ForeignKey('areas.Area', on_delete=models.PROTECT, related_name='province_addresses',
verbose_name='省')
city = models.ForeignKey('areas.Area', on_delete=models.PROTECT, related_name='city_addresses', verbose_name='市')
district = models.ForeignKey('areas.Area', on_delete=models.PROTECT, related_name='district_addresses',
verbose_name='区')
place = models.CharField(max_length=50, verbose_name='地址')
mobile = models.CharField(max_length=11, verbose_name='手机')
tel = models.CharField(max_length=20, null=True, blank=True, default='', verbose_name='固定电话')
email = models.CharField(max_length=30, null=True, blank=True, default='', verbose_name='电子邮箱')
is_deleted = models.BooleanField(default=False, verbose_name='逻辑删除')
class Meta:
db_table = 'tb_address'
verbose_name = '用户地址'
verbose_name_plural = verbose_name
ordering = ['-update_time']
2、为User模型增加默认地址
class User(AbstractUser):
default_address = models.ForeignKey('Address', related_name='users', null=True, blank=True, on_delete=models.SET_NULL, verbose_name='默认地址')
二、创建用户收货地址序列化器
class UserAddressSerializer(serializers.ModelSerializer):
"""
用户地址序列化器
"""
province = serializers.StringRelatedField(read_only=True)
city = serializers.StringRelatedField(read_only=True)
district = serializers.StringRelatedField(read_only=True)
province_id = serializers.IntegerField(label='省ID', required=True)
city_id = serializers.IntegerField(label='市ID', required=True)
district_id = serializers.IntegerField(label='区ID', required=True)
class Meta:
model = Address
exclude = ('user', 'is_deleted', 'create_time', 'update_time') # 排除
def validate_mobile(self, value):
"""
验证手机号
"""
if not re.match(r'^1[3-9]\d{9}$', value):
raise serializers.ValidationError('手机号格式错误')
return value
def create(self, validated_data):
"""保存"""
# 因为上面排除了user字段(exclude) 所有模型中就没有user了,就需要我们自己进行添加user模型
validated_data['user'] = self.context['request'].user
return super().create(validated_data)
三、收货地址的增删改查
@action() action装饰器可以接受两个参数: methods: 声明该action对应的请求方法 detail:声明该action的路径是否与单一资源对应 看看是不是只修改一个 True 格式 xxx/<pk>/action方法名 False 格式 xxx/action方法名
class AddressViewSet(UpdateModelMixin, GenericViewSet):
"""用户收货地址 增删改查"""
permission_classes = [IsAuthenticated]
serializer_class = UserAddressSerializer
# 重写
def get_queryset(self):
return self.request.user.addresses.filter(is_deleted=False)
# POST /addresses/
def create(self, request):
"""
创建收货地址
"""
user = request.user
# count = user.addresses.all().count()
count = Address.objects.filter(user=user).count()
# 用户收货地址有上限 最多只能有20个
if count >= 20:
return Response({'message': '收货地址数量上限'}, status=status.HTTP_400_BAD_REQUEST)
# 创建序列化器进行反序列化
serializer = self.get_serializer(data=request.data)
# 调用序列化器的is_valid() 进行校验
serializer.is_valid(raise_exception=True)
# 调用序列化器的save()
serializer.save()
# 响应
return Response(serializer.data, status=status.HTTP_201_CREATED)
# GET /addresses/
def list(self, request, *args, **kwargs):
"""
用户地址列表数据
"""
queryset = self.get_queryset() # get_queryset在上面进行了重写
serializer = self.get_serializer(queryset, many=True)
user = self.request.user
return Response({
'user_id': user.id,
'default_address_id': user.default_address_id,
'limit': 20,
'addresses': serializer.data,
})
# delete /addresses/<pk>/
def destroy(self, request, *args, **kwargs):
"""
处理删除
"""
address = self.get_object()
# 进行逻辑删除
address.is_deleted = True
address.save()
return Response(status=status.HTTP_204_NO_CONTENT)
# put /addresses/pk/title/
# 需要请求体参数 title
@action(methods=['put'], detail=True)
def title(self, request, pk=None):
"""
修改标题
"""
address = self.get_object()
serializer = AddressTitleSerializer(instance=address, data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)
# put /addresses/pk/status/
@action(methods=['put'], detail=True)
def status(self, request, pk=None):
"""
设置默认地址
"""
address = self.get_object()
request.user.default_address = address
request.user.save()
return Response({'message': 'OK'}, status=status.HTTP_200_OK)
四、添加urls路由
urlpatterns = [
.......
]
router = routers.DefaultRouter()
router.register('addresses', views.AddressViewSet, basename='addresses')
urlpatterns += router.urls