NoReverseMatch 错误:在视图中使用 POST 请求未找到带参数 ‘my_url’ 的反向匹配。

huangapple go评论57阅读模式
英文:

Django HTMX NoReverseMatch Reverse for 'my_url' with arguments '('',)' not found using POST-request in view

问题

It appears that you're encountering a Django reverse URL resolution issue with your create_cv_workexp view. The error message suggests that the URL reverse for create_cv_workexp is being called with empty arguments.

One common reason for this issue is that the pk argument is not being passed correctly when you make a POST request to the create_cv_workexp view. In your JavaScript or HTML form, make sure you include the pk value as part of the POST request to this view. Double-check that the position.id value is correctly passed when making the POST request.

Here's a checklist to help you troubleshoot:

  1. Verify that position.id is correctly passed when making the POST request to create_cv_workexp.
  2. Check the JavaScript or HTML form that generates the POST request to ensure it includes the pk value.
  3. Make sure there are no typos or errors in the JavaScript or HTML form that could lead to incorrect URL construction.
  4. Ensure that the position.id is available in the context when rendering the template that contains the form.

If you've checked these points and the issue persists, please provide more information about how you're making the POST request and how the position.id is being passed, so I can offer more specific guidance.

英文:

I ran into the following issue on the Django framework using HTMX: 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']

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"]

Here are two models two models linked by a ForeignKey.

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",
        ]
    )

Here in view create_cv_workexp after POST-request i do redirect to url 'resume:detail-workexp' and pass to url the parameter pk which refers to id just saved the instance of object WorkExperience. Then the view create_cv_workexp must be rendres 'resume/create_cv_workexp.html' template because 'resume:detail-workexp' uses dynamic template (about this is next).

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'),
]

The detail-workexp url calls view detail_workexp in views.py:

@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>

Here is template 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 %}

Here is template 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>

I think i passed all parameters from views to templates and urls, but when i mare POST-request from create_cv_view view i get exception:

Reverse for 'create_cv_workexp' with arguments '('',)' not found. 1 pattern(s) tried: ['create\\-cv\\-workexp/(?P<pk>[0-9]+)/\\Z']

I dont know why reverse for create_cv_workexp view is not working because i pass to url the id of Position object

Next is some screens about this exception:

NoReverseMatch 错误:在视图中使用 POST 请求未找到带参数 ‘my_url’ 的反向匹配。

NoReverseMatch 错误:在视图中使用 POST 请求未找到带参数 ‘my_url’ 的反向匹配。

NoReverseMatch 错误:在视图中使用 POST 请求未找到带参数 ‘my_url’ 的反向匹配。

The headers of request and response:

NoReverseMatch 错误:在视图中使用 POST 请求未找到带参数 ‘my_url’ 的反向匹配。

NoReverseMatch 错误:在视图中使用 POST 请求未找到带参数 ‘my_url’ 的反向匹配。

NoReverseMatch 错误:在视图中使用 POST 请求未找到带参数 ‘my_url’ 的反向匹配。

Here is full traceback of exception:

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

So i really don't know what's wrong... I didn't find the solution in Stack Overflow and other sources... Please help!!!

答案1

得分: 0

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">
            提交
        </button>
        {% endif %}
else:
            return render(request, "resume/partials/workexp_form.html", context={
                "form": form
            })
英文:

in workexp_form.html you also use position but it is not in the context:

        {% 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
            })

huangapple
  • 本文由 发表于 2023年5月18日 03:12:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/76275497.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定