41.Django_02

0.第一次使用

写一个简单的登入注册功能。
文件
链接:https://pan.baidu.com/s/1ILTL5iPHQp1rR1KfR_i7-A 
提取码:aej1 

1.静态文件配置

静态文件:前端写好的能直接使用的文件。
1. 网站写好的js文件
2. 网站需要用到的css文件
3. 网站用带的图片文件
4. 第三方前端框架
5. 其他可以拿来就直接使用的文件。
1.1文件位置
html文件默认都放在templates文件下。
站所有的静态文件都放在staric文件夹下,
需要自己手动创建文件static文件(别人都使用这个名称,就约定俗成了)。

对static文件夹进一步的划分处理,目的就是解耦合。
static
  js
  css
  img
  其他第三方文件

2.简单的登入页面

2.1创建项目
新建项目 --> Django项目 --> 创建
mysize文件夹
|--mysize文件下
|--__init__.py
|--settings.py   配置文件
|--urls.py       路由与视图关系文件
|--wsgi.ps
|--templates     存放html文件
|--static        手动创建,存放静态文件
2.2建立关系
1.创建app01应用
一个程序必须有一个应用。
在pycharm底部打开终端:
输入:
python manage.py startapp app02
2.注册app引用
创建的app必须要注册,在settings配置文件中添加注册。
INSTALLED_APPS = [
    'django.contrib.admin',
 ····························
    'app02'  # 添加app应用名称
]
3.分析需求
在地址栏输入127.0.0.1/login/
返回一个网址
4.在urls.py
在urls.py中建立关系。 
from django.conf.urls import url
from django.contrib import admin
from app01 import views     # 添加创建的app应用

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    # 登入功能的路由与视图关系
    url(r'^login/', views.login)
]
5.写功能
打开app02应用的views.py写功能。
# 所有自定义的函数都需要写request形参。
def login(request):
    # 返回一个html页面
    return render(request, 'login.html')
6.返回的网页
网页的地址在templates文件中。

将样式文件bootstrap-3.3.7-dist复制到static文件下。

templates下的创建login.html文件。
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
        <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
    </head>
    <body>
        <h1 class="text-center">登入</h1>
    </body>
    </html>
如果运行出错找不文件路径,在settings中将原本的'DIRS'的配置替换。将template的路径添加到环境变量中的设置更改一个。
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        ···
7.路径开发
在浏览器输入url能够看到对应的资源,是因为后端开设了该资源的接口,
如果访问不到资源,说名后端没有开始该资源的接口。
settings.py文件下:
STATIC_URL = '/static/'  相当于令牌,访问的路径必须以这个令牌的名称开始。
令牌名字更改了所有相关的路径都需要手动改。
/xxx/ 
os.path.join(BASE_DIR, 'xxx')
文件中的名称也需要一起改:
/xxx/bootstrap-3.3.7-dist/js/bootstrap.min.js
8.静态文件配置
settings.py文件下的STATIC_URL = '/static/' 下方, 静态文件路径配置。
STATIC_URL = '/static/' 
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
os.path.join(BASE_DIR, 'static1')
]
取值列表从上玩下依次查找,都没有则报错。
/static/bootstrap-3.3.7-dist/js/bootstrap.min.js
建立一个static1的文件件,再新建一个文件1.txt写 hello word!
访问
http://127.0.0.1:8000/static/1.txt
验证取值列表从上玩下依次查找的。
在写django项目的时候可能会出现后端代码修改了前端页面没有变化:
1.在用一个端口开了好几个django项目,一直运行的还是第一个gjango项目
2.流浪器缓存的问题
	settins (检测 - f1)
		netword
		 勾选disable xxxxx
		 刷新
3.就是你代码有问题。

在这里插入图片描述

10动态修改
令牌名字更改了所有相关的路径都自动改。
    {% load static %}
    <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
    <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js'%}"></script>
11.访问

在这里插入图片描述

3.request对象方法

request对象:请求相关的数据对象,里面有很多简易的方法。
3.1例
修改login.html文件内容。
访问下127.0.0.1/login
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    {% load static %}
    <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
    <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js'%}"></script>
</head>

<body>
    <h1 class="text-center">登入</h1>
    <div class="container">
        <div class="row">
            <div class="col-md-8 col-md-offset-2">
                <form action="">
                    <p>username: <input type="text" name="username" class="form-control"></p>
                    <p>password: <input type="text" name="password" class="form-control"></p>
                    <p>hobby
                        <input type="checkbox" name="hobby" value="1"> 1
                        <input type="checkbox" name="hobby" value="2"> 2
                    </p>
                    <input type="submit" class="btn btn-success btn-block">
                </form>
            </div>
        </div>
    </div>
