【发布时间】:2022-01-21 14:26:44
【问题描述】:
我有一个显示表单的 Django webapp。其中一个字段是 FileField,通过表单的 Django 模型定义:
来自models.py:
class Document(models.Model):
...
description = models.CharField(max_length=100, default="")
document = models.FileField(upload_to="documents/", max_length=500)
document file_field 附加了一个onchange ajax 函数,该函数将解析上传的文件名,根据它检查一些数据库内容,并使用结果填充 html 页面上的其他字段。
来自forms.py:
class DocumentForm(forms.ModelForm):
class Meta:
model = Document
fields = ("document",)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["customer"] = forms.CharField(initial="", required=True)
self.fields["output_profile"] = forms.CharField(initial="", required=True)
self.fields["document"].widget.attrs[
"onchange"
] = "checkFileFunction(this.value, '/ajax/check_file/')"
来自urls.py:
urlpatterns = [
#...
path("ajax/check_file/", views.check_file, name="ajax_check_file")
]
来自views.py:
def check_file(request):
full_data = {"my_errors": []}
my_path = pathlib.Path(request.GET.get("file_path").replace("\\", os.sep))
# parse customer ID from file_path
# get data of customer from db
# assemble everything into full_data
return JsonResponse(full_data)
这是显示的完整 html 页面(从 Chrome 复制 => 显示源并清理了一些缩进和空格):
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<link href="/static/css/main.css" rel="stylesheet" type="text/css">
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/themes/base/jquery-ui.css"/>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.20/css/dataTables.jqueryui.css"/>
<script src="/static/js/jquery.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdn.datatables.net/1.10.20/js/jquery.dataTables.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/1.10.20/js/dataTables.jqueryui.js"></script>
<title>
Convert RES FILE
</title>
</head>
<body>
<header id="header">
<section class="top_menu_left">
<a href="/accounts/login">Login</a>
<a> | </a>
<a href="/logout">Logout</a>
<a> | </a>
<a href="/edit_profile">Edit User</a>
<a> | </a>
<a href="/register">Register</a>
</section>
<section class="top_menu_right">
<a href="/cartoon">About Us</a>
<a> | </a>
<a href="/contact">Contact Us</a>
<a> | </a>
<a href="/issue">Submit an issue</a>
<a> | </a>
<a href="/documentation">Documentation</a>
<a> | </a>
<a href="/home">Home</a>
</section>
<div id="topbanner" >
<img src="/static/banner_small.png" alt="" width="100%" height="150"/>
</div>
</header>
<aside id="leftsidebar">
<section class="nav_account">
<h4>Submit a New Request</h3>
<ul>
<li><a href="/add_submission">Get Typing Results</a></li>
<li><a href="/add_comparison">Compare Typing Results</a></li>
<li><a href="/convert_typing_format">Convert Typing Format</a></li>
</ul>
</section>
<section class="nav_tools">
<h4>View Your Requests</h3>
<ul>
<li><a href="/view_submission/?show_all=no">View My Submissions</a></li>
</ul>
</section>
</aside>
<section id="main">
<p> </p>
<h2>Convert Typing Results to Format of Choice</h2>
<p> </p>
<h3>Upload a file to our database</h3>
<form method="post" enctype="multipart/form-data">
<input type="hidden" name="csrfmiddlewaretoken" value="qqIKcsAynuE35MQ37dvjF5XeIyfcEbHb3wjtgygGZaigQReNxHLQewoDKcEb8Roj">
<div id="div_id_document" class="form-group">
<label for="id_document" class=" requiredField">
Document<span class="asteriskField">*</span>
</label>
<div class="">
<input type="file" name="document" onchange="checkFileFunction(this.value, '/ajax/check_file/')" class="clearablefileinput form-control-file" required id="id_document">
</div>
</div>
<input type="hidden" id="id_description" name="description" value="">
<p> </p>
<div id="div_id_customer" class="form-group">
<label for="id_customer" class=" requiredField">
Customer<span class="asteriskField">*</span>
</label>
<div class="">
<input type="text" name="customer" readonly class="textinput textInput form-control" required id="id_customer">
</div>
</div>
<div id="div_id_output_profile" class="form-group">
<label for="id_output_profile" class=" requiredField">
Output profile<span class="asteriskField">*</span>
</label>
<div class="">
<input type="text" name="output_profile" readonly class="textinput textInput form-control" required id="id_output_profile">
</div>
</div>
<div class="form-group">
<div id="div_id_notify_me" class="form-check">
<input type="checkbox" name="notify_me" style="width:15px;height:15px;" class="checkboxinput form-check-input" id="id_notify_me">
<label for="id_notify_me" class="form-check-label">
Notify me
</label>
</div>
</div>
<p>
<button class="linkbutton" type="submit" id="submit_btn">Convert</button>
<button id="create-book" class="linkbutton" type="button" name="button" style="float: right;">Create an Output Profile</button>
</p>
</form>
<div class="modal fade" tabindex="-1" role="dialog" id="modal">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content" id="form-modal-content">
</div>
</div>
</div>
<div class="modal fade" tabindex="-1" role="dialog" id="modal-check-res-file">
<div class="modal-dialog" role="document">
<div class="modal-content" id="form-modal-content-check-res-file">
</div>
</div>
</div>
<script>
var formAjaxSubmit = function(form, modal) {
$(form).on('submit', function (e) {
e.preventDefault();
console.log("submitting...");
var my_val = $("#id_profile_name").val();
var this_val = $("#confirm_save").val();
var res = this_val.split(",");
var this_val_contains_my_val = (res.indexOf(my_val) > -1);
if (this_val_contains_my_val === true) {
var conf = confirm("Are you sure want to overwrite an exsisting profile?");
}else {var conf = true;};
if (conf === true) {
$.ajax({
type: $(this).attr('method'),
url: "/new_customer_profile/",
data: $(this).serialize(),
success: function (xhr, ajaxOptions, thrownError) {
if ( $(xhr).find('.invalid-feedback').length > 0 ) {
$(modal).find('.modal-content').html(xhr);
formAjaxSubmit(form, modal);
} else {
$(modal).find('.modal-content').html(xhr);
}
},
error: function (xhr, ajaxOptions, thrownError) {
}
});
};
});
};
$('#create-book').click(function() {
console.log("hhallo");
$('#form-modal-content').load('/new_customer_profile/', function () {
var iam_alive = document.getElementById("modal");
// check if iam_alive is defined, this is required if a session expired -> in that case the modal is lost and it would redirect to an almost empty page.
if (iam_alive) {
$('#modal').modal('toggle');
formAjaxSubmit('#form-modal-body form', '#modal');
}
// if not iam_alive: redirect to login page
else {
window.location.replace('/accounts/login/');
}
});
});
$('#check-res-file').click(function() {
console.log("hhallo hier unten jetzt");
$('#form-modal-content-check-res-file').load('/check_res_file/', function () {
$('#modal-check-res-file').modal('toggle');
//formAjaxSubmit('#form-modal-body form', '#modal');
});
});
</script>
<script type="text/javascript">
$(document).ready(function() {
var mycell = document.getElementById("create-book");
mycell.style.display = "none";
});
</script>
<script>
function checkFileFunction(myfile, url) {
$.ajax({ // initialize an AJAX request
url: url, // set the url of the request (= localhost:8000/hr/ajax/load-cities/)
data: {"file_path": myfile},
dataType: 'json',
success: function (x) {
if (x.my_errors.length == 0) {
$('#id_customer').val(x.customer_name);
$('#id_output_profile').val(x.customer_profile);
$('#id_description').val(x.customer_file);
}else{
$('#id_customer').val("");
$('#id_customer').val("");
$('#id_output_profile').val("");
alert(x.my_errors);
var showme = function myFunction() {
var mycell = document.getElementById("create-book");
mycell.style.display = "block";
};
showme();
}
},
});
}
</script>
</section>
</body>
</html>
现在,我正在尝试通过 Selenium 使用 pytest 进行测试。
我可以通过 send_keys() 将文件路径发送到字段。但是,onchange 事件似乎没有被触发。 (当我手动选择文件时它确实工作正常。)
file_field = self.driver.find_element(By.NAME, "document")
file_field.clear()
file_field.send_keys(str(path/to/myfile))
这将很好地注册文件并上传,但onchange 函数永远不会发生。
我搜了一下,好像其他人也遇到过send_keys没有触发onchange事件的问题。但是我无法在我的 Python 代码中实现任何建议的解决方案。 (我还没有写过这个应用程序的Django代码,我只是一个测试人员,我对Django和javascript的掌握还不是很好。我的母语编程语言是Python。)
我了解如何实施的唯一解决方案是之后发送 TAB 或 ENTER (file_field.send_keys(Keys.TAB)) 以更改焦点,但这会触发
selenium.common.exceptions.InvalidArgumentException: Message: invalid argument: File not found
(我输入的文件确实存在,路径没问题,可以成功调用.exists()。)
在send_keys之后简单地选择一个不同的元素来转移焦点(即customer_field.click())也不会触发file_field的onchange函数。
如何通过 Python 中的 Selenium 触发 onchange 事件? 或者确保它被触发?
【问题讨论】:
-
你怎么断定
onchange没有被解雇? -
@undetected Selenium 我有一个由 onchange 触发的函数。它在手动填充 file_field 时执行,但在使用 Selenium 填充时不会执行。所以我得出结论,onchange 没有发生。有不同的解释吗?
-
@undetectedSelenium 可以在上面的html代码中看到onchange-function:
onchange="checkFileFunction(this.value, &#x27;/ajax/check_file/&#x27;)"有没有办法显式检查是否触发了onchange?