Django

 创建项目

# Pycharm的Termianl
django-admin startproject Django .

启动项目

python3 manage.py  runserver 0.0.0.0:8888

默认项目文件

mysite
├── manage.py         【项目的管理,启动项目、创建app、数据管理】【不要动】【***常常用***】
└── mysite
    ├── __init__.py
    ├── settings.py    【项目配置】          【***常常修改***】
    ├── urls.py        【URL和函数的对应关系】【***常常修改***】
    ├── asgi.py        【接收网络请求】【不要动】
    └── wsgi.py        【接收网络请求】【不要动】

应用

创建子应用

意义:将各个子功能模块保持独立,达到解耦。也可以达到复用。

# Pycharm的Termianl
python3 manage.py startapp projects
├── projects
│   ├── __init__.py       包文件
│   ├── admin.py         【固定,不用动】用于配置admin后台管理站点。
│   ├── apps.py          【固定,不用动】用于配置子应用信息。
│   ├── migrations       【固定,不用动】用于存放迁移脚本,数据库变更记录
│   │   └── __init__.py
│   ├── models.py        【**重要**】用于定义模型类。
│   ├── tests.py         【固定,不用动】单元测试
│   └── views.py         【**重要**】编写子应用业务逻辑的模块。
├── manage.py
└── mysite2
    ├── __init__.py
    ├── asgi.py
    ├── settings.py
    ├── urls.py          【URL->函数】
    └── wsgi.py

注册应用

第一种:将子应用名追加到根项目里的settings里
第二种:将子应用app里的函数名,追加到根项目里的settings里

视图函数

        在子应用views.py文件中定义的函数叫视图函数。

路由

 定义路由

        request是一个对象,封装了用户通过浏览器发送过来的所有数据。

# 什么是路由?
    指URL与后端视图之间的一一映射关系

# 全局路由
    根路径下的urls

# 子路由
    在子应用下手动创建的urls

# 如何添加路由?
    1. 需要在全局路由文件中urls.py,urlpatterns列表中添加路由条目。
    2. urlpatterns列表条目总数就是路由总数。

# 路由如何匹配
    1. 路由匹配规则是从上到下全等匹配。(路由寻址)
    2. 匹配成功则停止匹配。
    3. 若条目全都不匹配,则抛出404异常。

# path函数
    1. 用于定义路由条目。
    2. 第一个参数是url路径参数字符串,只需在后面加/。
    3. 第二个参数为视图函数或类视图,如果添加的是视图函数,无需使用()调用。

子路由

路由中带有数值变量

关闭csrf安全认证

类视图

路由中带有数值变量

返回json数据

class ProjectView(View):
    def get(self, request, id):
        return HttpResponse(f"欢迎get{id}老baby")

    def post(self, request):
        result = {"msg": "登录超时,请重新登录", "code": 60001}

        # 1、第一种
        str = json.dumps(result, ensure_ascii=False)
        # content_type输出格式是json格式
        return HttpResponse(str, content_type="application/json")

        # 2、第二种,不用转json格式了,直接返回json格式
        return  JsonResponse(result,json_dumps_params={"ensure_ascii":False})

        # 3、第三种,可以返回多种格式,关闭安全模式
        return JsonResponse(result, json_dumps_params={"ensure_ascii": False},safe=False)

提取入参

    def post(self, request):
        # 1、提取入参,表单形式,x-www-form-urlencoded
        result = request.POST['提取的参数名']
        # 2、提取入参,Json形式
        result = json.loads(request.body)
        # 3、提取入参,文件,文件流,他是个文件流,form-data
        request.FILES
        # 4、提取入参,文件,文件流,binary
        request.body
        # 5、提取入参,请求头headers
        result = request.headers['提取的参数名']
        result = request.META['HTTP_大写提取的参数名']
        

 Rest Framework框架

基础配置

基本理念

class ProjectSerilizer(serializers.Serializer):
    """
    二、定义序列化器类
    1.必须得继承Serializer类或者Serializer子类
    2.定义的序列化器类中,字段名要与模型类中的字段名保持一致
        IntegerField  -> int
        CharField     -> str
        BooleanField  -> bool
        DateTimeField -> datetime
    3.定义的序列化器类的字段(类属性)为Field子类,与模型类中字段类型基本一致。
    4.默认定义的字段,要求前端必须入参且会返回前端。
    5.可以在序列化器字段中指定不同的选项
        label和help_text,与模型类中的verbose_name和help_text参数一样
        IntegerField,可以使用max_value指定最大值,min_value指定最小值
        CharField,可以使用max_length指定最大长度,min_length指定最小长度
    """

序列化器字段

id = serializers.IntegerField(label='项目id', help_text='项目id', max_value=1000, min_value=1)
name = serializers.CharField(max_length=20, min_length=5, write_only=True)
name = serializers.CharField(max_length=20, min_length=5, read_only=True)
name = serializers.CharField(max_length=20, min_length=5)
leader = serializers.CharField(allow_null=True)
leader = serializers.CharField(allow_blank=True)
leader = serializers.CharField(default='阿名')
is_execute = serializers.BooleanField()
update_time = serializers.DateTimeField()

应用

前端入参校验
"""
四、反序列化操作
1.定义序列化器类,使用data关键字参数传递字典参数。
2.可以使用序列化器对象调用.is_valid()方法,才会开始对前端输入的参数进行校验。
3.如果校验通过.is_valid()方法返回True,否则返回False。
4.如果调用.is_valid()方法,添加raise_exeception=True,校验不通过会抛出异常,否则不会抛出异常。
5.只有在调用.is_valid()方法之后:
    才可以使用序列化器对象调用.errors属性,来获取错误提示信息(字典类型)。
    才可以使用序列化器对象调用.validated_data属性,来获取校验通过之后的数据,与使用json.load转化之后的数据有区别
"""
def post(self, request):
    # 1、获取json参数并转化为python中的数据类型(字典)
    try:
        python_data = json.loads(request.body)
    except Exception as e:
        return JsonResponse({'msg': '参数有误'}, status=400)

    serializer11 = ProjectSerilizer(data=python_data)

    if not serializer11.is_valid(raise_exception=True):
        return JsonResponse(serializer11.errors, status=400)

    project_obj = Projects.objects.create(**serializer11.validated_data)

    serializer = ProjectSerilizer(instance=project_obj)
    return JsonResponse(serializer.data, status=201)
