我在使用 HTMX 的 Django 框架上遇到了以下问题:django.urls.exceptions.NoReverseMatch: Reverse for 'create_cv_workexp' with arguments '('',)' not found。尝试了 1 种模式:['create\-cv\-workexp/(?P
models.py:
class Position(models.Model):
position_name = models.CharField(max_length=255, blank=True, verbose_name='Position')
created_by = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='user by', blank=True, null=True)
date_create = models.DateTimeField(auto_now_add=True)
date_update = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['date_create']
def __str__(self):
return self.position_name
class WorkExperience(models.Model):
pos = models.ForeignKey('Position', blank=True, null=True, on_delete=models.SET_NULL, verbose_name='Position Relative')
company = models.CharField(max_length=50, verbose_name='Company', blank=True)
position_work = models.CharField(max_length=50, verbose_name='Position', blank=True)
link_company = models.URLField(verbose_name="Company's link", blank=True)
date_of_employment = models.DateField(blank=True, verbose_name='Date of employment')
date_of_dismissal = models.DateField(blank=True, verbose_name='Date of dismissal')
def __str__(self):
return self.company
class Meta:
ordering = ["-date_of_employment"]
这里有两个模型,两个模型通过外键链接。
forms.py:
class CreateCVWorkExperienceForm(forms.ModelForm):
''' form for WorkExperience object '''
class Meta:
model = resume.models.WorkExperience
fields = ('company',
'position_work',
'link_company',
'date_of_employment',
'date_of_dismissal')
views.py:
@login_required(login_url='/users/login/')
def create_cv_workexp(request, pk):
''' main views for displaying form for to add WorkExperience to CV and redirect to HTMX template '''
position = Position.objects.get(id=pk)
workexps = WorkExperience.objects.filter(pos=position)
form = CreateCVWorkExperienceForm(request.POST or None)
if request.method == "POST":
if form.is_valid():
workexp = form.save(commit=False)
workexp.pos = position
workexp.save()
pk = workexp.pk
return redirect("resume:detail-workexp", pk=pk)
else:
return render(request, "resume/partials/workexp_form.html", context={
"form": form
})
context = {
"form": form,
"position": position,
"workexps": workexps,
'title': 'Add company'
}
return render(request, "resume/create_cv_workexp.html", context)
@login_required(login_url='/users/login/')
def create_workexp_form(request, pk):
''' view for rendering form of WorkExperience object for adding instnce during creating CV '''
form = CreateCVWorkExperienceForm()
position = {"id": pk}
context = {
"form": form,
"position": position,
}
return render(request, "resume/partials/workexp_form.html", context)
@login_required(login_url='/users/login/')
def detail_workexp(request, pk):
''' view for rendering added WorkExperience to DB and displaying it on 'resume/create_cv_workexp.html' template '''
workexp = get_object_or_404(WorkExperience, pk=pk)
context = {
"workexp": workexp,
'pk': pk
}
return render(request, "resume/partials/workexp_detail.html", context)
@login_required(login_url='/users/login/')
def update_workexp(request, pk):
''' view for updating added WorkExperience '''
workexp = WorkExperience.objects.get(id=pk)
form = CreateCVWorkExperienceForm(request.POST or None, instance=workexp)
if request.method == "POST":
if form.is_valid():
form.save()
return redirect("resume:detail-workexp", pk=workexp.id)
context = {
"form": form,
"workexp": workexp
}
return render(request, "resume/partials/workexp_form.html", context)
@login_required(login_url='/users/login/')
def delete_workexp(request, pk):
''' view for delete instance of WorkExperience object '''
workexp = get_object_or_404(WorkExperience, id=pk)
if request.method == "POST":
workexp.delete()
return HttpResponse("")
return HttpResponseNotAllowed(
[
"POST",
]
)
在POST-request之后查看create_cv_workexp我确实重定向到url'resume:detail-workexp'并将参数pk传递给url,它指的是id刚刚保存了对象WorkExperience的实例。然后视图 create_cv_workexp 必须是 rendres 'resume/create_cv_workexp.html' 模板,因为 'resume:detail-workexp' 使用动态模板(关于这个是下一个)。
urls.py:
app_name = 'resume'
urlpatterns = [
...
# paths for working with WorWorkExperience objects during creating CV
path('create-cv-workexp/<int:pk>/', views.create_cv_workexp, name='create_cv_workexp'), # here
path('htmx/workexp/<int:pk>/', views.detail_workexp, name="detail-workexp"), # and here
path('htmx/workexp/<int:pk>/update/', views.update_workexp, name="update-workexp"),
path('htmx/workexp/<int:pk>/delete/', views.delete_workexp, name="delete-workexp"),
path('htmx/create-workexp-form/<int:pk>/', views.create_workexp_form, name='create-workexp-form'),
]
detail-workexp url在views.py中调用视图detail_workexp:
@login_required(login_url='/users/login/')
def detail_workexp(request, pk):
''' view for rendering added WorkExperience to DB and displaying it on 'resume/create_cv_workexp.html' template '''
workexp = get_object_or_404(WorkExperience, pk=pk)
context = {
"workexp": workexp,
'pk': pk
}
return render(request, "resume/partials/workexp_detail.html", context)
This view rendres template workexp_detail.html:
<div hx-target="this" class="mt-3 py-3 px-3 bg-white shadow border border-gray-100">
<h3 class="text-lg leading-6 font-medium text-gray-900">
Company: {{ workexp.company }}
</h3>
<p class="text-gray-600">Position: {{ workexp.position_work }}</p>
<div class="mt-2">
<button hx-get="{% url 'resume:update-workexp' workexp.id %}" hx-swap="outerHTML"
class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-indigo-700 bg-indigo-100 hover:bg-indigo-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
Update
</button>
<button hx-post="{% url 'resume:delete-workexp' workexp.id %}" hx-swap="outerHTML swap:1s"
class="ml-2 inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-red-700 bg-red-100 hover:bg-red-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500">
Delete
</button>
</div>
</div>
这里是模板create_cv_workexp.html:
{% extends 'resume/base.html' %}
{% block content %}
<h2>Add work experience for {{ position.position_name }}</h2>
<hr>
<div class="container">
<button type="button" hx-get="{% url 'resume:create-workexp-form' position.id %}" hx-target="#workexpform" hx-swap="beforeend">
Add work experience
</button>
</div>
<div id="workexpform" class="container"></div>
<div class="container">
{% for workexp in workexps %}
{% include 'resume/partials/workexp_detail.html' %}
{% endfor %}
</div>
{% endblock content %}
这是模板workexp_form.html:
{% load tailwind_filters %}
<div hx-target="this" hx-swap="outerHTML" class="mt-3 py-3 px-3 bg-white shadow border border-gray-100">
<form method="POST">
{% csrf_token %}
{{ form|crispy }}
{% if workexp %}
<button type="submit" hx-post="{% url 'resume:update-workexp' workexp.id %}"
class="inline-flex items-center px-3 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
Submit
</button>
<button hx-get="{% url 'resume:detail-workexp' workexp.id %}" type="button"
class="ml-2 inline-flex items-center px-3 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
Cancel
</button>
{% else %}
<button type="submit" hx-post="{% url 'resume:create_cv_workexp' position.id %}"
class="inline-flex items-center px-3 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
Submit
</button>
{% endif %}
</form>
</div>
我想我将所有参数从 views 传递到模板和 url,但是当我从 create_cv_view 视图中获取 POST-request 时,我得到异常:
Reverse for 'create_cv_workexp' with arguments '('',)' not found. 1 pattern(s) tried: ['create\\-cv\\-workexp/(?P<pk>[0-9]+)/\\Z']
我不知道为什么 create_cv_workexp 视图的反向不起作用,因为我将 Position 对象的 id 传递给 url
接下来是关于这个异常的一些屏幕:
请求头和响应头:
这里是异常的完整回溯:
Internal Server Error: /create-cv-workexp/3/
Traceback (most recent call last):
File "D:\virtualenv\mysite\Lib\site-packages\django\core\handlers\exception.py", line 55, in inner
response = get_response(request)
^^^^^^^^^^^^^^^^^^^^^
File "D:\virtualenv\mysite\Lib\site-packages\django\core\handlers\base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\virtualenv\mysite\Lib\site-packages\django\contrib\auth\decorators.py", line 23, in _wrapper_view
return view_func(request, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\python_projects\my_site\mysite\resume\views.py", line 286, in create_cv_workexp
return render(request, "resume/partials/workexp_form.html", context={
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\virtualenv\mysite\Lib\site-packages\django\shortcuts.py", line 24, in render
content = loader.render_to_string(template_name, context, request, using=using)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\virtualenv\mysite\Lib\site-packages\django\template\loader.py", line 62, in render_to_string
return template.render(context, request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\virtualenv\mysite\Lib\site-packages\django\template\backends\django.py", line 61, in render
return self.template.render(context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\virtualenv\mysite\Lib\site-packages\django\template\base.py", line 175, in render
return self._render(context)
^^^^^^^^^^^^^^^^^^^^^
File "D:\virtualenv\mysite\Lib\site-packages\django\template\base.py", line 167, in _render
return self.nodelist.render(context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\virtualenv\mysite\Lib\site-packages\django\template\base.py", line 1005, in render
return SafeString("".join([node.render_annotated(context) for node in self]))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\virtualenv\mysite\Lib\site-packages\django\template\base.py", line 1005, in <listcomp>
return SafeString("".join([node.render_annotated(context) for node in self]))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\virtualenv\mysite\Lib\site-packages\django\template\base.py", line 966, in render_annotated
return self.render(context)
^^^^^^^^^^^^^^^^^^^^
File "D:\virtualenv\mysite\Lib\site-packages\django\template\defaulttags.py", line 321, in render
return nodelist.render(context)
^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\virtualenv\mysite\Lib\site-packages\django\template\base.py", line 1005, in render
return SafeString("".join([node.render_annotated(context) for node in self]))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\virtualenv\mysite\Lib\site-packages\django\template\base.py", line 1005, in <listcomp>
return SafeString("".join([node.render_annotated(context) for node in self]))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\virtualenv\mysite\Lib\site-packages\django\template\base.py", line 966, in render_annotated
return self.render(context)
^^^^^^^^^^^^^^^^^^^^
File "D:\virtualenv\mysite\Lib\site-packages\django\template\defaulttags.py", line 471, in render
url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\virtualenv\mysite\Lib\site-packages\django\urls\base.py", line 88, in reverse
return resolver._reverse_with_prefix(view, prefix, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\virtualenv\mysite\Lib\site-packages\django\urls\resolvers.py", line 828, in _reverse_with_prefix
raise NoReverseMatch(msg)
django.urls.exceptions.NoReverseMatch: Reverse for 'create_cv_workexp' with arguments '('',)' not found. 1 pattern(s) tried: ['create\\-cv\\-workexp/(?P<pk>[0-9]+)/\\Z']
[17/May/2023 21:00:03] "POST /create-cv-workexp/3/ HTTP/1.1" 500 150333
所以我真的不知道出了什么问题...我没有在 Stack Overflow 和其他资源中找到解决方案...请帮忙!!!
在 workexp_form.html 你也使用
position
但它不在上下文中:
{% else %}
<button type="submit" hx-post="{% url 'resume:create_cv_workexp' position.id %}"
class="inline-flex items-center px-3 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
Submit
</button>
{% endif %}
else:
return render(request, "resume/partials/workexp_form.html", context={
"form": form
})