post action drops part of the url in django app - python

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 class="text-2xl">My Store</h1>
<h2 class="mt-6 text-xl ">{{ title }}</h2>
<form method="post" action="." enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button class="mt-6 py-4 px-8 bg-teal-500 text-white hover:bg-teal-800">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.

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.

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
relative link
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.

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

Related

Django UserCreationForm not responding when button clicked with input in fields

I'm having trouble getting my register application in Django to work. I am using the built-in UserCreationForm form. I can go to the URL and the form shows up but when I put info into the fields and click the submit button nothing happens. It should pop up an error screen saying "missing the csrf_field" (I know this because I'm following TechWithTim's tutorial and that's what happens to him). But when I click the "Register" button nothing happens.
views.py:
from django.shortcuts import render
from django.contrib.auth.forms import UserCreationForm
# Create your views here.
def register(response):
form = UserCreationForm()
return render(response, "register/register.html", {"form":form})
register.html:
{% extends "main/base.html" %}
{% block title %}Create an Account{% endblock %}
{% block content %}
<form method="POST" class="form-group">
{{form}}
<button type="submit" class="btn btn-success">Register</button>
</form>
{% endblock %}
urls.py:
from django.contrib import admin
from django.urls import path, include
from register import views as v
urlpatterns = [
path('', include("main.urls")),
path("register/", v.register, name="register"),
path('admin/', admin.site.urls),
]
main/urls.py
from django.urls import path
from . import views
urlpatterns = [
path("<int:id>", views.index, name='index'),
path("", views.home, name='home'),
path("create/", views.create, name='create'),
]
I added the application to my settings.py file as well.
This is my first question on here and I tried to format it properly so sorry if I didn't
In order for Django to recieve the data the user entered in the form, you need to pass the request's POST data to the form, if it exists. That would look like this:
form = UserCreationForm(response.POST)
But note that response.POST will not exist if it's not a POST request. (For example, if the user is viewing the form for the first time.) The Django docs have an example of how to process form data.
Alternatively, you can look at the tutorial you're using, which has an example of how to get the POST data out of the form:
# views.py
from django.shortcuts import render, redirect
from .forms import RegisterForm
# Create your views here.
def register(response):
if response.method == "POST":
form = RegisterForm(response.POST)
if form.is_valid():
form.save()
return redirect("/home")
else:
form = RegisterForm()
return render(response, "register/register.html", {"form":form})
(Source.)

My Model form for Django is not saving because it's invalid but I can't see what's wrong