后端出参校验
"""
五、序列化器的使用
1.可以使用序列化器进行序列化输出操作。
2.创建序列化器对象。
3.可以将模型对象、查询集对象、普通对象、嵌套普通对象的列表,以instance关键字来传递参数。
4.如果传递的是查询集对象、嵌套普通对象的列表(!多条数据!),必须得设置many=True。
5.如果传递的是模型对象、普通对象,不需要设置many=True。
6.可以使用序列化器对象的.data属性,获取序列化器之后的数据(字典、嵌套字典的列表)。
"""
def get(self, request):
    # 1.获取所有项目数据(查询集),获取列表数据。
    queryset = Projects.objects.all()
    serializer = ProjectSerilizer(instance=queryset, many=True).data
    return JsonResponse(serializer, safe=False)




def get(self, request, pk):
    # 2.获取指定项目数据,单条数据(模型对象)。
    try:
        project_obj = Projects.objects.get(id=pk)
    except Exception as e:
        return JsonResponse({'msg': '参数有误'}, status=400)

    serializer = ProjectSerilizer(instance=project_obj).data
    return JsonResponse(serializer)



def put(self, request, pk):
    try:
        project_obj = Projects.objects.get(id=pk)
    except Exception as e:
        return JsonResponse({'msg': '参数有误'}, status=400)

    # 获取json参数并转化为python中的数据类型(字典)
    try:
        python_data = json.loads(request.body)
    except Exception as e:
        return JsonResponse({'msg': '参数有误'}, status=400)

    serializer11 = ProjectSerilizer(data=python_data)

    if not serializer11.is_valid():
        return JsonResponse(serializer11.errors, status=400)

    # 更新数据
    project_obj.name = serializer11.validated_data.get('name')
    project_obj.leader = serializer11.validated_data.get('leader')
    project_obj.is_execute = serializer11.validated_data.get('is_execute')
    project_obj.desc = serializer11.validated_data.get('desc')
    project_obj.save()

    serializer = ProjectSerilizer(instance=project_obj).data
    # return JsonResponse(python_dict, status=201)
    return JsonResponse(serializer, status=201)

自定义报错

校验单个字段

# 1、可以在序列化器类中对单个字段进行校验
# 2、单字段的校验方法名称,必须把validate_作为前缀,加上待校验的字段名,如:validate_待校验的字段名
# 3、如果校验不通过,必须得返回serializers.ValidationError('具体报错信息')异常
# 4、如果校验通过,往往需要将校验之后的值,返回
# 5、如果该字段在定义时添加的校验规则不通过,那么是不会调用单字段的校验方法
def validate_name(self, attr: str):
    if not attr.endswith('项目'):
        raise serializers.ValidationError('项目名称必须得以“项目”结尾')
    return attr

校验多个字段

# 1、可以在序列化器类中对多个字段进行联合校验
# 2、使用固定的validate方法,会接收上面校验通过之后的字典数据
# 3、当所有字段定义时添加的校验规则都通过,且每个字段的单字段校验方法通过的情况下,才会调用validate
    def validate(self, attrs: dict):
        if len(attrs.get('leader')) <= 4 or not attrs.get('is_execute'):
            raise serializers.ValidationError('项目负责人名称长度不能少于4位或者is_execute参数为False')
        return attrs

 校验字段模块整体的,后续整理

# -*- coding: utf-8 -*-
from rest_framework import serializers
from rest_framework.validators import UniqueValidator

from interfaces.models import Interfaces
from .models import Projects


# 1、自定义的序列化器类实际上也是Field的子类
# 2、所以自定义的序列化器类可以作为另一个序列化器中的字段来使用
class InterfaceSerilizer(serializers.Serializer):
    id = serializers.IntegerField()
    name = serializers.CharField()
    tester = serializers.CharField()


# 1、可以在类外自定义校验函数
# 2、第一个参数为待校验的值
# 3、如果校验不通过,必须得抛出serializers.ValidationError('报错信息')异常,同时可以指定具体的报错信息
# 4、需要将校验函数名放置到validators列表中
def is_contains_keyword(value):
    if '项目' not in value:
        raise serializers.ValidationError('项目名称中必须得包含“项目”关键字')


