我希望在Django
和htmx
创建一个动态网站,该网站具有搜索栏,用户可以在其中输入关键字并获得搜索结果,而无需重新加载页面。为此,我打算使用 htmx .提交搜索栏不是通过提交按钮完成的,而是通过键盘上的Enter
键完成的。提交此搜索栏时,它会通过POST
方法将输入的关键字发送到 Django 的views.py
文件中,该方法将负责将结果返回到地址localhost:8000/search
和搜索栏页面上。这是我views.py
文件的内容:
from django.shortcuts import render
import requests
from bs4 import BeautifulSoup as bs
from search.models import MyForm
def index(request):
return render(request, 'index.html')
def search(request):
if request.method == 'POST':
search = request.POST['search']
form = MyForm(request.POST)
max_pages_to_scrap = 15
final_result = []
for page_num in range(1, max_pages_to_scrap+1):
url = "https://www.ask.com/web?q=" + search + "&qo=pagination&page=" + str(page_num)
res = requests.get(url)
soup = bs(res.text, 'lxml')
result_listings = soup.find_all('div', {'class': 'PartialSearchResults-item'})
for result in result_listings:
result_title = result.find(class_='PartialSearchResults-item-title').text
result_url = result.find('a').get('href')
result_desc = result.find(class_='PartialSearchResults-item-abstract').text
final_result.append((result_title, result_url, result_desc))
context = {'final_result': final_result, 'form':form}
return render(request, 'index.html', context)
else:
return render(request, 'index.html')
它是刮擦 Ask.com 站点的刮板。对于将发送给用户的提交表单,我首先尝试了以下方法:
<form method="POST" action="search">
...
<input type="search" name="search" hx-post="/search" hx-target="#results" hx-trigger="keyup changed delay:500ms" value="{{form.search.value}}" placeholder="Search here..." autofocus x-webkit-speech/>
</form>
当用户提交此表单时,输入的关键字将通过POST
方法发送到 Djangoviews.py
文件,这负责返回结果。
我试图替换:
<form method="POST" action="search">
...
<input type="search" name="search" hx-post="/search" hx-target="#results" hx-trigger="keyup changed delay:500ms" value="{{form.search.value}}" placeholder="Search here..." autofocus x-webkit-speech/>
</form>
由:
<input type="search" name="search" hx-post="/search" hx-target="#results" hx-sync="closest form:abort" hx-trigger="keyup changed delay:500ms" value="{{form.search.value}}" placeholder="Search here..." autofocus x-webkit-speech/>
</form>
我也试过这个:
<! DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<script src="https://unpkg.com/htmx.org@1.7.0" integrity="sha384-EzBXYPt0/T6gxNp0nuPtLkmRpmDBbjg6WmCUZRLXBBwYYmwAUxzlSGej0ARHX0Bo" crossorigin="anonymous"></script>
. . .
<title>Search page</title>
</head>
<body>
<div class="search">
<div class="header">
<header >
{% csrf_token %}
<input type="search" name="search" hx-sync="closest form:abort" hx-post="/search" hx-target="#results" hx-trigger="keyup changed delay:500ms" value="{{form.search.value}}" placeholder="Search here..." autofocus x-webkit-speech/>
</header>
</div>
</div>
<div id="results">
{% if final_result %}
<b style="padding-left: 50px; padding-right: 50px; color: #646464;">Web Results</b>
{% for result in final_result %}
<div style="padding-left: 50px; padding-right: 50px;">
<h3 style="color: blue; font-size:20px; "><a href="{{ result.1 }}">{{ result.0 }}</a></h3>
<h3 style="color: green; font-size:14px;">{{ result.1 }}</h3>
<h3 style="font-size:17.25px; " >{{ result.2 }}</h3>
</div><br><br>
{% endfor %}
{% endif %}
</div>
</body>
</html>
但没有成功。
根据更多信息更新了答案。
您需要考虑您的页面要求和返回的内容。
HTMX是一种通过ajax请求信息的方式,没有多余的javascript等。 我们将响应放入现有页面中,因此我们想要html,但我们不想要整个页面的HTML - 只是新部分。
你的 django 模板 index.html 由服务器提供。 它不知道 ajax 返回了什么,因为这都是在服务器交付 index.html之后发生的,所以你不能使用它格式化新的 HTML(除非你重新加载整个页面,这违背了使用 HTMX 的重点)
假设您有一个页面,我们将其称为/index 以供参考。 它调用 htmx 代码,以便我们可以使用它。放在索引.html的<head>
部分。
<script src="https://unpkg.com/htmx.org@1.7.0" integrity="sha384-EzBXYPt0/T6gxNp0nuPtLkmRpmDBbjg6WmCUZRLXBBwYYmwAUxzlSGej0ARHX0Bo" crossorigin="anonymous"></script>
在此之下,以及在<head>
seaction(来自各种文档)中,我们将放入以下内容,以确保我们将必要的CSRF令牌链接到htmx ajax帖子
<script>
document.body.addEventListener('htmx:configRequest', (event) => {
event.detail.headers['X-CSRFToken'] = '{{ csrf_token }}';
})
</script>
在该页面上,您还有一个htmx搜索字段。 我们将使用您的
<input type="search" name="search"
hx-post="/search" hx-target="#results"
hx-trigger="keyup changed delay:500ms"
value="{{form.search.value}}" placeholder="Search here..."
autofocus x-webkit-speech/>
您的hx触发器显示,在键入或更改时(键入,单击或按回车键后,等待半秒钟后)提交到视图域/搜索并将结果放入<div id="results"></div>
显然,我们需要确保域/搜索在 urls.py 中有一个条目,以便可以找到视图。
现在 - 因为我们希望这一切都在不加载页面的情况下发生,所以我们不能指望 django 的 index.html 模板来处理格式(服务器已经完成了将页面交付到浏览器的工作,我们不想重新加载整个页面和索引.html是整个页面的 HTML)。 所以我们的/search 必须使用另一个模板来渲染 html。我们称之为搜索.html
搜索.html
{% if final_result %}
<b style="padding-left: 50px; padding-right: 50px; color: #646464;">Web Results</b>
{% for result in final_result %}
<div style="padding-left: 50px; padding-right: 50px;">
<h3 style="color: blue; font-size:20px; "><a href="{{ result.1 }}">{{ result.0 }}</a></h3>
<h3 style="color: green; font-size:14px;">{{ result.1 }}</h3>
<h3 style="font-size:17.25px; " >{{ result.2 }}</h3>
</div><br><br>
{% endfor %}
{% endif %}
我们在 views.py 搜索中称之为索引而不是索引.html
return render(request, 'search.html', context) #context includes final_result
因此,在这种情况下,我们返回的是一个 HTML片段而不是整个页面,这就是应该显示在结果div 中的内容。