</body>
</html>

在这里插入图片描述

1.查看请求方式
request.method  返回请求方式,返回值为大写的字符串(GET/POST)。
修改app01下views.py文件。
def login(request):
    print(request.method)
    return render(request, 'login.html')
GET
2.from表单提交数据
from表单默认是get方式提交。
get请求携带数据有大小的限制,大概4kb左右。
而post没有限制。

action的三种情况:
1.不写,默认朝当前所有url提交数据。
2.全写,指定详细位置。
3.指定后缀/login/
修改app01下views.py文件。
from django.shortcuts import render

def login(request): 
    print(request.method)   # 打印当前提交方式,默认为get。
    return render(request, 'login.html')
在表单写数据
username:kid
password:123
勾选12
点登入

在这里插入图片描述

[11/Aug/2021 16:46:06] "GET /login/ HTTP/1.1" 200 998
GET    # 第一个gat 是请求

[11/Aug/2021 16:46:17] "GET /login/?username=kid&password=123&hobby=1&hobby=2 HTTP/1.1" 200 998
GET    # 第二个是form表单的提交方式
修改from表单的提交方式为post,再次访问,提交数据。
 <form action="" method="post">
[11/Aug/2021 17:06:27] "GET /login/ HTTP/1.1" 200 1012
GET  # 第一个gat 是请求

[11/Aug/2021 17:06:36] "POST /login/ HTTP/1.1" 200 1012
POST # 第二个是form表单的提交方式
3.获取post请求数据
修改form提交方式。
<form action="" method="post">

在使用django提交post请求的时候需要在配置中注释掉,否则报错 403.
settings中
MIDDLEWARE =[
···
 # 'django.middleware.csrf.CsrfViewMiddleware'
···
 ]
request.POST:获取用户提交的post请求数据(不包含文件),是一个字典的形式。
request.POST.get('xxx')      通过get取值,如果有多个值,取最后一个值。
request.POST.getlist('hobby'):如果有多个值,取多个值为列表形式。
from django.shortcuts import render


def login(request):
    if request.method == 'POST':
        print(request.POST)
        print(request.POST.get('username'))
        print(request.POST.get('password'))
        print(request.POST.get('hobby'))
        print(request.POST.getlist('hobby'))
    return render(request, 'login.html')

<QueryDict: {'username': ['kid'], 'password': ['123'], 'hobby': ['1', '2']}>
kid
123
2
['1', '2']
4.获取get请求数据
request.GET:获取用户提交的post请求数据(不包含文件),是一个字典的形式。
request.GET.get('xxx')      通过get取值,如果有多个值,取最后一个值。
request.GET.getlist('hobby'):如果有多个值,取多个值为列表形式。
<form action="" method="get">
from django.shortcuts import render


def login(request):
    """
     get请求于post请求因该有不同的处理机制
    :param request:请求相关的数据对象,里面有很多简易的方法
    """
    if request.method == 'POST':
        print(request.POST)
        print(request.POST.get('username'))
        print(request.POST.get('password'))
        print(request.POST.get('hobby'))
        print(request.POST.getlist('hobby'))

    # 第一次get请求是没有值的,点击按钮提交from表单,填了则有值否则就空字符串。
    if len(request.GET) != 0:    

        print(request.GET)
        print(request.GET.get('username'))
        print(request.GET.get('password'))
        print(request.GET.get('hobby'))
        print(request.GET.getlist('hobby'))

    return render(request, 'login.html')
有值和POST的情况一样,提交空表的情况:
<QueryDict: {'username': [''], 'password': ['']}>
None
None
None
[]

4.pycharm连接数据库

pycharm中三个位置查找数据库:
1.右侧上面  darabase。
2.左侧下面  database。
3.配置里面的plugins插件搜索darabase安装。
pycharm可以充当很多款数据库软件的客户端。
第一个选择数据库后记得下载驱动。
1.选择数据库

image-20210811181907356

2.安装驱动
点DOwnload

在这里插入图片描述

3.设置通信信息
填好了先点Test ** 测试先是否能成功连通,
连接的库必须是提前建立好的。

在这里插入图片描述

image-20210811182447807]

4.创建库
使用Navicat创建
https://blog.csdn.net/qq_46137324/article/details/119303398
命令行创建
https://blog.csdn.net/qq_46137324/article/details/119150449
5.测试成功点ok

在这里插入图片描述

6.查看数据库

在这里插入图片描述

5.django连接数据库