class ProjectSerilizer(serializers.Serializer):
    """
    二、定义序列化器类
    1.必须得继承Serializer类或者Serializer子类
    2.定义的序列化器类中,字段名要与模型类中的字段名保持一致
    3.定义的序列化器类的字段(类属性)为Field子类
    4.默认定义哪些字段,那么哪些字段就会返回前端,同时也必须的输入(前端需要传递)
    5.常用的序列化器字段类型
        IntegerField  -> int
        CharField     -> str
        BooleanField  -> bool
        DateTimeField -> datetime
    6.可以在序列化器字段中指定不同的选项
        label和help_text,与模型类中的verbose_name和help_text参数一样
        IntegerField,可以使用max_value指定最大值,min_value指定最小值
        CharField,可以使用max_length指定最大长度,min_length指定最小长度

    7.定义的序列化器字段中,required默认为True,说明默认定义的字段必须得输入和输出
    8.如果在序列化器字段中,设置required=False,那么前端用户可以不传递该字段(校验时会忽略改该字段,所以不会报错)
    9.如果未定义模型类中的某个字段,那么该字段不会输入,也不会输出
    10.前端必须的输入(反序列化输入)name(必须得校验),但是不会需要输出(序列化器输出)?
        如果某个参数指定了write_only=True,那么该字段仅仅只输入(反序列化输入,做数据校验),不会输出(序列化器输出),
        默认write_only为False
    11.前端可以不用传递,但是后端需要输出?
        如果某个参数指定了read_only=True,那么该字段仅仅只输出(序列化器输出),不会输入(反序列化输入,做数据校验),
        默认read_only为False
    12.在序列化器类中定义的字段,默认allow_null=False,该字段不允许传递null空值,
        如果指定allow_null=True,那么该字段允许传递null
    13.在序列化器类中定义CharField字段,默认allow_blank=False,该字段不允许传递空字符串,
        如果指定allow_blank=True,那么该字段允许传递空字符串
    14.在序列化器类中定义的字段,可以使用default参数来指定默认值,如果指定了default参数,那么前端用户可以不用传递,
        会将default指定的值作为入参
    """
    # id = serializers.IntegerField(label='项目id', help_text='项目id', max_value=1000, min_value=1)
    # name = serializers.CharField(label='项目名称', help_text='项目名称', max_length=20, min_length=5, write_only=True)
    # name = serializers.CharField(label='项目名称', help_text='项目名称', max_length=20, min_length=5, read_only=True)

    # 1、可以在序列化器字段上使用validators指定自定义的校验规则
    # 2、validators必须得为序列类型(列表),在列表中可以添加多个校验规则
    # 3、DRF框架自带UniqueValidator校验器,必须得使用queryset指定查询集对象,用于对该字段进行校验
    # 4、UniqueValidator校验器,可以使用message指定自定义报错信息
    # 5、校验规则的执行顺序?
    #   对字段类型进行校验 -> 依次验证validators列表中的校验规则 -> 从右到左依次验证其他规则 -> 调用单字段校验方法
    #   -> 调用多字段联合校验方法validate方法
    """a.DateTimeField可以使用format参数指定格式化字符串
    b.可以任意序列化器字段上使用error_messages来自定义错误提示信息
    c.使用校验选项名(校验方法名)作为key,把具体的错误提示信息作为value"""
    update_time = serializers.DateTimeField(label='更新时间', help_text='更新时间', format='%Y年%m月%d日 %H:%M:%S',
                                            error_messages={'required': '该字段为必传参数'})

    name = serializers.CharField(label='项目名称', help_text='项目名称', max_length=20, min_length=5,
                                 error_messages={
                                     'min_length': '项目名称不能少于5位',
                                     'max_length': '项目名称不能超过20位'
                                 }, validators=[UniqueValidator(queryset=Projects.objects.all(), message='项目名称不能重复'),
                                                is_contains_keyword])

    # leader = serializers.CharField(label='项目负责人', help_text='项目负责人', allow_null=True)
    # leader = serializers.CharField(label='项目负责人', help_text='项目负责人', allow_blank=True)
    leader = serializers.CharField(label='项目负责人', help_text='项目负责人', default='阿名')
    is_execute = serializers.BooleanField()
"""
    1、如果定义了一个模型类中没有的字段,并且该字段需要输出(序列化输出)
    2、需要在create方法、update方法中的模型对象上,添加动态的属性即可
    token = serializers.CharField(read_only=True)

    3、如果定义了一个模型类中没有的字段,并且该字段需要输入(反序列化输入)
    4、需要在create方法、update方法调用之前,将该字段pop调用
    sms_code = serializers.CharField(write_only=True)

    a.DateTimeField可以使用format参数指定格式化字符串
    b.可以任意序列化器字段上使用error_messages来自定义错误提示信息
    c.使用校验选项名(校验方法名)作为key,把具体的错误提示信息作为value
"""
    update_time = serializers.DateTimeField(label='更新时间', help_text='更新时间', format='%Y年%m月%d日 %H:%M:%S',
                                            error_messages={'required': '该字段为必传参数'})

    # 一、关联字段
    # 1、可以定义PrimaryKeyRelatedField来获取关联表的外键值
    # 2、如果通过父获取从表数据,默认需要使用从表模型类名小写_set作为序列化器类中的关联字段名称
    # 3、如果在定义模型类的外键字段时,指定了realated_name参数,那么会把realated_name参数名作为序列化器类中的关联字段名称
    # 4、PrimaryKeyRelatedField字段,要么指定read_only=True,要么指定queryset参数,否则会报错
    # 5、如果指定了read_only=True,那么该字段仅序列化输出
    # 6、如果指定了queryset参数(关联表的查询集对象),用于对参数进行校验
    # 7、如果关联字段有多个值,那么必须添加many=True,一般父表获取从表数据时,关联字段需要指定
    # interfaces_set = serializers.PrimaryKeyRelatedField(label='项目所属接口id', help_text='项目所属接口id',
    #                                                     many=True, queryset=Interfaces.objects.all(), write_only=True)

    # 1、使用StringRelatedField字段,将关联字段模型类中的__str__方法的返回值作为该字段的值
    # 2、StringRelatedField字段默认添加了read_only=True,该字段仅序列化输出
    # interfaces_set = serializers.StringRelatedField(many=True)

    # 1、使用SlugRelatedField字段,将关联模型类中的某个字段,作为该字段的值
    # 2、如果指定了read_only=True,那么该字段仅序列化输出
    # 3、如果该字段需要进行反序列化输入,那么必须得指定queryset参数,同时关联字段必须有唯一约束
    # interfaces_set = serializers.SlugRelatedField(slug_field='name', many=True, queryset=Interfaces.objects.all())

    # interfaces_set = InterfaceSerilizer(label='所属接口信息', help_text='所属接口信息', read_only=True,
    #                                     many=True)

    # 1、可以在序列化器类中对单个字段进行校验
    # 2、单字段的校验方法名称,必须把validate_作为前缀,加上待校验的字段名,如:validate_待校验的字段名
    # 3、如果校验不通过,必须得返回serializers.ValidationError('具体报错信息')异常
    # 4、如果校验通过,往往需要将校验之后的值,返回
    # 5、如果该字段在定义时添加的校验规则不通过,那么是不会调用单字段的校验方法
    def validate_name(self, attr: str):
        if not attr.endswith('项目'):
            raise serializers.ValidationError('项目名称必须得以“项目”结尾')
        return attr

    # 1、可以在序列化器类中对多个字段进行联合校验
    # 2、使用固定的validate方法,会接收上面校验通过之后的字典数据
    # 3、当所有字段定义时添加的校验规则都通过,且每个字段的单字段校验方法通过的情况下,才会调用validate
    def validate(self, attrs: dict):
        if len(attrs.get('leader')) <= 4 or not attrs.get('is_execute'):
            raise serializers.ValidationError('项目负责人名称长度不能少于4位或者is_execute参数为False')
        return attrs

