慕西商城开发笔记:(四:用户接口)

64 阅读5分钟

用户注册

user/views

class UserApiView(APIView):
    #注册功能实现
    def post(self,request):
        # 反序列化,json变对象
        user_data_serializer=UserSerializer(data=request.data)
        user_data_serializer.is_valid(raise_exception=True)
        user_data=user_data_serializer.save()

        #返回之前需要序列化
        user_ser=UserSerializer(instance=user_data)
        return ResponseMessage.UserResponse.success(user_ser.data)

user_data = user_data_serializer.save()

这个方法的作用是将序列化器的数据保存到数据库中。我们之前的写法是: user_data=User.objects.create(**user_data_serializer.data),很明显使用save更加简洁

user/serializers

import datetime

from rest_framework import serializers
from rest_framework.validators import UniqueValidator

from apps_shop.user.models import User
from utils.password_encode import get_md5


class UserSerializer(serializers.ModelSerializer):
    # email作为用户名进行登录,这里我们需要做一个唯一性的验证
    email = serializers.EmailField(
        required=True,
        allow_blank=False,
        validators=[UniqueValidator(queryset=User.objects, message="用户已经存在了")]
    )
    # password = serializers.CharField(write_only=True)
    password = serializers.CharField()
    birthday = serializers.DateTimeField("%Y-%m-%d %H:%M:%S")
    create_time = serializers.DateTimeField("%Y-%m-%d %H:%M:%S",required=False)
    # create方法会被自动调用,这里可以做一些数据的验证或者是存储之前数据的加工
    def create(self, validated_data):
        print("create方法被调用了")
        print(validated_data)
        validated_data["password"] = get_md5(validated_data["password"])
        validated_data["create_time"] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        result = User.objects.create(**validated_data)
        return result

    class Meta:
        model = User
        fields = "__all__"

我们对数据进行加工之后直接赋值,就可以保证密码不被泄露,因为存储和返回的都是加密过后的

md5

对用户密码进行加密

password = serializers.CharField(write_only=True) 只写属性,表示不能读,我们返回也就没有密码,防止被拦截密码

.datetime.now().strftime

生成当前时间并且格式化时间

user/urls

from django.urls import path
from .views import UserApiView
urlpatterns = [
    # 注册
    path('',UserApiView.as_view()),
]

根目录 utils/ResponseMessage

# 用户的响应全部都是4开头的
class UserResponse():

    @staticmethod
    def success(data):
        result = {"status":4000,"data":data}
        return JsonResponse(result,safe=False)

    @staticmethod
    def failed(data):
        result = {"status": 4001, "data": data}
        return JsonResponse(result, safe=False)

    @staticmethod
    def other(data):
        result = {"status": 4002, "data": data}
        return JsonResponse(result, safe=False)

数据库

alter table user modify create_time datetime null default CURRENT_TIMESTAMP

用户信息获取

user/views

# Create your views here.
class UserApiView(APIView):
.....
    #获取用户信息
    def get(self, request):
        email = request.GET.get("email")
        try:
            user_data = User.objects.get(email=email)
            user_ser = UserSerializer(user_data)
            return ResponseMessage.UserResponse.success(user_ser.data)
        except Exception as e:
            print(e)
            return ResponseMessage.UserResponse.failed("用户信息获取失败")

try...except

try 后面的代码块是你要尝试执行的代码。如果在这个代码块中发生了异常,Python 将跳过剩余的代码并进入与异常类型匹配的 except 块,从而进行异常处理

try: 
    # 可能引发异常的代码块 
except ExceptionType1:
    # 处理 ExceptionType1 类型的异常 
except ExceptionType2: 
    # 处理 ExceptionType2 类型的异常 
else: 
    # 如果没有发生任何异常,则执行该块 
finally: 
    # 无论是否发生异常,都会执行该块

订单

创建订单

数据库

create table order_goods(
	id int not null auto_increment,
	trade_no varchar(255) collate utf8mb4_general_ci,
	sku_id varchar(255) collate utf8mb4_general_ci,
	goods_num int,
	create_time datetime default CURRENT_TIMESTAMP,
	primary key(id)
)engine=INNODB charset=utf8mb4 collate=utf8mb4_general_ci;

create table `order`(
	id int not null auto_increment,
	email varchar(255) collate utf8mb4_general_ci,
	order_amount decimal(10,2),
	address_id int, 
	pay_status varchar(155),
	pay_time datetime default CURRENT_TIMESTAMP,
	ali_trade_no varchar(255) collate utf8mb4_general_ci,
	is_delete int UNSIGNED default 0,
	create_time datetime default CURRENT_TIMESTAMP,
	update_time datetime default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
	primary key(id)
)engine=INNODB charset=utf8mb4 collate=utf8mb4_general_ci;

collate

order/models

# This is an auto-generated Django model module.
# You'll have to do the following manually to clean this up:
#   * Rearrange models' order
#   * Make sure each model has one field with primary_key=True
#   * Make sure each ForeignKey and OneToOneField has `on_delete` set to the desired behavior
#   * Remove `managed = False` lines if you wish to allow Django to create, modify, and delete the table
# Feel free to rename the models, but don't rename db_table values or field names.
from django.db import models


