I'm building my first ecommerce app, while attempting to gain more skills in Django. I have a form problem, where I am either adding a product, or editing one, using the same Template. My problem is where the action call drops part of the url when submitting POST back to the server ( right now, it's just the python manage.py runserver
).
When I go to edit, I see the url: http://127.0.0.1:8000/mystore/edit-product/4
When I edit the product and click submit, I get the Request URL: http://127.0.0.1:8000/mystore/edit-product/
page not found error.
This error prevents me from returning to the view to determine anything else. please note, I am missing the last part of the url (4
), which is the crux of my issue.
It looks like I'm missing something. This is what I have
userprofile/url.py
from django.urls import path
from django.contrib.auth import views as auth_views
from . import views
urlpatterns = [
path('signup/', views.signup, name='signup'),
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
path('login/', auth_views.LoginView.as_view(template_name='userprofile/login.html'), name='login'),
path('myaccount/', views.myaccount, name='myaccount'),
path('mystore/', views.my_store, name='my_store'),
path('mystore/add-product/', views.add_product, name='add-product'),
path('mystore/edit-product/<int:pk>', views.edit_product, name='edit-product'),
path('vendors/<int:pk>/', views.vendor_detail, name='vendor_detail')
]
store/urls.py
from django.urls import path
from . import views
urlpatterns =[
path('search/', views.search, name='search'),
path('<slug:slug>', views.category_detail, name='category_detail'),
path('<slug:category_slug>/<slug:slug>', views.product_detail, name='product_detail')
]
core/urls.py <-- the base urls
from django.urls import path,include
from .views import frontpage, about
urlpatterns =[
path('', include('userprofile.urls')),
path('', frontpage, name='frontpage'),
path('about', about, name='about'),
path('', include('store.urls'))
]
Views
@login_required
def add_product(request):
if request.method == 'POST':
form = ProductForm(request.POST, request.FILES)
if form.is_valid():
title = request.POST.get('title')
slug = slugify(title)
product = form.save(commit=False)
product.user = request.user
product.slug = slug
product.save()
return redirect('my_store')
else:
form = ProductForm()
return render(request, 'userprofile/add-product.html', {
'title': 'Add Product',
'form':form
})
@login_required
def edit_product(request, pk):
product = Product.objects.filter(user=request.user).get(pk=pk)
if request.method == 'POST':
form = ProductForm(request.POST, request.FILES, instance=product)
if form.is_valid():
form.save()
return redirect('my_store')
else:
form = ProductForm(instance=product)
return render(request, 'userprofile/add-product.html', {
'title': 'Edit Product',
'form': form
})
add-product.html (Note: template is used for both add and edit. the variable title
distinguishes from the two.)
{% extends 'core/base.html' %}
{% block title %}My Store{% endblock %}
{% block content %}
<h1 >My Store</h1>
<h2 >{{ title }}</h2>
<form method="post" action="." enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button >Save</button>
</form>
{% endblock %}
form.py
from django import forms
from .models import Product
class ProductForm(forms.ModelForm):
class Meta:
model = Product
fields = ('category', 'title', 'description', 'price', 'images', )
logs
[26/Dec/2022 20:27:32] "GET /mystore/edit-product/4 HTTP/1.1" 200 2690
Not Found: /mystore/edit-product/
[26/Dec/2022 20:27:47] "POST /mystore/edit-product/ HTTP/1.1" 404 5121
The not found indicates the response from pressing the "submit" button.
Thank you.
CodePudding user response:
Update:
For some reason, the relative path indicated in your form action, e.g. action="."
does not refer to your current page, but to it's parent "directory". Perhaps the "." means "current directory" and not "current URL". However, since the default action is performed at the current URL, you can simply omit the action property and it will submit at current URL.
Previous:
Looks like you are redirecting to a different page when the form is valid:
if form.is_valid():
form.save()
return redirect('my_store')
Sounds like you may want this branch to end with logic that renders your updated form rather than redirecting you somewhere. In this case, you are being redirected to a URL with no corresponding view, which is why you keep getting a 404 error message.
CodePudding user response:
Form, view, template, urls in general look fine.
I guess it's a result of a combination: relative url action="."
and page URL without trailing slash - path('mystore/edit-product/<int:pk>')
.
You can fix the issue these ways:
- put full url into form definition e.g.
action="{% url 'edit-product' product.pk %}"
- fix url pattern, add trailing slash
path('mystore/edit-product/<int:pk>/')
thus the page will be opened as/mystore/edit-product/4/
I guess since you render the same template for add and edit option 1 is a no go, so fix url pattern. For better support from Django enable option APPEND_SLASH in your settings.py
Here is a test:
If you open this question's page with trailing slash in the address https://stackoverflow.com/questions/74922497/post-action-drops-part-of-the-url-in-django-app/
code below would generate link with full page adress
<a href=".">relative link</a>
But if you omit trailing slash in the same page address (SO does not redirect and can show same page under both urls) then the same link "."
will address https://stackoverflow.com/questions/74922497/
Which is exactly your case.
Note, you have such url patterns without trailing slash in store/urls.py
as well.
ps while I was writing @DragonBobZ mentioned the same reason.
CodePudding user response:
I think that specifying an apt url in the form action of your 'add-product.html' would direct you to the desired page.
<form method="post" action="{% url 'appName: pathName'%}">
The path name would probably be anyone of the desired url specified in urls.py