模型序列化器类


from rest_framework import serializers
from rest_framework.validators import UniqueValidator

from interfaces.models import Interfaces
from .models import Projects


# 1、自定义的序列化器类实际上也是Field的子类
# 2、所以自定义的序列化器类可以作为另一个序列化器中的字段来使用
class InterfaceSerilizer(serializers.Serializer):
    id = serializers.IntegerField()
    name = serializers.CharField()
    tester = serializers.CharField()


# 1、可以在类外自定义校验函数
# 2、第一个参数为待校验的值
# 3、如果校验不通过,必须得抛出serializers.ValidationError('报错信息')异常,同时可以指定具体的报错信息
# 4、需要将校验函数名放置到validators列表中
def is_contains_keyword(value):
    if '项目' not in value:
        raise serializers.ValidationError('项目名称中必须得包含“项目”关键字')


class ProjectModelSerializer(serializers.ModelSerializer):
    """
    定义模型序列化器类
    1、继承serializers.ModelSerializer类或者其子类
    2、需要在Meta内部类中指定model、fields、exclude类属性参数
    3、model指定模型类(需要生成序列化器的模型类)
    4、fields指定模型类中哪些字段需要自动生成序列化器字段
    5、会给id主键、指定了auto_now_add或者auto_now参数的DateTimeField字段,添加read_only=True,仅仅只进行序列化输出
    6、有设置unique=True的模型字段,会自动在validators列表中添加唯一约束校验<UniqueValidator
    7、有设置default=True的模型字段,会自动添加required=False
    8、有设置null=True的模型字段,会自动添加allow_null=True
    9、有设置blank=True的模型字段,会自动添加allow_blank=True
    """
    """
    修改自动生成的序列化器字段
    方式一:
        a.可以重新定义模型类中同名的字段
        b.自定义字段的优先级会更高(会覆盖自动生成的序列化器字段)
    name = serializers.CharField(label='项目名称', help_text='项目名称', max_length=20, min_length=5,
                                 error_messages={
                                     'min_length': '项目名称不能少于5位',
                                     'max_length': '项目名称不能超过20位'
                                 }, validators=[UniqueValidator(queryset=Projects.objects.all(), message='项目名称不能重复'),
                                                is_contains_keyword])

    interfaces_set = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
    token = serializers.CharField(read_only=True)
    """
    class Meta:
        model = Projects
        """
        fields指定模型类中哪些字段需要自动生成序列化器字段
            a.如果指定为"__all__",那么模型类中所有的字段都需要自动转化为序列化器字段
            b.可以传递需要转化为序列化器字段的模型字段名元组
            c.fields元祖中必须指定进行序列化或者反序列化操作的所有字段名称,指定了'__all__'和exclude除外
        fields = "__all__"
        fields = ('id', 'name', 'leader', 'interfaces_set', 'token')
        c.exclude指定模型类中哪些字段不需要转化为序列化器字段,其他的字段都需要转化
        exclude = ('create_time', 'update_time')

        方式二:
            a.如果自动生成的序列化器字段,只有少量不满足要求,可以在Meta中extra_kwargs字典进行微调
            b.将需要调整的字段作为key,把具体需要修改的内容字典作为value
        """
        extra_kwargs = {
            'leader': {
                'label': '负责人',
                'max_length': 15,
                'min_length': 2,
                # 'read_only': True
                # 'validators': []
            },
            'name': {
                'min_length': 5
            }
        }

        """可以将需要批量需要设置read_only=True参数的字段名添加到Meta中read_only_fields元组"""
        read_only_fields = ('leader', 'is_execute', 'id')

    def create(self, validated_data):
        """
        a.继承ModelSerializer之后,ModelSerializer中实现了create和update方法
        b.一般无需再次定义create和update方法
        c.如果父类提供的create和update方法不满足需要时,可以重写create和update方法,最后再调用父类的create和update方法
        :param validated_data:
        :return:
        """
        validated_data.pop('myname')
        validated_data.pop('myage')
        instance = super().create(validated_data)
        instance.token = "xxxxxxx"
        return instance

解析器&渲染器 

import json

from django.http import HttpResponse, JsonResponse
from django.views import View
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status

from .models import Projects
from .serializers import ProjectSerilizer, ProjectModelSerializer


# class ProjectsView(View):
class ProjectsView(APIView):
    """
    继承APIView父类(Django中View的子类)
    a.具备View的所有特性
    b.提供了认证、授权、限流功能
    """
    def get(self, request):
        queryset = Projects.objects.all()
        serializer = ProjectSerilizer(instance=queryset, many=True)
        # return JsonResponse(serializer.data, safe=False)

        # 在DRF中Response为HTTPResponse的子类
        # a.data参数为序列化之后的数据(一般为字典或嵌套字典的列表)
        # b.会自动根据渲染器来将数据转化为请求头中Accept需要的格式进行返回
        # c.status指定响应状态码
        # d.content_type指定响应头中的Content-Type,一般无需指定,会根据渲染器来自动设置
        return Response(serializer.data, status=status.HTTP_200_OK, content_type='ap')

    def post(self, request):
        # a.一旦继承APIView之后,request是DRF中Request对象
        # b.Request是在HttpRequest基础上做了拓展
        # c.兼容HttpRequest的所有功能
        # d.前端传递的查询字符串参数:GET、query_params
        # e.前端传递application/json、application/x-www-form-urlencoded、multipart/form-data参数
        #   可以根据请求头中Content-Type,使用统一的data属性获取
        # try:
        #     python_data = json.loads(request.body)
        # except Exception as e:
        #     return JsonResponse({'msg': '参数有误'}, status=400)

        # python_data = request.data
        serializer = ProjectModelSerializer(data=request.data)
        # if not serializer.is_valid():
        #     # return JsonResponse(serializer11.errors, status=400)
        #     return Response(serializer.errors, status=400)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data, status=status.HTTP_201_CREATED)