I'm very new to Django and part of the assignment was to create our own blog model form. I followed the previous examples of the youtube tutorial but was unable to create my own blog model form. The form will not save because it's invalid and I have been busting my head for 2 days to solve it but can't find what is wrong.
Also, every time I submit my form, it redirects me to another page which I don't quite understand why.
Please help.
I'm using Django version 2.0.7.
My models.py
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=120) # Max length required
content = models.TextField()
active = models.BooleanField(default=True)
My forms.py
from django import forms
from .models import Article
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = [
'title',
'content',
'active'
]
my views.py
from django.shortcuts import render, get_object_or_404, redirect
from .forms import ArticleForm
from .models import Article
def article_list_view(request):
print("this is article_list.html")
queryset = Article.objects.all()
context ={
"object_list": queryset
}
return render(request, "blogs/article_list.html", context)
def article_create_view(request):
form = ArticleForm(request.POST or None)
print(ArticleForm.errors)
if form.is_valid():
print("Valid form")
form.save()
else:
print("invalid")
print(ArticleForm.errors)
context = {
"form": form
}
return render(request, "blogs/article_create.html", context)
article_create.html
{% extends 'base.html' %}
{% block content %}
<form action='.' method='POST'>{% csrf_token %}
{{ form.as_p }}
<input type='submit' value='Save'>
</form>
{% endblock %}
urls.py
from django.contrib import admin
from django.urls import include, path
from pages.views import (
home_view,
contact_view,
about_view,
social_view
)
from blog.views import (
article_list_view,
article_detail_view,
article_create_view
)
urlpatterns = [
path('products/', include('products.urls')),
path('', home_view, name='home'),
path('contact/', contact_view, name='contact'),
path('about/', about_view, name='product-detail'),
path('social/', social_view, name='social'),
path('admin/', admin.site.urls),
#blog paths
path('articles/', article_list_view, name = 'articles'),
path('articles/detail/<int:id>', article_detail_view, name = 'article-detail'),
path('articles/create', article_create_view, name = 'article-create'),
]
This shows up on my command prompt of my server:
Django version 2.0.7, using settings 'trydjango.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
<property object at 0x000001ED94386458>
invalid
<property object at 0x000001ED94386458>
[18/Apr/2019 22:33:51] "GET /articles/create HTTP/1.1" 200 920
this is article_list.html
[18/Apr/2019 22:34:02] "POST /articles/ HTTP/1.1" 200 668
As soon as I land onto the articles/create or article_create.html, the <property object at 0x000001ED94386458> shows up.
1) You should not use .errors on the class.
ArticleForm.errors
should be
form.errors
2) You should separate your GET and POST requests in your view.
def article_create_view(request):
if request.method == "POST":
form = ArticleForm(request.POST)
if form.is_valid():
print("Valid form")
form.save()
else:
print("Invalid form")
print(form.errors)
else:
form = ArticleForm()
context = {"form": form)
return render(request, "blogs/article_create.html", context)
Your form should be posting to "", not ".".
<form action='' method='POST'>{% csrf_token %}
Alternatively/additionally, make sure you originally navigate to /articles/create/, not /articles/create without the final slash. (Although normally the built-in CommonMiddleware will take care of redirecting to the path with the slash - have you set the APPEND_SLASH setting to False by any chance? Don't.)

Is there a better way to move between Django's views aside from pasting new url?

I'm learning to use Django to build my web application. I want to access another page through a link on the index page, but the browser keeps appending the file and app name to the request.
How do I get the browser to switch through links without appending the directory name each time ?
I've tried using reg exp with the old url method but it doesn't seem to work
# My project
# urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('index.urls')),
]
# My app
# urls.py
urlpatterns = [
path('index/',include([
path('', views.index,name="index"),
path('theteam', views.theteam,name="theteam"),
path('services',views.services,name="services"),
path('quotes',views.quotes,name="quotes"),
path('insurance',views.insurance,name="insurance"),
path('contact',views.contact,name="contact"),
path('thanks', views.thanks,name="thanks"),
])),
]
# Views
def index(request):
return render(request, 'index/index.html')
def theteam(request):
return render(request, 'index/theteam.html')
def services(request):
return render(request, 'index/services.html')
def quotes(request):
form = ContactForm(request.POST or None)
if request.method == 'POST':
return redirect(request, '/thanks/')
return render(request, 'index/quotes.html', { 'form': form })
def insurance(request):
return render(request, 'index/insurance.html')
def contact(request):
return render(request, 'index/contact.html')
def thanks(request):
return render(request, '/thanks.html')
#My Views HTML
<div class="menu-bar ">
<ul>
<li>Services</li>
<li>The Team</li>
<li>Quotes</li>
<li>Insurance</li>
<li>Contact Us</li>
</ul>
</div>
So far I've been able to visit each page by simply pasting "/index/template/" into the browser but I can't switch between using the links. MY expected result is to be able to switch between pages using the links.
In your apps urls.py, add a line above urlpatterns that looks like:
app_name = your_app_name
Then, in your html file, change
{% url 'services' %}
to
{% url 'your_app_name:services' %}

Django: forms not visible on the webpage

