imartov
imartov

Reputation: 27

django redirect url Not Found 404 during working with dynamic forms HTMX

In the view function, I redirect when making a post-request to refer-urk, to which I pass the id of the saved class instance, however, this id is lost and I get 404 Not Found.

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 Contacts(models.Model):
    pos = models.ForeignKey('Position', blank=True, null=True, on_delete=models.SET_NULL, verbose_name='Position')
    contact_label = models.CharField(max_length=100, blank=True, verbose_name='Contact label')
    contact_value = models.CharField(max_length=255, blank=True, verbose_name='Contact value')

    def __str__(self):
        return self.contact_label

forms.py:

class CreateCVContactForm(forms.ModelForm):
    class Meta:
        model = resume.models.Contacts
        fields = (
            'contact_label',
            'contact_value'
        )

In views.py usnig def createcvcontacts i do redirect for POST-request and pas id of saved object instance to url and then with HTMX i get this id in def ditailcontact which renders detail info abot object instance and pass context to contact_detail.html template:

views.py:

@login_required(login_url='/users/login/')
def create_cv_contacts(request, pk):
    ''' functions for working with models.Contacts '''

    position = Position.objects.get(id=pk)
    contacts = Contacts.objects.filter(pos=position)
    form = CreateCVContactForm(request.POST or None)

    if request.method == "POST":
        if form.is_valid():
            contact = form.save(commit=False)
            contact.pos = position
            contact.save()
            return redirect("resume:detail-contact", pk=contact.id) # here this redirect
        else:
            return render(request, "resume/partials/contact_form.html", context={
                "form": form
            })

    context = {
        "form": form,
        "position": position,
        "contacts": contacts,
        'title': 'Add contacts'
    }

    return render(request, "resume/create_cv_contacts.html", context)


@login_required(login_url='/users/login/')
def update_contact(request, pk):
    contact = Contacts.objects.get(id=pk)
    form = CreateCVContactForm(request.POST or None, instance=contact)

    if request.method == "POST":
        if form.is_valid():
            form.save()
            return redirect("resume:detail-contact", pk=contact.id)

    context = {
        "form": form,
        "contact": contact
    }

    return render(request, "resume/partials/contact_form.html", context)


@login_required(login_url='/users/login/')
def delete_contact(request, pk):
    contact = get_object_or_404(Contacts, id=pk)

    if request.method == "POST":
        contact.delete()
        return HttpResponse("")

    return HttpResponseNotAllowed(
        [
            "POST",
        ]
    )


@login_required(login_url='/users/login/')
def detail_contact(request, pk):
    contact = get_object_or_404(Contacts, id=pk)
    context = {
        "contact": contact
    }
    return render(request, "resume/partials/contact_detail.html", context)


@login_required(login_url='/users/login/')
def create_contact_form(request):
    form = CreateCVContactForm()
    context = {
        "form": form
    }
    return render(request, "resume/partials/contact_form.html", context)

urls.py, url name is detail-contact i get this id of saved instance:

app_name = 'resume'
urlpatterns = [
    path('', views.main_page, name='main_page'),
    path('list/', views.IndexView.as_view(), name='index'),
    path('<int:pk>/', views.GetResume.as_view(), name='get_person'),
    path('create-cv-pers-data/', views.create_cv_personal_data, name='create_cv_personal_data'),
    # path('create-cv-position/', views.CreateCVPosition.as_view(), name='create_cv_position'),
    path('create-cv-position/', views.create_cv_position, name='create_cv_position'),

    # paths for working with Contacts objects
    path('create-cv-contacts/<int:pk>', views.create_cv_contacts, name='create_cv_contacts'), # here is url for GET-request in def create_cv_contacts
    path('htmx/contact/<pk>/', views.detail_contact, name="detail-contact"), # here i get this id of saved instance
    path('htmx/contact/<pk>/update/', views.update_contact, name="update-contact"),
    path('htmx/contact/<pk>/delete/', views.delete_contact, name="delete-contact"),
    path('htmx/create-contact-form/', views.create_contact_form, name='create-contact-form'),
]

templates:

createcvcontacts.html*,* this template is rendered during at runtime GET-request of def create_cv_contatcs:

{% extends 'resume/base.html' %}
{% load static %}

{% block content %}

    <div class="md:flex md:items-center md:justify-between">
        <div class="flex-1 min-w-0">
            <h2 class="text-2xl font-bold leading-7 text-gray-900 sm:text-3xl sm:truncate">
                Add contacts for {{ position.position_name }}
            </h2>
        </div>
        <div class="mt-4 flex md:mt-0 md:ml-4">
            <button type="button" hx-get="{% url 'resume:create-contact-form' %}" hx-target="#contactforms" hx-swap="beforeend"
                class="ml-3 inline-flex items-center px-4 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">
                Add form
            </button>
        </div>
    </div>


    <div id="contactforms" class="py-5 mt-5"></div>

    <div class="mt-5 py-5 border-t border-gray-100">
        {% for contact in contacts %}

        {% include "resume/partials/contact_detail.html" %}

        {% endfor %}
    </div>

{% endblock %}

contact_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">
        Contact label: {{ contact.contact_label }}
    </h3>
    <p class="text-gray-600">Contact: {{ contact.contact_value }}</p>
    <div class="mt-2">
        <button hx-get="{% url 'resume:update-contact' contact.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-contact' contact.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 headers of request (the URL doesn't have id):

enter image description here

And here is the mesage from console:

Not Found: /create-cv-contacts/

[08/May/2023 21:41:26] "POST /create-cv-contacts/ HTTP/1.1" 404 4149

Here i use HTMX. I got tutorial of this one from this video https://www.youtube.com/watch?v=KVq_DjIfnBo and here all is work.

I didn't find solution of my problem in Stack Owerflow, please help me

Upvotes: 0

Views: 125

Answers (1)

KingRanTheMan
KingRanTheMan

Reputation: 740

Please post the partial HTML you are using in "resume/partials/contact_form.html".

My guess is you are doing an hx-post in there, but you're not including the appropriate position.id variable inside the hx-post value. E.g. it should look like the below:

<button hx-post="{% url 'resume:create_cv_contacts' position.id %}" ...>
    Create
</button>

I suspect the position.id is missing from the above.


You will probably need to include this position.id dynamically, in which case you will need to adjust the contact_form view, url and templates as follows:

Change the Add Form button as below:

<button type="button" hx-get="{% url 'resume:create-contact-form' position.id %}" ...>
    Add form
</button>

Change the 'create-contact-form' URL as follows:

path('htmx/create-contact-form/<int:pk>/', views.create_contact_form, name='create-contact-form')

Change the create_contact_form View as follows:

@login_required(login_url='/users/login/')
def create_contact_form(request, pk):
    form = CreateCVContactForm()
    position = {"id": pk}  # add this
    context = {
        "form": form,
        "position": position,  # add this
    }
    return render(request, "resume/partials/contact_form.html", context)

Now make sure you have this position.id inside your hx-post on the create_form.html itself (as at the top of this post), and hopefully it should work. Let me know if not.

Upvotes: 0

Related Questions