class ProjectsDetailView(APIView):
    def get(self, request, pk):
        try:
            project_obj = Projects.objects.get(id=pk)
        except Exception as e:
            return JsonResponse({'msg': '参数有误'}, status=400)

        serializer = ProjectSerilizer(instance=project_obj)
        return Response(serializer.data, status=status.HTTP_200_OK)

    def get_object(self, pk):
        try:
            project_obj = Projects.objects.get(id=pk)
            return project_obj
        except Exception as e:
            return Response({'msg': '参数有误'}, status=400)

    def put(self, request, pk):
        # try:
        #     project_obj = Projects.objects.get(id=pk)
        # except Exception as e:
        #     return JsonResponse({'msg': '参数有误'}, status=400)
        project_obj = self.get_object(pk)

        serializer = ProjectSerilizer(instance=project_obj, data=request.data)

        # if not serializer.is_valid():
        #     return JsonResponse(serializer.errors, status=400)
        # 在序列化器对象调用is_valid(raise_exception=True),校验失败时,会抛出异常,DRF框架会自动处理异常
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    def delete(self, request, pk):
        try:
            project_obj = Projects.objects.get(id=pk)
        except Exception as e:
            return JsonResponse({'msg': '参数有误'}, status=400)

        # 3、执行删除
        project_obj.delete()

        # return JsonResponse({'msg': '删除成功'}, status=204)
        return Response(status=status.HTTP_204_NO_CONTENT)

GenericAPIView

排序 过滤 分页

from django.http import JsonResponse
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.generics import GenericAPIView
from rest_framework import status
from rest_framework import filters

from .models import Projects
from .serializers import ProjectSerilizer, ProjectModelSerializer


# class ProjectsView(View):
# class ProjectsView(APIView):
class ProjectsView(GenericAPIView):
    """
    继承GenericAPIView父类(GenericAPIView子类)
    a.具备View的所有特性
    b.具备了APIView中的认证、授权、限流功能
    c.还支持对于获取列表数据接口的功能:搜索、排序、分页
    """
    # 一旦继承GenericAPIView之后,往往需要指定queryset、serializer_class类属性
    # queryset指定当前类视图的实例方法需要使用的查询集对象
    queryset = Projects.objects.all()
    # serializer_class指定当前类视图的实例方法需要使用的序列化器类
    serializer_class = ProjectSerilizer

    # filter_backends在继承了GenericAPIView的类视图中指定使用的过滤引擎类(搜索、排序)
    # 优先级高于全局
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    # 2、在继承了GenericAPIView的类视图中,search_fields类属性指定模型类中需要进行搜索过滤的字段名
    # 3、使用icontains查询类型作为过滤类型
    # 4、可以在字段名称前添加相应符号,指定查询类型
    #  '^': 'istartswith',
    #  '=': 'iexact',
    #  '$': 'iregex',
    search_fields = ['^name', '=leader', 'id']

    # ordering_fields类属性指定模型类中允许前端进行排序的字段名称
    # 前端默认可以使用ordering作为排序功能查询字符串参数名称,默认改字段的升序
    # 如果在字段名称前添加“-”,代表改字段降序
    # 如果指定多个排序字段,使用英文逗号进行分割
    ordering_fields = ['id', 'name', 'leader']

    def get(self, request: Request):
        # name_param = request.query_params.get('name')
        # if name_param:
        #     queryset = Projects.objects.filter(name__exact=name_param)
        # else:
        #     queryset = Projects.objects.all()

        # queryset = Projects.objects.all()

        # 1、在实例方法中,往往使用get_queryset()方法获取查询集对象
        # 2、一般不会指定调用queryset类属性,原因:为了提供让用户重写get_queryset()
        # 3、如果未重写get_queryset()方法,那么必须得指定queryset类属性
        # queryset = self.queryset
        # queryset = self.get_queryset()

        # filter_queryset对查询对象进行过滤操作
        queryset = self.filter_queryset(self.get_queryset())
        # serializer = ProjectSerilizer(instance=queryset, many=True)

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(instance=page, many=True)
            return self.get_paginated_response(serializer.data)
        # 1、在实例方法中,往往使用get_serializer()方法获取序列化器类
        # 2、一般不会直接调用serializer_class类属性,原因:为了让用户重写get_serializer_class()
        # 3、如果未重写get_serializer_class()方法,那么必须得指定serializer_class类属性
        # serializer = self.serializer_class(instance=queryset, many=True)
        serializer = self.get_serializer(instance=queryset, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)

    def post(self, request):
        # serializer = ProjectModelSerializer(data=request.data)
        # serializer = self.serializer_class(data=request.data)
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data, status=status.HTTP_201_CREATED)