django 自带一个 sqkite3数据库。
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}
将默认的库修改为MySQL。
第一步:settings配置文件修改:
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'db1',
        'USER': 'root',
        'PASSWORD': 123,
        'HOST': '127.0.0.1',
        'POST': 3306,
        'CHARSET': 'utf8' # 不能使用-
    }
}
第二步:代码声明
django 默认是使用mysqldb模块连接MySQL,但该模块的兼容性不好,需要手动改为pymysql模块链接。
替换模块,使用pymysql。
安装 pip3 install pymysql
在app01应用下有个__init__,或者任何应用名下书写以下代码
import pymysql
pymysql.install_as_MySQLdb()

6.Django ORM

作用能够让一个不会用sql语句的小白也能通过python面向对象的代码简单快捷的操作数据路。
不足之处:封装程度太高,有时候效率低,需要自己写sql语句。

ORM对象关系映射:
   --->  
对象  ---> 记录
对象属性  ---> 记录中的某个字段
6.1创建表
1.第一步models.py中创建表
app应用下面的models.py创建表
models.py中书写一个类就是创建一个表。
类必须继承models.Model才能创建。
# 创建表
class user(models.Model):         
    # 添加字段 
    # verbose_name 参数是字段的解释信息
    id = models.AutoField(primary_key=True, verbose_name="主键")   
    username = models.CharField(max_length=32,verbose_name="密码") 
    password = models.IntegerField()
id = models.AutoField(primary_key=True, verbose_name="主键")
等同于
id int primary_key auto_increment 

username = models.CharField(max_length=32, verbose_name="用户名")
等同于
username = models.CharField(max_length=32,verbose_name="密码")
varchar字段必须指定max_length参数不指定就会直接报错。

password = models.IntegerField()
等同于
password int
2.第二步:数据库迁移命令
需要迁移数据库才能生效

1. python manage.py makemigrations   

(简写,运行task的 run manage task,直接输入makemigrations)
将操作记录记录在migrations文件夹中migrations文件夹中默认只有一个__init__.py,
执行命令后,会多一个文件,会记录操作。


2. python manage.py migrate 
将操作真正的同步到数据库中。

***** 只要修改了models.py中的更数据库相关的代码就必须重新执行上面的代码。*****
无法迁移,检查app是否注册。
INSTALLED_APPS = [
···
    'app02.apps.App01Config',
]

在这里插入图片描述

orm创建的表会自动加上一个前缀,应为一个django项目有很多的应用,多个应用之间可能出现表名的冲突,加上前缀来避免冲突。
6.2自动添加id字段
每个表中都需要有一个主键字段,并在一般情况下都叫id字段,
在没有定义id字段时,orm会自动创建一个名为id的主键字段。
class Author(models.Model):
    username = models.CharField(max_length=32)
    password = models.IntegerField()
后续在创建模型表的售后如果主键字段名没有而外的叫法,那么主键字段可以省略不写。
6.3字段操作
1.字段增加
lv = models.IntegerField()
数据库迁移命令xxx
You are trying to add a non-nullable field 'age' to user without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
 2) Quit, and let me add a default in models.py
Select an option:
添加空的键需要值,1提供值2退出
1  1  回车
2 exit 回车
E:\备份\test\djangoProject1>python manage.py makemigrations
You are trying to add a non-nullable field 'lv' to user without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
 2) Quit, and let me add a default in models.py
Select an option: 1
Please enter the default value now, as valid Python
The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now
Type 'exit' to exit this prompt
>>> 6
Migrations for 'app02':
  app02\migrations\0002_user_lv.py
    - Add field lv to user

E:\备份\test\djangoProject1>python manage.py migrate
System check identified some issues:

WARNINGS:
?: (mysql.W002) MySQL Strict Mode is not set for database connection 'default'
        HINT: MySQL's Strict Mode fixes many data integrity problems in MySQL, such as data truncation upon insertion, by escalating warnings into errors. It is strongly recommended you activate it. See: https://docs.djangoproject.c
om/en/1.11/ref/databases/#mysql-sql-mode
Operations to perform:
  Apply all migrations: admin, app02, auth, contenttypes, sessions
Running migrations:
  Applying app02.0002_user_lv... OK
第一钟情况,在终端输入值 1 添加的字段的值都为1
lv = models.IntegerField(validators='1')
第二种情况 设置null为空,添加的字段全部为空
info = models.CharField(max_length=32, verbose_name='简历', null=True)
第三情况,这种默认值,添加的字段全部为默认的值
hobby = models.CharField(max_length=32, verbose_name='爱好', default='study')
修改后需要一定要执行
python manage.py makemigrtions 
python manage.pu migrate
2.字段的更改
直接修改代码
password = models.CharField(max_length=30, validators='密码')
迁移命令xxx
3.字段的删除
将需要删除的字段注释掉
# lv = models.IntegerField()
# info = models.CharField(max_length=32, verbose_name='简历', null=True)
    python manage.py makemigrtions 
    python manage.pu migrate