I am trying to create a simple Django webpage that uses forms, but my forms are not visible. I have read all of the Django docs and read multiple questions related to this issue, but I have found no solution that fixes my problem.
Here are the relevant files:
views.py
from django.shortcuts import render
from .forms import FileForm
with open('calendar.txt') as f:
file_content = f.read()
def home(request):
return render(request, 'main/index.html',{'file_content':file_content})
def form_get(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = FileForm(request.POST)
# check whether it's valid:
if form.is_valid():
pass
else:
form = FileForm()
return render(request, 'index.html', {'form': FileForm.form})
urls.py
from django.conf.urls import url
from django.contrib import admin
from main import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', views.home, name='home'),
]
index.py
{% extends "base.html" %}
{% block content %}
<h1>Welcome to the calendar!</h1>
<form action="/#" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>
{{form}}
{% endblock content %}
Link to program
From what I have read, I suspect there may be an issue in the urls.py file, but I've been looking over it many times and I haven't found anything wrong. Any thoughts?
Try
def form_get(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = FileForm(request.POST)
# check whether it's valid:
if form.is_valid():
pass
else:
form = FileForm()
return render(request, 'main/index.html', {'form': form})
See how I changed the context for the render from {'form': FileForm.form} to {'form': form}. The path to the index.html file was also wrong.
After fixing the view, you need to add an actual URL to go to it. Your current URL has
url(r'^$', views.index, name='home'),
Note how is using views.index and not views.form_get. Change the URL to use form_get and it will work.
url(r'^$', views.form_get, name='home'),
Don't know if you want to have / go to the form, or if you would rather have / still go to home, where you have a link to the form. But in that case, you do not want to share the same index.html file.
But seems like you may be trying to merge those two, but in that case, you need a single view, which can both show the content of the file, and ask for the file. But will be easier if you have two views, and leave the form to just take the input, and then redirect to the second view to show the results.

Cannot find url

I got an error that,
Page not found (404)
Request Method: GET
Request URL: `http://localhost:8000/accounts/registration/accounts/registration/accounts/registration/accounts/profile.html` .
I think routes are wrong But I cannot understand how to fix the routes.
In accounts app,I wrote
in urls.py
from django.conf.urls import url
from . import views
from django.contrib.auth.views import login, logout
urlpatterns = [
url(r'^login/$', login,
{'template_name': 'registration/accounts/login.html'},
name='login'),
url(r'^logout/$', logout, name='logout'),
url(r'^regist/$', views.regist,name='regist' ),
url(r'^regist_save/$', views.regist_save, name='regist_save'),
url(r'^registration/accounts/registration/accounts/profile.html$', views.regist_save, name='regist_save'),
]
in views.py
#require_POST
def regist_save(request):
form = RegisterForm(request.POST)
if form.is_valid():
user = form.save()
login(request, user)
context = {
'user': request.user,
}
return redirect('registration/accounts/profile.html', context)
context = {
'form': form,
}
return render(request, 'registration/accounts/regist.html', context)
in accounts(child app)/templates/registration/accounts/profile.html directory,
{% extends "registration/accounts/base.html" %}
{% block content %}
user.username: {{ user.username }}<hr>
user.is_staff: {{ user.is_staff }}<hr>
user.is_active: {{ user.is_active }}<hr>
user.last_login: {{ user.last_login }}<hr>
user.date_joined: {{ user.date_joined }}
{% endblock %}
You have some serious misunderstandings here.
You can't have a template without a view. You have written a template for the profile, but you haven't written a view. You need the view that loads the profile data and then renders the profile.html template.
Secondly, your URL has nothing to do with the template location; as you have done in regist_save, you should define a sensible URL pointing to that view - for the profile, you probably want something like r'^profile/$'.
So, the fifth entry in your urls.py should be:
url(r'^profile/$', views.profile, name='profile'),
and you need a corresponding function named profile in views.py.
Finally, when you redirect you need to use an actual URL entry - again, it has nothing to do with templates. So in your regist_save view, you should do:
return redirect('profile')

Categories