# class ProjectsDetailView(APIView):
class ProjectsDetailView(GenericAPIView):
    queryset = Projects.objects.all()
    serializer_class = ProjectSerilizer

    # a.lookup_url_kwarg默认为None
    # b.如果lookup_url_kwarg为None,那么lookup_url_kwarg与lookup_field值相同(‘pk’)
    # c.lookup_url_kwarg指定url路由条目中外键的路径参数名称,一般无需指定
    # lookup_url_kwarg = 'kk'

    # def get_object(self, pk):
    #     try:
    #         # project_obj = Projects.objects.get(id=pk)
    #         project_obj = self.get_queryset().get(id=pk)
    #         return project_obj
    #     except Exception as e:
    #         return Response({'msg': '参数有误'}, status=400)

    def get(self, request, **kwargs):
        # project_obj = self.get_object(pk)
        # get_object可以获取模型对象,无需传递外键值
        project_obj = self.get_object()

        # serializer = ProjectSerilizer(instance=project_obj)
        # serializer = self.serializer_class(instance=project_obj)
        serializer = self.get_serializer(instance=project_obj)
        return Response(serializer.data, status=status.HTTP_200_OK)

    def put(self, request, **kwargs):
        project_obj = self.get_object()

        serializer = self.get_serializer(instance=project_obj, data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    def delete(self, request, pk):
        # try:
        #     project_obj = Projects.objects.get(id=pk)
        # except Exception as e:
        #     return JsonResponse({'msg': '参数有误'}, status=400)
        project_obj = self.get_object()
        project_obj.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

setting也要改

"""
Django settings for dev07 project.

Generated by 'django-admin startproject' using Django 3.2.

For more information on this file, see
https://docs.djangoproject.com/en/3.2/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.2/ref/settings/
"""

from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-oay(@i%k!r6lp*0s#*s=9-&%h7_37$5vdl3#x_nog=zksp4us4'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',

    'projects',
    # 'projects.apps.ProjectsConfig',
    'interfaces',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'dev07.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'dev07.wsgi.application'

# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases

# 指定在全局配置文件settings.py中的DATABASES字典里配置需要连接的数据库信息
DATABASES = {
    # 指定数据库的别名/标签
    # 指定的是django默认使用的数据库
    'default': {
        # 指定当前使用的数据库引擎
        # django.db.backends.mysql、oracle、sqlite3
        'ENGINE': 'django.db.backends.sqlite3',
        # 'ENGINE': 'django.db.backends.mysql',
        # 指定数据库名称,如果使用的是sqlite3,需要指定sqlite3文件的绝对路径
        'NAME': BASE_DIR / 'db.sqlite3',
        # 'NAME': 'mydb',
        # 'USER': 'root',
        # 'PASSWORD': '123456',
        # 'PORT': 3306,
        # 'HOST': '127.0.0.1'
    }

}

# Password validation
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/

LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_L10N = True

USE_TZ = True

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/

STATIC_URL = '/static/'

# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

# DRF中的解析器(类)
# 1、可以根据请求头中的Content-Type来自动解析参数,使用统一的data属性来获取即可
# 2、默认JSONParser、FormParser、MultiPartParser三个解析器类
# 3、可以在全局配置文件(settings.py)中修改DRF全局参数,把REST_FRAMEWORK作为名称
REST_FRAMEWORK = {
    # 'DEFAULT_PARSER_CLASSES': [
    #     'rest_framework.parsers.JSONParser',
    #     'rest_framework.parsers.FormParser',
    #     'rest_framework.parsers.MultiPartParser'
    # ],

    # DRF中的渲染器(类)
    # 1、可以根据请求头中的Accept参数来自动渲染前端需要的数据格式
    # 2、默认的渲染器为JSONRenderer、BrowsableAPIRenderer
    # 3、如果前端请求头未指定Accept参数或者指定为application/json,那么会自动返回json格式的数据
    # 4、如果前端请求头指定Accept参数为text/html,那么默认会返回可浏览的api页面(api进行管理)
    # 5、可以在DEFAULT_RENDERER_CLASSES中指定需要使用的渲染器
    # 'DEFAULT_RENDERER_CLASSES': [
    #     'rest_framework.renderers.JSONRenderer',
    #     'rest_framework.renderers.BrowsableAPIRenderer',
    # ],

    # 1、在全局DEFAULT_FILTER_BACKENDS指定使用的过滤引擎类(SearchFilter为搜索引擎类)
    'DEFAULT_FILTER_BACKENDS': ['rest_framework.filters.SearchFilter',
                                'rest_framework.filters.OrderingFilter'],
    # 可以在全局使用SEARCH_PARAM修改前端过滤查询字符串参数名称(默认为search)
    # 'SEARCH_PARAM': 'se',

    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 3,
}

如何选择视图

1.ModelViewSet是一个最完整的视图集类
    a.提供了获取列表数据接口、获取详情数据接口、创建数据接口、更新数据接口、删除数据的接口
    b.如果需要多某个模型进行增删改查操作,才会选择ModelViewSet
2.ReadOnlyModelViewSet
    a.仅仅只对某个模型进行数据读取操作(取列表数据接口、获取详情数据接口),一般会选择

自动生成路由条目

url改动
from django.urls import path, include
from rest_framework import routers

# from projects.views import get_project, create_project, put_project, delete_project
# from projects import views
from . import views


# 1、可以使用路由器对象,为视图集类自动生成路由条目
# 2、路由器对象默认只为通用action(create、list、retrieve、update、destroy)生成路由条目,自定义的action不会生成路由条目
# 3、创建SimpleRouter路由对象
router = routers.SimpleRouter()
# DefaultRouter与SimpleRouter功能类似,仅有的区别为:DefaultRouter会自动生成一个根路由(显示获取数据的入口)
# router = routers.DefaultRouter()
# 4、使用路由器对象调用register方法进行注册
# 5、prefix指定路由前缀
# 6、viewset指定视图集类,不可调用as_view
router.register(r'projects', views.ProjectViewSet)

# 方式二:
# router.urls为列表
urlpatterns += router.urls
视图类改动
 # 1、如果需要使用路由器机制自动生成路由条目,那么就必须得使用action装饰器
    # 2、methods指定需要使用的请求方法,如果不指定,默认为GET
    # 3、detail指定是否为详情接口,是否需要传递当前模型的pk值
    #   如果需要传递当前模型的pk值,那么detail=True,否则detail=False
    # 4、url_path指定url路径,默认为action方法名称
    # 5、url_name指定url路由条目名称后缀,默认为action方法名称
    # @action(methods=['GET'], detail=False, url_path='xxx', url_name='yyyy')
    @action(methods=['GET'], detail=False)
    def names(self, request, *args, **kwargs):
        # queryset = self.get_queryset()
        # queryset = self.filter_queryset(queryset)
        # names_list = []
        # for project in queryset:
        #     names_list.append({
        #         'id': project.id,
        #         'name': project.name
        #     })
        # serializer = self.get_serializer(queryset, many=True)
        #
        # # return Response(names_list, status=200)
        # return Response(serializer.data, status=200)
        return super().list(request, *args, **kwargs)

    @action(detail=True)
    def interfaces(self, request, *args, **kwargs):
        project = self.get_object()
        interfaces_qs = project.interfaces_set.all()
        interfaces_data = [{'id': interface.id, 'name': interface.name} for interface in interfaces_qs]
        return Response(interfaces_data, status=200)

数据库

ORM框架

数据库:需要提前手动创建数据库
数据表:与ORM框架中的模型类一一对应
字段:模型类中的类属性(Field子类)
记录:类似于模型类的多个实例

设置库类型

创建迁移文件

projects为创建的所在项目
python3 manage.py makemigrations projects   

迁移数据库 

python3 manage.py migrate projects    


class Projects(models.Model):
    # 类属性,也就是表字段
    # 姓名,字符串,最长256字节,限制长度50,unique设置值唯一
    name = models.CharField(max_length=50, unique=True, verbose_name="姓名", help_text="姓名")
    # 年龄,整型
    age = models.IntegerField(verbose_name="年龄", help_text="年龄")
    # 性别,布尔值,默认为True
    gender = models.BooleanField(default=True, verbose_name="性别", help_text="性别")
    # 备注,长文本,null前端入参可为null,blank可不填
    console = models.TextField(null=True, blank=True, default="没啥可备注的", verbose_name="备注", help_text="备注")
    # 创建时间,创建记录时,自动将当前时间作为该字段值。
    createTime = models.DateTimeField(auto_now_add=True, verbose_name="创建时间", help_text="创建时间")
    # 更新时间,更新记录时,自动将当前时间作为该字段值。
    updateTime = models.DateTimeField(auto_now=True, verbose_name="更新时间", help_text="更新时间")

    # 在模型类内创建一个Meta内部类,用于修改数据库的元数据信息
    class Meta:
        # 指定创建的数据表名称
        db_table = "tb_project"

ADUS

父表和从表定义

QuerySet查询集对象

其特性

1)支持链式调用:可以在查询集上多次调用filter、exclude方法
2)惰性查询:仅仅在使用数据时才会执行sql语句,为了提升数据库读写性能
会执行sql语句的场景:len()、.count()、通过索引取值、print、for
qs = Projects.objects.values('id').annotate(Count('interfaces'))