直接注释的后对应的数据会全部丢失。
不要轻易的操作删除字段。操作迁移命令的时候一定要检查自己写的代码。
4.字段的查肉眼看
以后在补上、
6.4数据的增删改查
先在Navicat为app02_user添加数据:
id   username   password
1     kid        123
2     qz         456
models.user.objects.filter(查询条件).first()
models.User.objects.create(username=username, password=password) 添加数据
models.User.objects.filter(id=edit_id).update(更改的字段=,更改的字段=) 
models.User.objects.filter(删除的条件).delete()

7.简单完善项目

结合之前的登入案例从数据库中获取值完成登入功能。
7.1登入功能
读取数据库中的值,与提交的数据进行比对。
<form action="" method="post">
from django.shortcuts import render, HttpResponse

def login(request):
    if request.method == 'POST':
		# 获取post提交的账户密码
        username = request.POST.get('username')
        password = request.POST.get('password')

        from app02 import models
        # filter(username=username, password='xxx) 括号内可以携带对个参数,参数于参数之间默认为and的关系
        user_obj = models.user.objects.filter(username=username).first()
		
         # 直接以名称去取值,空则用户不存在,有组则说明用户存在。
        if user_obj: 
            # 直接对用户的密码进行比对,数据库密码的值为字符串,输入的密码位数字。
            if password == str(user_obj.password):
                return HttpResponse('登入成功')
            else:
                return HttpResponse('密码错误')
        else:
            return HttpResponse('用户不存在')
    return render(request, 'login.html')
objects.filter().first() 获取第一个值 
(内部还是使用索引,自己索引操作不安全别人操作,自己使用就好)

原本的操作:
# # select * from User where username='username';
# res = models.User.objects.filter(username=username)
# print(res)
# # < QueryDict: {'username': ['kid'], 'password': ['123']} >
# # < QuerySet[ < User: Userobject >] > 列表套数据对象
# user_obj = res[0]  # 索引取值拿到

在user中添加,在打印时触发。
    def __str__(self):
    return '%s' % self.username
7.2注册功能
开设一个注册功能
获取post提交的数据添加到数据库中。
字段为id(自增的)
username
password
1.第一步添加关系
在urls.py中添加路由与视图的关系。
# 在urls.py中添加
url(r'^register/', views.reg),
2.第二步创建路由
 创建简单的路由。
# 在app引用的views下创建reg函数
def reg(request):
    return reder(request,'reg.html')
3.第三部创建页面
创建注册页面。
在templates创建reg.html。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册</title>

    {% load static %}
    <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
    <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js'%}"></script>
</head>
<body>
    <h1 class="text-center">注册</h1>
    <div class="container">
        <div class="row">
            <div class="col-md-8 col-md-offset-2">
                <form action="" method="post">
                    <p>username: <input type="text" name="username" class="form-control"></p>
                    <p>password: <input type="password" name="password" class="form-control"></p>
                    <input type="submit" class="btn btn-danger btn-block">
                </form>
            </div>
        </div>
    </div>
</body>
</html>

在这里插入图片描述

3.第四步获取数据写入
丰富路由功能。
获取post方式提交的帐户名称与密码。
将信息写入数据库中。
from app02 import models  # 添加到文件顶部去
def reg(request):
    
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        
        models.user.objects.create(username=username, password=password)
        return HttpResponse('注册成功')
    return render(request, 'reg.html')
res = models.User.objects.create(username=username, password=password)
print(res, res.username, res.password)
# 返回值就是当前被创建对象的本身

8.增加功能

展示所有的用户信息。
点击按钮选择修改。
修改页面中展示用户名和密码,提供参考修改。
修改完成在存入数据库。
8.1展示部分
1.第一步建立关系
# 在urls.py中添加路由与视图的关系。
url(r'^userlist', views.userlist),
2.第二步创建路由
def userlist(request):
	return render(request, 'userlist.html')
3.创建页面
在templates创建userlist.html。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户信息</title>
    <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
    <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>

