深拷贝和浅拷贝
| import copy |
| |
| |
| |
| obj = {'name': 'Alice', 'age': 25, 'address': {'city': 'New York'}} |
| |
| |
| obj_copy = copy.copy(obj) |
| |
| |
| obj_deep_copy = copy.deepcopy(obj) |
| obj_deep_copy1 = copy.copy(obj) |
| obj['address']['city'] = 'London' |
| print(obj) |
| print("深拷贝"+str(obj_deep_copy)) |
| print("浅拷贝"+str(obj_deep_copy1)) |
Pytest
| import sys |
| |
| import pytest |
| |
| |
| def inc(x): |
| return x+1 |
| |
| def test_answer(): |
| assert inc(4) == 5 |
| |
| def test_str(): |
| assert "a" in "abc" |
| |
| def test_print(): |
| print(sys.platform) |
| assert True |
| |
| params = ["appnium","pytest","selenium"] |
| @pytest.mark.parametrize("param",[ |
| ("3+5",8),("2+5",7),("7+5",12) |
| ]) |
| @pytest.mark.parametrize("expected",params) |
| def test_mark_more(param,expected): |
| print(f"param:{param},expected:{expected}") |
| |
| |
| |
| @pytest.mark.add |
| def test_function_add(): |
| print("test number add function") |
| assert 1+5 == 6 |
| |
| @pytest.mark.sub |
| def test_function_sub(): |
| print("test number sub function") |
| assert 1-5 == -4 |
| |
| @pytest.mark.mult |
| def test_function_mult(): |
| print("test number mult function") |
| assert 1*5 == 5 |
| |
| @pytest.mark.divide |
| def test_function_divide(): |
| print("test number divide function") |
| assert 1/5 == 0.2 |
| |
| @pytest.mark.divide |
| def test_function_divide2(): |
| print("test number divide function") |
| assert 1/10 == 0.1 |
如果希望没有警告,在项目根目录下创建pytest.ini文件,并输入对应的内容
| [pytest] |
| markers = add |
| sub |
| mult |
| divide |
| parametrize |
| |
| @pytest.mark.skip |
| def test_print(): |
| print("test) |
| |
| # 跳过这条用例并返回原因 |
| @pytest.mark.skip(reason="原因") |
| def test_print1(): |
| print("test) |
| |
| |
| @pytest.mark.skipif(sys.platform="win",reason="do not run in windows") |
| def test_print3(): |
| print("test) |
| |
| # xfail预期运行失败能够符合预期 |
| @pytest.mark.xfail(reason="原因") |
| def test_print4(): |
| print("代码尚未开发完") |
| |
pytest test_demo.py -vs --lf
--lf参数:将所有失败的测试用例全部重新执行一次
pytest test_demo.py -vs --ff
--ff参数:先执行所有失败的测试用例,再去执行其他的测试用例
-x参数:用例一旦失败(fail/error),就立刻停止执行
--maxfail=num参数:用例达到num数量
-m参数:运行被标记的标签的用例
-k参数:执行包含某个关键字的测试用例
-v参数:打印详细日志
-s参数:打印输出日志(一般-vs一起使用)
-collect-only(测试平台,pytest 自动导入功能)
| def test_raise1(): |
| with pytest.raises(ZeroDivisionError) as exc_info: |
| raise ValueError("value must be 42") |
| |
| assert exc_info.type is ValueError |
| assert exc_info.value.args[0] == "value must be 42" |
数据驱动-yaml
selenium高级交互
鼠标滚轮操作
| import time |
| |
| from selenium import webdriver |
| from selenium.webdriver import ActionChains |
| from selenium.webdriver.common.by import By |
| |
| |
| class TestScroll: |
| |
| def setup_class(self): |
| self.driver = webdriver.Chrome() |
| self.driver.implicitly_wait(3) |
| |
| def teardown_class(self): |
| self.driver.quit() |
| |
| def test_scroll(self): |
| |
| self.driver.get("https://ceshiren.com/tag/%E7%B2%BE%E5%8D%8E%E5%B8%96") |
| self.driver.maximize_window() |
| ele1 = self.driver.find_element(By.XPATH,"//*[text()='毕业设计-针对OB-制品项目业务测试方案']") |
| ActionChains(self.driver).scroll_to_element(ele1).perform() |
| time.sleep(15) |
| |
| def test_scroll_to_xy(self): |
| |
| self.driver.get("https://ceshiren.com/tag/%E7%B2%BE%E5%8D%8E%E5%B8%96") |
| self.driver.maximize_window() |
| ActionChains(self.driver).scroll_by_amount(0,3000).perform() |
| time.sleep(10) |
鼠标移动操作
| import time |
| |
| from selenium import webdriver |
| from selenium.webdriver import ActionChains |
| from selenium.webdriver.common.by import By |
| |
| |
| class TestMouse: |
| |
| def setup_class(self): |
| self.driver = webdriver.Chrome() |
| self.driver.implicitly_wait(3) |
| |
| def teardown_class(self): |
| self.driver.quit() |
| |
| def test_double_click(self): |
| |
| self.driver.get("https://vip.ceshiren.com/#/ui_study/frame") |
| self.driver.maximize_window() |
| ele = self.driver.find_element(By.ID,"primary_btn") |
| ActionChains(self.driver).double_click(ele).perform() |
| time.sleep(5) |
| |
| def test_drag_and_drop(self): |
| |
| self.driver.get("https://vip.ceshiren.com/#/ui_study/action_chains") |
| self.driver.maximize_window() |
| ele1 = self.driver.find_element(By.ID,"item1") |
| ele2 = self.driver.find_element(By.ID,"item3") |
| ActionChains(self.driver).drag_and_drop(ele1, ele2).perform() |
| time.sleep(5) |
| |
| def test_move_to_element(self): |
| |
| self.driver.get("https://vip.ceshiren.com/#/ui_study/action_chains2") |
| self.driver.maximize_window() |
| ele1 = self.driver.find_element(By.CLASS_NAME,"title") |
| ele2 = self.driver.find_element(By.XPATH,"//*[contains(text(),'管理班')]") |
| ActionChains(self.driver)\ |
| .move_to_element(ele1)\ |
| .click(ele2)\ |
| .perform() |
| time.sleep(5) |
| |
键盘输入操作
| import sys |
| import time |
| |
| from selenium import webdriver |
| from selenium.webdriver import ActionChains |
| from selenium.webdriver.common.by import By |
| from selenium.webdriver.common.keys import Keys |
| |
| |
| class Testweb: |
| |
| def setup_class(self): |
| self.driver = webdriver.Chrome() |
| self.driver.implicitly_wait(3) |
| |
| def teardown_class(self): |
| self.driver.quit() |
| |
| def test_shife(self): |
| |
| self.driver.get("https://ceshiren.com") |
| self.driver.maximize_window() |
| self.driver.find_element(By.ID,"search-button").click() |
| ele = self.driver.find_element(By.ID,"search-term") |
| ActionChains(self.driver).key_down(Keys.SHIFT, ele).send_keys("selenium").perform() |
| time.sleep(5) |
| |
| def test_enter_by_send_keys(self): |
| |
| self.driver.get("https://www.sogou.com/") |
| self.driver.maximize_window() |
| self.driver.find_element(By.ID,"query").send_keys("selenium") |
| self.driver.find_element(By.ID,"stb").click() |
| time.sleep(5) |
| |
| def test_exit_by_actions(self): |
| |
| self.driver.get("https://www.sogou.com/") |
| self.driver.maximize_window() |
| ActionChains(self.driver)\ |
| .key_down(Keys.SHIFT)\ |
| .send_keys("selenium")\ |
| .key_down(Keys.ENTER)\ |
| .perform() |
| time.sleep(5) |
| |
| def test_copy_and_paste(self): |
| |
| self.driver.get("https://www.sogou.com/") |
| self.driver.maximize_window() |
| if sys.platform == "darwin": |
| command_control = Keys.COMMAND |
| else: |
| command_control = Keys.CONTROL |
| ele = self.driver.find_element(By.ID,"query") |
| ActionChains(self.driver)\ |
| .key_down(Keys.SHIFT,ele)\ |
| .send_keys("selenium")\ |
| .key_down(Keys.ARROW_LEFT)\ |
| .key_down(command_control)\ |
| .send_keys("cvvvv").key_up(command_control).perform() |
| time.sleep(5) |
| |
多窗口和frame处理
切换页面和切换frame
| import time |
| |
| from selenium import webdriver |
| from selenium.webdriver import ActionChains |
| from selenium.webdriver.common.by import By |
| |
| |
| class TestBaidu: |
| |
| def setup_class(self): |
| self.driver = webdriver.Chrome() |
| self.driver.implicitly_wait(3) |
| self.driver.maximize_window() |
| |
| def tear_down(self): |
| self.driver.quit() |
| |
| def test_baidu(self): |
| |
| self.driver.get("https://www.baidu.com/") |
| self.driver.find_element(By.LINK_TEXT, "登录").click() |
| |
| self.driver.find_element(By.LINK_TEXT, "立即注册").click() |
| windows = self.driver.window_handles |
| self.driver.switch_to.window(windows[1]) |
| self.driver.find_element(By.ID,"TANGRAM__PSP_4__userName").send_keys("username") |
| self.driver.find_element(By.ID,"TANGRAM__PSP_4__phone").send_keys("15915420233") |
| self.driver.find_element(By.ID,"TANGRAM__PSP_4__password").send_keys("password") |
| self.driver.switch_to.window(windows[0]) |
| self.driver.find_element(By.ID, "TANGRAM__PSP_11__userName").send_keys("username") |
| self.driver.find_element(By.ID, "TANGRAM__PSP_11__password").send_keys("password") |
| time.sleep(5) |
| |
| def test_switch_to_frame(self): |
| |
| self.driver.get("https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable") |
| self.driver.switch_to.frame("iframeResult") |
| print(self.driver.find_element(By.ID, "draggable").text) |
| self.driver.switch_to.parent_frame() |
| print(self.driver.find_element(By.ID, "submitBTN").text) |
| |
文件上传及弹窗处理
上传文件
| import time |
| |
| from selenium import webdriver |
| from selenium.webdriver.common.by import By |
| |
| |
| class TestIamge: |
| def setup_class(self): |
| self.driver = webdriver.Chrome() |
| self.driver.implicitly_wait(3) |
| self.driver.maximize_window() |
| |
| def teardown_class(self): |
| self.driver.quit() |
| |
| def test_uploadfile(self): |
| |
| self.driver.get("https://image.baidu.com/") |
| self.driver.find_element(By.XPATH,"//*[@id='sttb']/img[1]").click() |
| self.driver.find_element(By.ID,"stfile").send_keys("D:\code_repository\pythonProject\img\img1.jpg") |
| time.sleep(5) |
弹窗处理
| import time |
| |
| from selenium import webdriver |
| from selenium.webdriver import ActionChains |
| from selenium.webdriver.common.by import By |
| |
| |
| class TestAlert: |
| def setup_class(self): |
| self.driver = webdriver.Chrome() |
| self.driver.implicitly_wait(3) |
| self.driver.maximize_window() |
| |
| def teardown_class(self): |
| self.driver.quit() |
| |
| def test_alert(self): |
| |
| self.driver.get("https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable") |
| self.driver.switch_to.frame("iframeResult") |
| element = self.driver.find_element(By.ID, "draggable") |
| target_element = self.driver.find_element(By.ID, "droppable") |
| ActionChains(self.driver).drag_and_drop(element,target_element).perform() |
| alert = self.driver.switch_to.alert |
| print(alert.text) |
| alert.accept() |
| time.sleep(5) |
获取日志
日志工具类
| import logging |
| |
| |
| logger = logging.getLogger('simple_example') |
| |
| logger.setLevel(logging.DEBUG) |
| |
| ch = logging.StreamHandler() |
| ch.setLevel(logging.DEBUG) |
| |
| formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') |
| |
| ch.setFormatter(formatter) |
| |
| logger.addHandler(ch) |
打印日志和截图、获取源码
| import time |
| |
| from selenium import webdriver |
| from selenium.webdriver.common.by import By |
| |
| from log_util import logger |
| |
| |
| class TestDataRecord: |
| def setup_class(self): |
| self.driver = webdriver.Chrome() |
| self.driver.implicitly_wait(3) |
| self.driver.maximize_window() |
| |
| def teardown_class(self): |
| self.driver.quit() |
| |
| def test_log_data_record(self): |
| |
| search_content = "selenium" |
| self.driver.get("https://www.sogou.com/") |
| self.driver.find_element(By.ID, "query").send_keys(search_content) |
| logger.debug(f"搜索信息为{search_content}") |
| self.driver.find_element(By.ID, "stb").click() |
| elements = self.driver.find_elements(By.CSS_SELECTOR, 'em') |
| for element in elements: |
| logger.info(f"实际结果为{element.text},预期结果为{search_content}") |
| time.sleep(5) |
| |
| def test_screenshot_data_record(self): |
| |
| search_content = "selenium" |
| self.driver.get("https://www.sogou.com/") |
| self.driver.find_element(By.ID, "query").send_keys(search_content) |
| logger.debug(f"搜索信息为{search_content}") |
| self.driver.find_element(By.ID, "stb").click() |
| elements = self.driver.find_elements(By.CSS_SELECTOR, 'em') |
| print(elements) |
| for element in elements: |
| logger.info(f"实际结果为{element.text},预期结果为{search_content}") |
| index_num = str(elements.index(element)) |
| self.driver.save_screenshot("search_content"+index_num+".jpg") |
| |
| def test_page_source(self): |
| |
| search_content = "selenium" |
| self.driver.get("https://www.sogou.com/") |
| self.driver.find_element(By.ID, "query").send_keys(search_content) |
| logger.debug(self.driver.page_source) |
| with open("../log/log1.html", "x", encoding="u8") as file: |
| file.write(self.driver.page_source) |
浏览器复用
步骤
1、获取浏览器的路径

2、配置环境变量到path

3、关闭所有chrome浏览器并关闭进程
cmd运行chrome --remote-debugging-port=9222
4、使用浏览器复用操作
| from selenium import webdriver |
| from selenium.webdriver.chrome.options import Options |
| |
| |
| option = Options() |
| |
| option.debugger_address = "localhost:9222" |
| |
| driver = webdriver.Chrome(options=option) |
| driver.get("https://work.weixin.qq.com/wework_admin/loginpage_wx") |
| |
Cookie复用
| import json |
| import time |
| |
| import yaml |
| from selenium import webdriver |
| |
| |
| class TestChromeCookie: |
| |
| def setup_class(self): |
| self.driver = webdriver.Chrome() |
| self.driver.maximize_window() |
| self.driver.implicitly_wait(3) |
| |
| def test_get_cookie(self): |
| |
| self.driver.get("https://work.weixin.qq.com/wework_admin/loginpage_wx") |
| time.sleep(20) |
| cookie = self.driver.get_cookies() |
| with open("../cookie/cookie.yaml", "w") as filter: |
| yaml.dump(cookie, filter) |
| print(cookie) |
| |
| def test_add_cookie(self): |
| |
| |
| self.driver.get("https://work.weixin.qq.com/wework_admin/loginpage_wx") |
| |
| cookies = yaml.safe_load(open("../cookie/cookie.yaml")) |
| for cookie in cookies: |
| self.driver.add_cookie(cookie) |
| self.driver.get("https://work.weixin.qq.com/wework_admin/loginpage_wx") |
| time.sleep(5) |
异常截图并导入到报告中
| import time |
| |
| import allure |
| import pytest |
| from selenium import webdriver |
| from selenium.webdriver.common.by import By |
| |
| |
| class TestBaidu: |
| |
| def setup_class(self): |
| self.driver = webdriver.Chrome() |
| self.driver.maximize_window() |
| |
| def tearDown(self): |
| self.driver.quit() |
| |
| def test_baidu(self): |
| self.driver.get("https://www.baidu.com") |
| try: |
| self.driver.find_element(By.ID, "su") |
| except Exception: |
| print("出现异常啦") |
| timestamp = int(time.time()) |
| |
| image_path = f"../images/image_{timestamp}.png" |
| page_source_path = f"../page_source/page_source_{timestamp}.html" |
| self.driver.save_screenshot(image_path) |
| |
| with open(page_source_path, mode="w", encoding='u8') as f: |
| f.write(self.driver.page_source) |
| allure.attach.file(image_path, name="picture", attachment_type=allure.attachment_type.PNG) |
| allure.attach.file(page_source_path, name="page_source", attachment_type=allure.attachment_type.HTML) |
| |
| raise Exception |
通过命令行进行运行生成allure需要加载的内容
pytest python文件路径 --alluredir=./reports
然后通过allure命令进行allure测试报告进行读取
allure serve ./reports
代码优化
| import time |
| |
| import allure |
| import pytest |
| from selenium import webdriver |
| from selenium.webdriver.common.by import By |
| |
| from util.decorators_util import ui_exception_record |
| |
| """ |
| 把装饰器的架子搭好 |
| 把相关的逻辑嵌套进来 |
| 问题1: |
| 需要通过driver实例截图/打印page_source,装饰器需要先去获取driver对象 |
| 解决方案: |
| 1、通过setup_class进行driver对象的声明 |
| 2、在使用driver之前声明driver |
| 问题2: |
| 隐藏的Bug:一旦被装饰方法有返回值,会丢失返回值 |
| 解决方法: |
| 当被装饰方法被执行的时候,添加return |
| """ |
| |
| |
| class TestBaidu: |
| |
| def setup_class(self): |
| self.driver = webdriver.Chrome() |
| self.driver.maximize_window() |
| |
| def tear_down(self): |
| self.driver.quit() |
| |
| @ui_exception_record |
| def find(self): |
| return self.driver.find_element(By.ID, "su1") |
| |
| |
| def test_baidu(self): |
| self.driver.get("https://www.baidu.com") |
| self.find().click() |
| |
装饰器工具封装
| |
| import allure |
| |
| |
| def ui_exception_record(func): |
| def inner(*args, **kwargs): |
| |
| |
| |
| |
| |
| try: |
| |
| return func(*args, **kwargs) |
| except Exception: |
| driver = args[0].driver |
| print("出现异常啦") |
| timestamp = int(time.time()) |
| |
| image_path = f"../images/image_{timestamp}.png" |
| page_source_path = f"../page_source/page_source_{timestamp}.html" |
| driver.save_screenshot(image_path) |
| |
| with open(page_source_path, mode="w", encoding='u8') as f: |
| f.write(driver.path_source) |
| allure.attach.file(image_path, name="picture", attachment_type=allure.attachment_type.PNG) |
| allure.attach.file(page_source_path, name="page_source", attachment_type=allure.attachment_type.TEXT) |
| |
| raise Exception |
| return inner |
page object设计模式
POM建模原则
字段意义
不要暴露页面内部的元素给外部
不需要建模UI内的所有元素
方法意义
用公共方法代表UI所提供的功能
方法应该返回其他的PageObject或者返回用于断言的数据
同样的行为不同的结果可以建模为不同的方法
不要在方法内加断言
把元素信息和操作细节封装到PageObject类中
根据业务逻辑,在测试用例中链式调用
Django
创建项目方式
访问进入到想要放置项目的地址
终端运行命令
django-admin startproject 项目名
快速上手
确保App已注册 setting.py
在setting.py文件中注册App
| from django.apps import AppConfig |
| |
| |
| class App01Config(AppConfig): |
| default_auto_field = 'django.db.models.BigAutoField' |
| name = 'DjangoTryProject' |
| INSTALLED_APPS = [ |
| 'django.contrib.admin', |
| 'django.contrib.auth', |
| 'django.contrib.contenttypes', |
| 'django.contrib.sessions', |
| 'django.contrib.messages', |
| 'django.contrib.staticfiles', |
| 'DjangoProject.apps' |
| ] |
| |
编写url和视图函数对应关系 ursl.py
如果访问 域名/index/,将会找到view中的index方法并执行index方法
| from DjangoTryProject import view |
| |
| urlpatterns = [ |
| |
| path('index/', view.index), |
| ] |
| |

编写视图函数
| from django.http import HttpResponse |
| |
| |
| def index(request): |
| return HttpResponse("欢迎使用Django") |
启动Django项目
命令行方式
| python manager.py runserver |
pycharm直接运行
跟前端文件联动
创建一个templates文件夹,里面放需要使用的前端html文件
| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <title>测试Django</title> |
| </head> |
| <body> |
| <h1>用户列表</h1> |
| </body> |
| </html> |
| from django.http import HttpResponse |
| from django.shortcuts import render |
| |
| |
| def index(request): |
| return HttpResponse("欢迎使用Django") |
| |
| def user_list(request): |
| return render(request, "user_list.html") |
静态文件
放到static文件夹并用文件夹区分好

静态文件引入
| {% load static %} |
| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <title>测试Django</title> |
| </head> |
| <body> |
| <h1>用户列表</h1> |
| </body> |
| |
| <script src="{% static 'js/jquery.js' %}"></script> |
| </html> |
模版语法
通过在html文件中填写占位符,然后由数据对这些占位符进行替换和处理
| def tpl(request): |
| name = "tpl测试" |
| roles = ["admin","user","CES"] |
| user_info = {"name":"郭嘉","salary":2000,"role":"CTO"} |
| data_list = [ |
| {"name": "曹操", "salary": 2000, "role": "CTO"}, |
| {"name": "郭嘉", "salary": 2000, "role": "CTO"}, |
| {"name": "张飞", "salary": 2000, "role": "CTO"} |
| ] |
| return render(request, "tpl.html", {"n1":name,"n2":roles,"n3":user_info,"n4":data_list}) |
| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <title>tpl</title> |
| </head> |
| <body> |
| <h1>模版语法的学习</h1> |
| <div>{{ n1 }}</div> |
| <div> |
| {% for item in n2 %} |
| <span>{{ item }}</span> |
| {% endfor %} |
| </div> |
| <hr> |
| |
| <ul> |
| {% for item in n3.values %} |
| <li>{{ item }}</li> |
| {% endfor %} |
| </ul> |
| <hr> |
| {{ n4 }} |
| {{ n4.0.name }} |
| {{ n4.0.salary }} |
| {{ n4.0.role }} |
| <hr> |
| {% for foo in n4 %} |
| <div>{{ foo.name }}</div> |
| <div>{{ foo.salary }}</div> |
| <div>{{ foo.role }}</div> |
| {% endfor %} |
| |
| <hr> |
| {% if n1 == "tpl测试" %} |
| <div>tpl测试</div> |
| {% else %} |
| <div>tpl测试失败</div> |
| {% endif %} |
| |
| </body> |
| </html> |
模版语法实战
| def news(request): |
| import requests |
| result = requests.get( |
| url="https://i.news.qq.com/gw/event/pc_hot_ranking_list?ids_hash=&offset=0&page_size=50&appver=15.5_qqnews_7.1.60&rank_id=hot" |
| ) |
| data_list = result.json()["idlist"][0]["newslist"] |
| return render(request, "news.html", {"result": data_list}) |
| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <title>腾讯新闻</title> |
| </head> |
| <body> |
| <ul> |
| {% for foo in result %} |
| <li>{{ foo.id }}</li> |
| <li>{{ foo.articletype }}</li> |
| <li>{{ foo.picShowType }}</li> |
| <li>{{ foo.title }}</li> |
| {% endfor %} |
| </ul> |
| |
| {{ result }} |
| |
| </body> |
| </html> |
| |
| |
用户访问逻辑
用户访问地址,会到urls.py匹配到对应的方法,然后到view.py中找到这个方法,再又这个方法的模版页面替换里面的数据,然后再渲染给用户

获取url的传参
- request.GET方法能够获取param
- request.POST方法能够获取到POST请求的请求体
- request.method方法能够获取请求方式
return的内容
- redirect重定向
- render方法页面模版
- HttpResponse响应
提交表单
| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <title>Title</title> |
| </head> |
| <body> |
| <form action="/login/" method="post" > |
| {% csrf_token %} |
| <input type="text" name="user" placeholder="用户名"> |
| <input type="password" name="password" placeholder="密码"> |
| <input type="submit" value="提交">{{ error_message }} |
| </form> |
| </body> |
| </html> |
表单提交的时候,需要在form中补充{% csrf_token %}才不会报错
{{ error_message }}如果需要出现报错信息,就可以在方法中补充传值
| def login(request): |
| if request.method == "GET": |
| return render(request, "login.html") |
| user = request.POST.get("user") |
| password = request.POST.get("password") |
| if user == "root" and password == "1234": |
| print(request.POST) |
| return render(request, "login.html", {"error_message":"登录成功"}) |
| else: |
| return render(request, "login.html", {"error_message":"用户名或密码错误"}) |
| |
数据库操作
Django开发操作数据库更简单,内部提供了ORM框架
安装第三方模块mysqlclient
ORM作用
- 不用亲自写SQL语句
- 创建修改删除数据库中的表(无法创建database)
- 操作表中的数据
Django连接数据库
| DATABASES = { |
| "default": { |
| "ENGINE": "django.db.backends.mysql", |
| "NAME": "", |
| "USER": "", |
| "PASSWORD": "", |
| "HOST": "", |
| "PORT": "", |
| } |
| } |
创建表
| from django.db import models |
| |
| """ |
| 自动运行以下代码 |
| create table DjangoProject_userinfo( |
| id bigint primary key autoincrement, |
| name varchar(32), |
| password varchar(64), |
| age int |
| ) |
| """ |
| class User_info(models.Model): |
| name = models.CharField(max_length=32) |
| age = models.IntegerField() |
| password = models.CharField(max_length=64) |
| text = models.CharField(max_length=16) |
| textname = models.CharField(max_length=16,default=2) |
| |
| |
| |
| |
| class department(models.Model): |
| name = models.CharField(max_length=16) |
| |
| class role(models.Model): |
| name = models.CharField(max_length=16) |
| |
| |
| |
cmd运行(大前提:App必须已经注册)
| python.exe .\manage.py makemigrations APP名称 |
| python.exe .\manage.py migrate |
| |
| |
| |
新建数据
| department.object.create(name="销售部") |
| |
| |
| def orm(request): |
| if request.method == 'GET': |
| return render(request, "orm.html") |
| username = request.POST.get("name") |
| age = request.POST.get("age") |
| password = request.POST.get("password") |
| text = request.POST.get("text") |
| |
| User_info.objects.create(name= username, age = age, password =password, text = text) |
| |
| User_info.objects.filter(id="1").delete() |
| |
| User_info.objects.all().delete() |
| |
| userObject = User_info.objects |
| user_list = User_info.objects.all() |
| for user in user_list: |
| print(user.name, user.password, user.age, user.text) |
| |
| userObject.filter(id=1).update(password = 123123) |
| first = userObject.filter(id=1).first() |
| print(first.name, first.age, first.text, first.password) |
| return HttpResponse("上传成功") |
| |
| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <title>orm</title> |
| </head> |
| <body> |
| <form action="/orm/" method="post"> |
| {% csrf_token %} |
| <input type="text" placeholder="name" name="name"> |
| <input type="text" placeholder="age" name="age"> |
| <input type="password" placeholder="password" name="password"> |
| <input type="text" placeholder="text" name="text"> |
| <input type="submit" value="提交"> |
| </form> |
| </body> |
| </html> |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本