QuerySet查询集对象和列表类似,列表嵌套字典

可以用for遍历,查询出的是模型对象,可以用.属性提取

econdData = Projects.objects.filter(name="巴拉巴拉")

# QuerySet查询集第一个
secondData.first()
secondData[0]

# QuerySet查询集最后一个
secondData.last()

# QuerySet查询集的数量/长度
secondData.count()
len(secondData)

# QuerySet查询集是否为空,返回True或Fasle
secondData.exists()

manage对象

模型类.objects返回manager对象

Projects.objects

filter查询类型


# 大于
Projects.objects.filter(id__gt=1)

# 大于等于
Projects.objects.filter(id__gte=1)

# 小于
Projects.objects.filter(id__lt=1)

# 小于等于
Projects.objects.filter(id__lte=1)

# 指定字段模糊查询。
Projects.objects.filter(name__contains="yue")

# 指定字段模糊查询,忽略大小写。
Projects.objects.filter(name__icontains="yue")

# 查询字段值在指定区域内,id是123的都符合
Projects.objects.filter(id__in=[1, 2, 3])

# 以什么开头。
Projects.objects.filter(name__startswith="yu")

# 以什么开头,忽略大小写。
Projects.objects.filter(name__istartswith="Yu")

# 以什么结尾。
Projects.objects.filter(name__endswith="yu")

# 以什么结尾,忽略大小写。
Projects.objects.filter(name__iendswith="Yu")

正常增加

父表中创建从表数据
# 创建从表数据
# 外键对应的父表如何传递?

""" 方式一:
 1)先获取父表模型对象
 2)将获取的父表模型对象以外键字段名作为参数来传递 """
project_obj = Projects.objects.get(name='在线图书项目')
interface_obj = Interfaces.objects.create(name='在线图书项目-登录接口', tester='珍惜',projects=project_obj)


""" 方式二:
 1)先获取父表模型对象,进而获取父表数据的id值
 2)将父表数据的主键id值以外键名_id作为参数来传递"""
interface_obj = Interfaces.objects.create(name='在线图书项目-注册接口', tester='珍惜',projects_id=project_obj.id)


"""方式一:一条数据"""
project_obj = Projects.objects.get(id=1)
project_obj.delete()

"""方式二:多条数据"""
Projects.objects.filter(name__contains='2').delete()

"""
方式一:一条数据
1)必须调用save方法才会执行sql语句,并且默认进行完整更新
2)可以在save方法中设置update_fields参数(序列类型),指定需要更新的字段名称(字符串)
"""

project_obj = Projects.objects.get(id=1)
project_obj.name = '在线图书项目(一期)'
project_obj.leader = '不语'
project_obj.save(update_fields=["name","leader"])


"""
方式一:多条数据
在QuerySet对象.update(字段名称='字段值',字段名称='字段值'),返回修改成功的值,无需调用save方法
"""
Projects.objects.filter(name__contains='2').update(leader='珍惜')

正常查询
class ProjectView(View):
    def get(self, request, id):

        """ 第一种,只能查单条数据,结果不存在或超出1个会报错,返回的是模型对象。"""
        firstData = Projects.objects.get(name="巴拉巴拉")

        """ 第二种,结果不存在不报错,返回的是QuerySet查询集对象。"""
        secondData = Projects.objects.filter(name="巴拉巴拉")

        """ QuerySet查询集第一个 """
        secondData.first()
        secondData[0]

        """ QuerySet查询集最后一个 """
        secondData.last()

        """ QuerySet查询集的数量 """
        secondData.count()


        """ 查所有数据,返回的是QuerySet查询集对象。"""
        allData = Projects.objects.all()
主表参数为条件获取从表数据
""" 目的:查主表中leader为多喝热水的,在从表中接口都是什么。"""
# 以从表入手!从表查询集(外键名__代表主表的引用,leader为主表字段的过滤)。
Interfaces.objects.filter(projects__leader="多喝热水")


""" 目的:查主表projects中leader包含漂亮的,在从表中有多少个接口。"""
# 以从表入手!从表查询集(projects__是父表的引用,leader__contains="大漂亮"是父表的字段模糊筛选)
Interfaces.objects.filter(projects__leader__contains="漂亮")


# 以主表入手!主表查询集第一个(leader__contains="漂亮")[0],从表模型类名_set.all(),返回的是查询集
Projects.objects.filter(leader__contains="漂亮")[0].interfaces_set.all()


