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.
Related
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
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.)
I'm trying to create a usercreationform on the homepage of my website. After reading and watching tutorials on user creation I noticed everyone creates a separate HTML page for "signup", however, I want my signup page to be directly on my homepage - is this a possibility? I'm finding it difficult to understand with 'accounts' having its own separate app, as well as the homepage having its own app, which I have called mine 'game'. Do both apps have to be separate? Am I able to make the accounts app my main 'homepage' app?
Can anyone recommend any tutorials on this? I think I should also mention I'm quite new to django. Thank you.
My homepage app (titled game)
urls.py:
from django.contrib import admin
from django.urls import path
from.import views
urlpatterns = [
path('', views.game_start),
]
views.py:
from django.shortcuts import render
from django.contrib.auth.forms import UserCreationForm
from .models import Game
def game_start(request):
games = Game.objects.all().order_by('date') # grabs all records in game in db table, order by date
return render (request, 'game/game_start.html', {'games':games})
def signup_view(request):
form = UserCreationForm()
return render(request, 'game/game_start.html', {'form': form})
accounts/urls.py:
from django.conf.urls import url
from .import views
app_name = 'accounts'
urlpatterns = [
path('', game_views.game_start, name="home"),
]
accounts/views.py:
from django.http import HttpResponse
from django.shortcuts import render
def about(request):
# return HttpResponse('Price is right game one')
return render(request, 'about.html')
I want my signup page to be directly on my homepage - is this a possibility?
Yes it's a possibility that you can define a custom signup function in your accounts app and then import that inside of your homepage app like this:
accounts/views.py:
def signup(request):
data = {'form':None, 'user_created': False}
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
user = form.save()
# do soemthing with the registered user
data['user_created'] = True
else:
form = UserCreationForm()
data['form'] = form
return data
homepage/views.py:
from accounts.views import signup
def game_start(request):
games = Game.objects.all().order_by('date')
data = {'msg': ''}
response = signup(request)
if response['user_created']:
# you can redirect user here to somewhere else when they have been registered.
data['msg'] = 'Thanks for being the part of our beautiful community!'
return render(request, 'game/game_start.html', {
'games':games,
'form': response['form'],
'msg': data['msg']
})
game_start.html:
<p>{{msg}}</p>
<form action="/" method="post">
{% csrf_token %}
{{ form }}
<button type="submit">Sign Up</button>
</form>
Do both apps have to be separate?
Well, you can have both of them under one app but that is not recommended because of the following reasons:
You won't take advantage of App Reusability.
All of your code would look messy.
Debugging would be hard.
If you are having difficult understanding what apps in django are, then you can simply take a look at my answer here
You could include the form in your "game_start.html" template:
{% if not user.is_authenticated %}
<form role="form"
action="{% url 'player_login' %}"
method="post">
{% csrf_token %}
<p>Please login.</p>
{{ form.as_p }}
<button type="submit">Sign in</button>
</form>
{% endif %}
This assumes you have a named url pattern player_login.
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')
My underlying struggle is I am having trouble understanding how django templates, views, and urls are tied together... What is the simplest, bare minimum way to prompt the user to input a string, then use that string to query a database (preferably w/ python model not raw sql queries)? Should I use GET and POST methods? Should I use a form? Do I need to use a template or can I use a generic view?
when i try submitting input it just reloads the input page.
views.py:
from django.shortcuts import render
from django.shortcuts import HttpResponse
from People.models import Person
def index(request):
return render(request, 'People/index.html')
def search(request):
search_id = request.POST.get('textfield', None)
try:
user = Person.objects.get(MAIN_AUTHOR = search_id)
#do something with user
html = ("<H1>%s</H1>", user)
return HttpResponse(html)
except Person.DoesNotExist:
return HttpResponse("no such user")
urls.py
from django.conf.urls import patterns, include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
url(r'^admin/', include(admin.site.urls)),
url(r'^People/', 'People.views.index'),
url(r'^People/send/', 'People.views.search'),
)
template:
<form method="POST" action="send/">
{% csrf_token %}
<input type="text" name="textfield">
<button type="submit">Upload text</button>
</form>
Am I missing something or doing something wrong?
If I understand correctly, you want to take some input from the user, query the database and show the user results based on the input. For this you can create a simple django form that will take the input. Then you can pass the parameter to a view in GET request and query the database for the keyword.
EDIT:
I have edited the code. It should work now.
views.py
from django.shortcuts import render
from django.shortcuts import HttpResponse
from .models import Person
from django.core.exceptions import *
def index(request):
return render(request, 'form.html')
def search(request):
if request.method == 'POST':
search_id = request.POST.get('textfield', None)
try:
user = Person.objects.get(name = search_id)
#do something with user
html = ("<H1>%s</H1>", user)
return HttpResponse(html)
except Person.DoesNotExist:
return HttpResponse("no such user")
else:
return render(request, 'form.html')
urls.py
from django.conf.urls import patterns, include, url
from People.views import *
urlpatterns = patterns('',
url(r'^search/', search),
url(r'^index/', index)
)
form.html
<form method="POST" action="/search">
{% csrf_token %}
<input type="text" name="textfield">
<button type="submit">Upload text</button>
</form>
Also make sure that you place your templates in a seperate folder named templates and add this in your settings.py:
TEMPLATE_DIRS = (
os.path.join(os.path.dirname(__file__), '../templates').replace('\\','/'),
)
For a user input you'll need 2 views - one to display the page with the form and another to process the data. You hook the first view to one url, say "feedback/", and the other one to a url like "feedback/send/". You also need to specify this second url in your form tag.
<form method="POST" action="feedback/send/">
<input type="text" name="textfield">
...
<button type="submit">Upload text</button>
</form>
Now in the second view you can obtain the form data and do whatever you want with it.
def second_view(request):
if request.method == "POST":
get_text = request.POST["textfield"]
# Do whatever you want with the data
Take a look at this page Fun with Forms. It'll give you the basic understanding. I would also advice to work through the whole book.
You should use ether GET or POST (GET is probably not secure). Using form is not mandatory, as you can style it and perform all the validation yourself and then pass the data straight to the model.