</head>
<body>
    <h1 class="text-center"> 数据展示</h1>
    <div class="row">
        <div class="col-md-8 col-md-offset-2"></div>
        <table class="table table-striped table-hover">
            <thead>
                <tr>
                    <th>ID</th>
                    <th>username</th>
                    <th>password</th>
                    <th>action</th>
                </tr>
            </thead>
            <tbody>
                {% for user_obj in user_querySet %}
                    <tr>
                    <td>{{ user_obj.id }}</td>
                    <td>{{ user_obj.username }}</td>
                    <td>{{ user_obj.password }}</td>
                    <td>
                        <a href="" class="btn btn-primary btn-xs">编辑</a>
                        <a href="" class="btn btn-danger btn-xs">删除</a>
                    </td>
                    </tr>
                {% endfor %}

            </tbody>
        </table>
    </div>
</body>
</html>
4.完善路由
def userlist(request):
    user_querySet = models.user.objects.all()           # .all 获取所有数据
    return render(request, 'userlist.html', locals())   # 将xx_querySet 名称空间传递到html

在这里插入图片描述

8.2修改数据
1.第一步给按键添加功能
点击标签跳转到数据修改的页面编辑按钮。
点击编辑提交get请求携带需要需要用户的id值。
在templates下的userlist.html。
<a href="/edit_user/?user_id={{ user_obj.id }}" class="btn btn-primary btn-xs">编辑</a>
2.第二步创建路由关系
url(r'^edit_user/', views.edit_user,
3.第三步创建路由
edit_id = request.GET.get('user_id') 获取需要修改的用户id。
def edit_user(request):
    user_id = request.GET.get('user_id')  # id的值

    edit_querySet = models.user.objects.filter(id=user_id).first()     # 获取修改用户的id
    return render(request, 'edit_user.html', locals())                 #  将xx_querySet 名称空间传递到html
4.第四步创建页面
value="{{ edit_querySet.username }}  # 展示用户的数据做为修改的参考
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>修改信息</title>

    {% load static %}
    <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
    <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js'%}"></script>
</head>
<body>
    <h1 class="text-center">修改</h1>
    <div class="container">
        <div class="row">
            <div class="col-md-8 col-md-offset-2">
                <form action="" method="post">
                    <p>username: <input type="text" name="username" class="form-control" value="{{ edit_querySet.username }}"></p>
                    <p>password: <input type="texe" name="password" class="form-control" value={{ edit_querySet.password  }}></p>
                    <input type="submit" class="btn btn-danger btn-block">
                </form>
            </div>
        </div>
    </div>
</body>
</html>>
5.完善路由功能
获取页面修改后post提交的数据。
models.User.objects.filter(id=edit_id).update(username=username,password=password)  更新数据。
def edit_user(request):
    user_id = request.GET.get('user_id')  # id的值
    edit_querySet = models.user.objects.filter(id=user_id).first()     # 获取修改用户的id
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')

        models.user.objects.filter(id=user_id).update(username=username, password=password)
        return redirect('/userlist/')  # 修改成功跳转到用户信息页面

    return render(request, 'edit_user.html', locals())   #  将xx_querySet 名称空间传递到html
# 方式二:  单独更新
edit_obj.username = username
edit_obj.password = password
edit_obj.save()
# 当字段多的时候效率低,从头到尾将数 据字段全更新一遍,无论是字段是否修改。
8.3删除功能
1.第一步给按键添加功能
点击编辑提交get请求携带需要需要用户的id值。
在templates下的userlist.html。
<a href="/delete_user/?user_id={{ user_obj.id }}" class="btn btn-primary btn-xs">删除</a>
2.第二步创建路由关系
url(r'^delete_user/', views.delete_user,
3.第三步创建路由
edit_id = request.GET.get('user_id') # 获取需要修改的用户id。
models.User.objects.filter(id=delete_id).delete()   # 使用id直接删除数据。
def delete_user(request):
    # 获取用户想要删除的数据id值
    delete_id = request.GET.get('user_id')
    # 直接去数据库中找到对应的数据删除即可
    models.User.objects.filter(id=delete_id).delete()
    # 批量删除
    return redirect('/userlist/')
1.真正的删除功能应该需要二次确认,
2.删除数据内部其实并不去真正的数据。为数据添加一个标识字段来表示当前数据是否被删除了。
如果数据被删了仅仅只是将字段修改了一个状态

userbane password is_delete
kid	      123	     0   
qz		  456        1
查询数据时过滤 is_delete = 0
C:\Users\86176\PycharmProjects\PythonProject15\venv\Scripts\python.exe "D:/python/PyCharm Community Edition 2024.3.5/plugins/python-ce/helpers/pycharm/_jb_pytest_runner.py" --path C:\Users\86176\PycharmProjects\PythonProject15\tests\test_conde.py Testing started at 00:13 ... Launching pytest with arguments C:\Users\86176\PycharmProjects\PythonProject15\tests\test_conde.py --no-header --no-summary -q in C:\Users\86176\PycharmProjects\PythonProject15\tests ============================= test session starts ============================= collecting ... collected 6 items test_conde.py::Test_Conde::test_topics test_conde.py::Test_Conde::test_topicsdetails test_conde.py::Test_Conde::test_updatatopic test_conde.py::Test_Conde::test_de_collect test_conde.py::Test_Conde::test_collecttopics test_conde.py::Test_Conde::test_replies ======================== 1 failed, 5 passed in 11.59s ========================= {'headers': {'Content-Type': 'application/json'}, 'ip': 'https://cnodejs.org/api/v1/', 'token': '72d70b7e-d2f7-4088-b773-e58b1c80a290', 'topics_id': '688a0c31f135766bd30832e3'} {'headers': {'Content-Type': 'application/json'}, 'ip': 'https://cnodejs.org/api/v1/', 'token': '72d70b7e-d2f7-4088-b773-e58b1c80a290', 'topics_id': '688a0c31f135766bd30832e3'} 主题首页的响应结果: {'success': True, 'data': [{'id': '688a0f96f1357644340832e9', 'author_id': '6844fce5f1357687c5082263', 'tab': 'ask', 'content': '<div class="markdown-text"><p>测试主题Tjdl62</p>\n</div>', 'title': '这是测试的主题vHFZ8', 'last_reply_at': '2025-07-30T12:27:02.770Z', 'good': False, 'top': False, 'reply_count': 0, 'visit_count': 86, 'create_at': '2025-07-30T12:27:02.770Z', 'author': {'loginname': 'fanmao54', 'avatar_url': '//gravatar.com/avatar/a3f848723b9dc33dfbdad1a8aa937cde?size=48'}}, {'id': '688a0c87f1357620e90832e5', 'author_id': '6844fce5f1357687c5082263', 'tab': 'ask', 'content': '<div class="markdown-text"><p>测试主题AGbm35</p>\n</div>', 'title': '这是测试的主题wMBj58', 'last_reply_at': '2025-07-30T12:13:59.796Z', 'good': False, 'top': False, 'reply_count': 0, 'visit_count': 46, 'create_at': '2025-07-30T12:13:59.796Z', 'author': {'loginname': 'fanmao54', 'avatar_url': '//gravatar.com/avatar/a3f848723b9dc33dfbdad1a8aa937cde?size=48'}}, {'id': '688a0c31f135766bd30832e3', 'author_id': '6844fce5f1357687c5082263', 'tab': 'ask', 'content': '<div class="markdown-text"><p>测试主题iLBb23</p>\n</div>', 'title': '这是测试的主题zkMX23', 'last_reply_at': '2025-07-30T12:12:33.525Z', 'good': False, 'top': False, 'reply_count': 0, 'visit_count': 63, 'create_at': '2025-07-30T12:12:33.525Z', 'author': {'loginname': 'fanmao54', 'avatar_url': '//gravatar.com/avatar/a3f848723b9dc33dfbdad1a8aa937cde?size=48'}}, {'id': '688a0a85f13576f8230832df', 'author_id': '6844fce5f1357687c5082263', 'tab': 'ask', 'content': '<div class="markdown-text"><p>主题内容JAGeZ33</p>\n</div>', 'title': '这是要测试的主题mCxC85', 'last_reply_at': '2025-07-30T12:05:25.867Z', 'good': False, 'top': False, 'reply_count': 0, 'visit_count': 50, 'create_at': '2025-07-30T12:05:25.867Z', 'author': {'loginname': 'fanmao54', 'avatar_url': '//gravatar.com/avatar/a3f848723b9dc33dfbdad1a8aa937cde?size=48'}}, {'id': '688a06bff13576221d0832d6', 'author_id': '6844fce5f1357687c5082263', 'tab': 'ask', 'content': '<div class="markdown-text"><p>主题内容</p>\n</div>', 'title': '这是要测试的主题', 'last_reply_at': '2025-07-30T11:49:19.692Z', 'good': False, 'top': False, 'reply_count': 0, 'visit_count': 56, 'create_at': '2025-07-30T11:49:19.692Z', 'author': {'loginname': 'fanmao54', 'avatar_url': '//gravatar.com/avatar/a3f848723b9dc33dfbdad1a8aa937cde?size=48'}}, {'id': '688a05abf1357665ac0832d2', 'author_id': '6844fce5f1357687c5082263', 'tab': 'ask', 'content': '<div class="markdown-text"><p>主题内容</p>\n</div>', 'title': '这是要测试的主题', 'last_reply_at': '2025-07-30T11:44:43.829Z', 'good': False, 'top': False, 'reply_count': 0, 'visit_count': 48, 'create_at': '2025-07-30T11:44:43.829Z', 'author': {'loginname': 'fanmao54', 'avatar_url': '//gravatar.com/avatar/a3f848723b9dc33dfbdad1a8aa937cde?size=48'}}, {'id': '686d2244f13576585f082ef4', 'author_id': '59315c6d64c9781e4812c952', 'tab': 'ask', 'content': '<div class="markdown-text"><p><img src="//static.cnodejs.org/FsSMCl8OyWMYXUxFbAF6fyUJ12X9" alt="heap.png"></p>\n<p>rss特别高但是js堆的内存都不高,通过–inspect我也拿不到这部分堆外内容的内存快照。\n我拿到的内存快照都只有50m左右大小,完全和rss不匹配\n有什么有效的排查思路/方法吗?</p>\n<p>// 补充\n图不知道为什么裂了。。。\n补充:\nrss - 1648.1mb\nextrenal - 2.26mb\nusedHeap - 49.97mb\ntotalHeap - 59.35mb</p>\n</div>', 'title': '【求助】内存泄漏排查', 'last_reply_at': '2025-07-29T06:41:05.636Z', 'good': False, 'top': False, 'reply_count': 4, 'visit_count': 577, 'create_at': '2025-07-08T13:51:00.415Z', 'author': {'loginname': 'tangtangtangtangtang', 'avatar_url': 'https://avatars.githubusercontent.com/u/24206594?v=4&s=120'}}, {'id': '6887aaf9f135766bfe0831fa', 'author_id': '6844fce5f1357687c5082263', 'tab': 'ask', 'content': '<div class="markdown-text"><p>主题内容</p>\n</div>', 'title': '这是要测试的主题', 'last_reply_at': '2025-07-28T16:53:13.601Z', 'good': False, 'top': False, 'reply_count': 0, 'visit_count': 119, 'create_at': '2025-07-28T16:53:13.601Z', 'author': {'loginname': 'fanmao54', 'avatar_url': '//gravatar.com/avatar/a3f848723b9dc33dfbdad1a8aa937cde?size=48'}}, {'id': '68862adff13576c3c90831d4', 'author_id': '6844fce5f1357687c5082263', 'tab': 'ask', 'content': '<div class="markdown-text"><p>主题内容</p>\n</div>', 'title': '这是要测试的主题', 'last_reply_at': '2025-07-27T13:34:23.484Z', 'good': False, 'top': False, 'reply_count': 0, 'visit_count': 123, 'create_at': '2025-07-27T13:34:23.484Z', 'author': {'loginname': 'fanmao54', 'avatar_url': '//gravatar.com/avatar/a3f848723b9dc33dfbdad1a8aa937cde?size=48'}}, {'id': '682a3b1a982e400de6722c81', 'author_id': '60d169c1248d04e60a4ae5de', 'tab': 'ask', 'content': '<div class="markdown-text"><p>最近在找工作,感觉很卷,真的完蛋了吗</p>\n</div>', 'title': '35岁的前端真的完蛋了吗?', 'last_reply_at': '2025-07-11T13:12:30.692Z', 'good': False, 'top': False, 'reply_count': 14, 'visit_count': 1775, 'create_at': '2025-05-18T19:55:06.731Z', 'author': {'loginname': 'dyjiang', 'avatar_url': 'https://avatars.githubusercontent.com/u/37732251?v=4&s=120'}}]} PASSED主题详情的响应结果: {'success': True, 'data': {'id': '688a0c31f135766bd30832e3', 'author_id': '6844fce5f1357687c5082263', 'tab': 'ask', 'content': '<div class="markdown-text"><p>测试主题iLBb23</p>\n</div>', 'title': '这是测试的主题zkMX23', 'last_reply_at': '2025-07-30T12:12:33.525Z', 'good': False, 'top': False, 'reply_count': 0, 'visit_count': 64, 'create_at': '2025-07-30T12:12:33.525Z', 'author': {'loginname': 'fanmao54', 'avatar_url': '//gravatar.com/avatar/a3f848723b9dc33dfbdad1a8aa937cde?size=48'}, 'replies': [], 'is_collect': False}} PASSED编辑主题的响应结果: {'success': True, 'topic_id': '688a0c31f135766bd30832e3'} PASSED取消收藏主题的响应结果: {'success': True} PASSED收藏主题的响应结果: {'success': True} PASSEDFAILED tests\test_conde.py:43 (Test_Conde.test_replies) self = <Response [404]>, kwargs = {} def json(self, **kwargs): r"""Returns the json-encoded content of a response, if any. :param \*\*kwargs: Optional arguments that ``json.loads`` takes. :raises requests.exceptions.JSONDecodeError: If the response body does not contain valid json. """ if not self.encoding and self.content and len(self.content) > 3: # No encoding set. JSON RFC 4627 section 3 states we should expect # UTF-8, -16 or -32. Detect which one to use; If the detection or # decoding fails, fall back to `self.text` (using charset_normalizer to make # a best guess). encoding = guess_json_utf(self.content) if encoding is not None: try: return complexjson.loads(self.content.decode(encoding), **kwargs) except UnicodeDecodeError: # Wrong UTF codec detected; usually because it's not UTF-8 # but some other 8-bit codec. This is an RFC violation, # and the server didn't bother to tell us what codec *was* # used. pass except JSONDecodeError as e: raise RequestsJSONDecodeError(e.msg, e.doc, e.pos) try: > return complexjson.loads(self.text, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ..\..\..\AppData\Local\Programs\Python\Python312\Lib\site-packages\requests\models.py:974: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ..\..\..\AppData\Local\Programs\Python\Python312\Lib\json\__init__.py:346: in loads return _default_decoder.decode(s) ^^^^^^^^^^^^^^^^^^^^^^^^^^ ..\..\..\AppData\Local\Programs\Python\Python312\Lib\json\decoder.py:337: in decode obj, end = self.raw_decode(s, idx=_w(s, 0).end()) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <json.decoder.JSONDecoder object at 0x0000023876655160> s = '<!DOCTYPE html>\n<html lang="en">\n<head>\n<meta charset="utf-8">\n<title>Error</title>\n</head>\n<body>\n<pre>Cannot POST /api/v1/topic/:topic/688a0c31f135766bd30832e3/replies</pre>\n</body>\n</html>\n' idx = 0 def raw_decode(self, s, idx=0): """Decode a JSON document from ``s`` (a ``str`` beginning with a JSON document) and return a 2-tuple of the Python representation and the index in ``s`` where the document ended. This can be used to decode a JSON document from a string that may have extraneous data at the end. """ try: obj, end = self.scan_once(s, idx) except StopIteration as err: > raise JSONDecodeError("Expecting value", s, err.value) from None E json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0) ..\..\..\AppData\Local\Programs\Python\Python312\Lib\json\decoder.py:355: JSONDecodeError During handling of the above exception, another exception occurred: self = <tests.test_conde.Test_Conde object at 0x0000023879610590> def test_replies(self):#新建评论 r = Replies(accesstoken=self.g.token,content="这是评论"+''.join(random.choice(string.ascii_letters)for _ in range(4))+str(random.randint(0,100))) > res = self.b.reply_id(r) ^^^^^^^^^^^^^^^^^^ test_conde.py:46: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ..\controller\base_controller.py:63: in reply_id print("新建评论的响应结果:", res.json()) ^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <Response [404]>, kwargs = {} def json(self, **kwargs): r"""Returns the json-encoded content of a response, if any. :param \*\*kwargs: Optional arguments that ``json.loads`` takes. :raises requests.exceptions.JSONDecodeError: If the response body does not contain valid json. """ if not self.encoding and self.content and len(self.content) > 3: # No encoding set. JSON RFC 4627 section 3 states we should expect # UTF-8, -16 or -32. Detect which one to use; If the detection or # decoding fails, fall back to `self.text` (using charset_normalizer to make # a best guess). encoding = guess_json_utf(self.content) if encoding is not None: try: return complexjson.loads(self.content.decode(encoding), **kwargs) except UnicodeDecodeError: # Wrong UTF codec detected; usually because it's not UTF-8 # but some other 8-bit codec. This is an RFC violation, # and the server didn't bother to tell us what codec *was* # used. pass except JSONDecodeError as e: raise RequestsJSONDecodeError(e.msg, e.doc, e.pos) try: return complexjson.loads(self.text, **kwargs) except JSONDecodeError as e: # Catch JSON-related errors and raise as requests.JSONDecodeError # This aliases json.JSONDecodeError and simplejson.JSONDecodeError > raise RequestsJSONDecodeError(e.msg, e.doc, e.pos) E requests.exceptions.JSONDecodeError: Expecting value: line 1 column 1 (char 0) ..\..\..\AppData\Local\Programs\Python\Python312\Lib\site-packages\requests\models.py:978: JSONDecodeError 进程已结束,退出代码为 1
08-02
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值