从表参数为条件获取主表数据 
""" 目的:查从表中接口名包含登录的接口,在主表中哪个项目里."""
#从表查询集(name__contains="登录"),第一个模型对象.first()的.从表的外键字段projects
Interfaces.objects.filter(name__contains="登录").first().projects

Projects.objects.filter(interfaces__name__contains='登录')
分组查询
a.可以使用QuerySet对象.values('父表主键id').annotate(聚合函数('从表模型类名小写'))
b.会自动连接两张表,然后使用外键字段作为分组条件
聚合查询
可以使用QuerySet对象.aggregate(聚合函数('字段名'))方法,返回字典数据
b.返回的字典数据中key为字段名__聚合函数名小写
c.可以使用关键字参数形式,那么返回的字典数据中key为关键字参数名
qs = Projects.objects.filter(name__contains='2').aggregate(Count('id'))

抽出来的表公用字段

外键

class Interfaces(BaseModel):
    name = models.CharField(verbose_name='接口名称', help_text='接口名称', max_length=20, unique=True)
    tester = models.CharField(verbose_name='测试人员', help_text='测试人员', max_length=10)

    """ 
    外键字段在表中会自动追加一个_id

    a.如果需要创建一对多的外键,那么会在“多”的那一个模型类中定义外键字段
    b.如果创建的是一对多的关系,使用ForeignKey
    c.如果创建的是一对一的关系,可以在任何一个模型类使用OneToOneField
    d.如果创建的是多对多的关系,可以在任何一个模型类使用ManyToManyField 

    e.ForeignKey第一个参数为必传参数,指定需要关联的父表模型类
      方式一:直接使用父表模型类的引用
      方式二:可以使用'子应用名称.父表模型类名'(推荐)

    f.ForeignKey需要使用on_delete指定级联删除策略
       CASCADE: 当父表数据删除时,相对应的从表数据会被自动删除
       SET_NULL:当父表数据删除时,相对应的从表数据会被自动设置为null值
       PROTECT:当父表数据删除时,如果有相对应的从表数据会抛出异常
       SET_DEFAULT: 当父表数据删除时,相对应的从表数据会被自动设置为默认值,还需要额外指定default=True
"""

    projects = models.ForeignKey('projects.Projects', on_delete=models.CASCADE,
                                 verbose_name='所属项目', help_text='所属项目')

    class Meta:
        # db_table指定创建的数据表名称
        db_table = 'tb_interfaces'
        # 为当前数据表设置中文描述信息
        verbose_name = '接口表'
        verbose_name_plural = '接口表'
        ordering = ['id']

    def __str__(self):
        return f"Interfaces({self.name})"

from django.db import models
from utils.base_model import BaseModel


class Animal(models.Model):
    """
    1)一般在子应用models.py中定义模型类(相当于数据库中的一张表)
    2)必须继承Model或者Model的子类
    3)在模型类中定义类属性(必须得为Field子类)相当于数据表中字段
    4)CharField ---> varchar
       IntegerField ---> integer
       BooleanField ---> bool
    5)在migrations里,存放迁移脚本:
        python manage.py makemigrations 子应用名(如果不指定子应用名,会把所有子应用生成迁移脚本)
    6)查询迁移脚本生成的SQL语句:python manage.py sqlmigrate 子应用名 迁移脚本名(无需加.py)
    7)生成的数据表名称默认为:子应用名_模型类名小写
    8)默认会自动创建一个名为id的自增主键
    """
    # varchar
    name = models.CharField(max_length=50)
    age = models.IntegerField()
    gender = models.BooleanField()


class Projects(BaseModel):
    # 在一个模型类中仅仅只能为一个字段指定primary_key=True
    # 一旦在模型类中的某个字段上指定了primary_key=True,那么ORM框架就不会自动创建名称为id的主键
    # a.CharField类型必须指定max_length参数(改字段的最大字节数)
    # b.如果需要给一个字段添加唯一约束,unique=True(默认为False)
    name = models.CharField(max_length=20, verbose_name='项目名称', help_text='项目名称', unique=True)
    leader = models.CharField(max_length=10, verbose_name='项目负责人', help_text='项目负责人')

    # c.使用default指定默认值(如果指定默认值后,在创建记录时,改字段传递,会使用默认值)
    is_execute = models.BooleanField(verbose_name='是否启动项目', help_text='是否启动项目', default=True)

    # d.null=True指定前端创建数据时,可以指定该字段为null,默认为null=False,DRF进行反序列化器输入时才有效
    # e.blank=True指定前端创建数据时,可以指定该字段为空字符串,默认为blank=False,DRF进行反序列化器输入时才有效
    desc = models.TextField(verbose_name='项目描述信息', help_text='项目描述信息', null=True, blank=True, default='')

    # h.可以在任意一个模型类中创建Meta内部类,用于修改数据库的元数据信息
    class Meta:
        # i.db_table指定创建的数据表名称
        db_table = 'tb_projects'
        # 为当前数据表设置中文描述信息
        verbose_name = '项目表'
        verbose_name_plural = '项目表'
        # 排序
        ordering = ['id']

    def __str__(self):
        return f"Projects({self.name})"

逻辑关系

""" 方式一:在同一个filter方法内部,添加多个关键字参数,那么每个条件为“与”的关系"""
Projects.objects.filter(name__contains='2', leader='keyou')


""" 方式二:可以多次调用filter方法,那么filter方法的条件为“与”的关系,QuerySet链式调用特性"""
Projects.objects.filter(name__contains='2').filter(leader='keyou')


""" 方式三:可以使用Q方法,& 为与关系"""
Projects.objects.filter(Q(name__contains='2') & Q(leader='keyou'))

"""使用Q查询,实现逻辑关系,多个Q对象之间使用“|”,为“或”关系"""
Projects.objects.filter(Q(name__contains='2') | Q(leader='多喝热水'))

排序

"""使用QuerySet对象(manager对象).order_by('字段名1', '字段名2', '-字段名3')
默认为ASC升序,可以在字段名称前添加“-”,那么为DESC降序"""

Projects.objects.filter(Q(name__contains='2') | Q(leader='多喝热水')).order_by('-name', 'leader')

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秦朝胖子得加钱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值