class Order(models.Model):
    email = models.CharField(max_length=255, blank=True, null=True)
    trade_no = models.CharField(max_length=155, blank=True, null=True)
    order_amount = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
    address_id = models.IntegerField(blank=True, null=True)
    pay_status = models.CharField(max_length=155, blank=True, null=True)
    pay_time = models.DateTimeField(blank=True, null=True)
    ali_trade_no = models.CharField(max_length=255, blank=True, null=True)
    is_delete = models.PositiveIntegerField(blank=True, null=True)
    create_time = models.DateTimeField(blank=True, null=True)
    # update_time = models.DateTimeField(blank=True, null=True)

    class Meta:
        managed = False
        db_table = 'order'


class OrderGoods(models.Model):
    trade_no = models.CharField(max_length=255, blank=True, null=True)
    sku_id = models.CharField(max_length=255, blank=True, null=True)
    goods_num = models.IntegerField(blank=True, null=True)
    # create_time = models.DateTimeField(blank=True, null=True)

    class Meta:
        managed = False
        db_table = 'order_goods'

order/views

class OrderGoodsGenericAPIView(GenericAPIView):
    queryset = OrderGoods.objects
    serializer_class = OrderGoodsSerializer
    def post(self, request):
        ser = self.get_serializer(data=request.data)
        ser.is_valid()
        ser.save()
        return JsonResponse("ok",safe=False)

queryset = OrderGoods.objects

该视图类提供了一个 queryset 属性,它指定了要在视图中使用的查询集。在这里,queryset 被设置为 OrderGoods.objects,意味着你将使用 OrderGoods 模型的查询集作为数据源,就是这里我可以直接获取到整个数据集

order/Serializer

from rest_framework import serializers
from apps_shop.order.models import OrderGoods

class OrderGoodsSerializer(serializers.ModelSerializer):
    class Meta:
        model = OrderGoods
        fields = "__all__"

order/urls

path("goods/",OrderGoodsGenericAPIView.as_view()),

获取订单接口

order/views

lookup_field = "trade_no"
def get(self, request,trade_no):
    # 这一行代码就实现了数据库里所有数据的查询
    # return JsonResponse(self.get_serializer(instance=self.get_queryset(),many=True).data,safe=False)
    # ser = self.get_serializer(instance=self.get_object(),many=False)
    ser = self.get_serializer(instance=self.get_object(),many=True)
    return JsonResponse(ser.data,safe=False)

ser = self.get_serializer(instance=self.get_object(),many=False)

queryset = OrderGoods.objects

serializer_class = OrderGoodsSerializer

order/urls

from django.urls import path, re_path
from .views import OrderGoodsGenericAPIView

urlpatterns = [
    path("goods/",OrderGoodsGenericAPIView.as_view()),
    re_path("goods/(?P<trade_no>.*)",OrderGoodsGenericAPIView.as_view()),
]

re_path("goods/(?P<trade_no>.*)

收货地址接口

address/models

# This is an auto-generated Django model module.
# You'll have to do the following manually to clean this up:
#   * Rearrange models' order
#   * Make sure each model has one field with primary_key=True
#   * Make sure each ForeignKey and OneToOneField has `on_delete` set to the desired behavior
#   * Remove `managed = False` lines if you wish to allow Django to create, modify, and delete the table
# Feel free to rename the models, but don't rename db_table values or field names.
from django.db import models


class UserAddress(models.Model):
    id = models.IntegerField(primary_key=True)
    email = models.CharField(max_length=255, blank=True, null=True)
    signer_name = models.CharField(max_length=255, blank=True, null=True)
    telphone = models.CharField(max_length=255, blank=True, null=True)
    signer_address = models.CharField(max_length=255, blank=True, null=True)
    district = models.CharField(max_length=255, blank=True, null=True)
    default = models.IntegerField(blank=True, null=True)
    create_time = models.DateTimeField()

    class Meta:
        managed = False
        db_table = 'user_address'

问题

RuntimeError: You called this URL via POST, but the URL doesn't end in a slash and you have APPEND_SLASH set. Django can't redirect to the slash URL while maintaining POST data. Change your form to point to localhost:8000/user/ (note the trailing slash), or set APPEND_SLASH=False in your Django settings.

解决:请求路径要以斜杠结尾

TypeError: django.db.models.query.QuerySet.create() argument after ** must be a mapping, not UserSerializer

解决:忘记取data image.png

AssertionError: 'OrderGoodsGenericAPIView' should either include a queryset attribute, or override the get_queryset() method.

解决:在视图类中设置 queryset 属性,并将其指定为合适的查询集对象。例如:serializer_class = OrderGoodsSerializer

apps_shop.order.models.OrderGoods.MultipleObjectsReturned: get() returned more than one OrderGoods -- it returned 3!

未知:这里报错是因为返回了多个数据,但是我们明确写了many=true,但是还是报错

image.png