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.
Related
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 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.
I'm new to django and trying to create my first app and I think I might need some little help :)
I have a ModelForm on a site to submit and want to show the data on the same page. I'm having trouble to set up two functions on the same page, I think i might have to use a class and set it in urls.py but I'm not able to make it work :( the code looks like this:
forms.py:
from django import forms
from .models import Eintrag
class NameForm(forms.ModelForm):
class Meta:
model = Eintrag
fields = ['Anmeldung', 'Essen']
urls.py
from django.urls import path
from . import views
app_name = 'form'
urlpatterns = [
path('', views.get_name, name='form'),
]
views.py
from django.shortcuts import render
from django.utils import timezone
from django.contrib.auth.decorators import login_required
from .forms import NameForm
from .models import Eintrag
#login_required()
def get_name(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 = NameForm(request.POST)
# check whether it's valid:
if form.is_valid():
eintrag = form.save(commit=False)
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
eintrag.Name = request.user # Set the user object here
eintrag.pub_date = timezone.now() # Set the user object here
eintrag.save()
return render(request, 'form/name.html', {'form': form})
# if a GET (or any other method) we'll create a blank form
else:
form = NameForm()
return render(request, 'form/name.html', {'form': form})
def post_list(request):
posts = Eintrag.objects.all()
return render('form/post_list.html', {'posts': posts})
name.html
...
{% include "form/post_list.html" %}
<form action="/form/" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit" />
</form>
...
post_list.html
{% for post in posts %}
{{ post }}
{% endfor %}
So the problem is in urls.py only get_name is handled and I'm clueless how I should include post_list. I rather not want to use different url's, do I have to?
Thanks for any help and advice!
You don't need a separate URL or view for the list. Just include the queryset in the context of your get_name view.
posts = Eintrag.objects.all()
return render(request, 'form/name.html', {'form': form, 'posts': posts})
with [Class Based View] it would be better.
But with your view, you can send multiple data via context.
#login_required()
def get_name(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:
''' codes '''
eintrag.save()
return HttpResponseRedirect(request.path) # generate an empty form
# if a GET (or any other method) we'll create a blank form
else:
form = NameForm()
posts = Eintrag.objects.all() # the queryset is here, and sent via context
return render(request, 'form/name.html', {'form': form,'posts':posts})
I your html remain the same, but keep your form action='' empty
{% include "form/post_list.html" %}
<form action="" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit" />
</form>
I'm trying to pass data from a successful form submission to a thank you page that could then display this data. I am trying to do a reverse HttpResponseRedirect, but I keep getting this error:
NoReverseMatch at /contactform/process
Reverse for 'thankyou' with arguments '(24,)' not found. 1 pattern(s) tried: [u'contactform/thankyou/$']
Here is the code I have so far:
views.py
from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.views import generic
from .models import Contact_Object
def index(request):
template_name = 'contactform/index.html'
return render(request, 'contactform/index.html')
def thankyou(request, entered_id):
contact_info = get_object_or_404(Contact_Object, pk=contact_object_id)
template_name = 'contactform/thankyou.html'
return render(request, 'contactform/thankyou.html', {name: contact_info.name})
def process(request):
entered_name = request.POST['fullname']
entered_email = request.POST['email']
entered_message = request.POST['message']
entered = Contact_Object(name=entered_name, email=entered_email, message=entered_message)
entered.save()
entered_id = entered.id
return HttpResponseRedirect(reverse('contactform:thankyou', args=(entered.id,)))
urls.py
from django.conf.urls import url
from . import views
app_name = 'contactform'
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^thankyou/$', views.thankyou, name='thankyou'),
url(r'^process$', views.process, name='process'),
]
Template for Form
<H1>Contact Form</H1>
<FORM action="{% url 'contactform:process' %}" method="post">
{% csrf_token %}
Full Name:<br>
<input type="text" name="fullname"><br>
Email:<br>
<input type="text" name="email" ><br>
Message:<br>
<textarea name="message" cols="40" rows="5"></textarea>
<input type="submit" value="Enter">
</FORM>
Template for Thank you page
<h1>Thank You</h1>
<p>Thank you, {% contact_info.name %}</p>
I'm new to working with Python/Django so I feel it's probably an obvious beginners mistake, I just can't seem to spot it.
Thanks in advance.
Your problem is right here:
return HttpResponseRedirect(reverse('contactform:thankyou', args=(entered.id,)))
the thankyou url doesn't take any arguments.
url(r'^thankyou/$', views.thankyou, name='thankyou'),
To fix it you should change it to this:
url(r'^thankyou/([0-9]*)$', views.thankyou, name='thankyou'),
Using the reverse function and the args kwarg, it translates it into a usable URL like: /thankyou/24 plugging in the args provided in the args iterable. You can also use kwargs to pass in keywords to your url if you're using keyword groupings in your url as described below.
See here: https://docs.djangoproject.com/en/1.11/topics/http/urls/#example
Each of the regex groupings is an argument that gets passed to the view.
You can also have keyword arguments passed if you do the url like this:
url(r'^thankyou/(?P<pk>[0-9]*)$', views.thankyou, name='thankyou'),
and in a function based view you would access it by defining it in the view function signature like this:
def thankyou(request, pk=None):
I am learning Django and am trying to create a form that I can submit a participant's information to the database.
I have an index view, which list all the participants:
http://127.0.0.1:8000/participants/
Clicking a button on the index will go to form submission:
http://127.0.0.1:8000/participants/add_participant/
After submitting the form, the page goes back to the index view, but the URL is not correct, it stucks at http://127.0.0.1:8000/participants/add_participant/
If I refresh the browser immediately, it will add another record to the database.
add_participant.html
<!DOCTYPE html>
<html>
<head>
<title>This is the title</title>
</head>
<body>
<h1>Add a Participant</h1>
<form id="participant_form" method="post" action="/participants/add_participant/">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" name="submit" value="Create Participant" />
</form>
</body>
</html>
views.py
from django.shortcuts import render, get_object_or_404, redirect
from django.http import HttpResponse, HttpResponseRedirect
from participants.models import Participant
from .forms import ParticipantForm
# Create your views here.
def index(request):
participant_list = Participant.objects.order_by('-first_name')[:50]
context = {'participants': participant_list}
return render(request, 'participants/index.html', context)
def add_participant(request):
if request.method == 'POST':
form = ParticipantForm(request.POST)
if form.is_valid():
form.save(commit=True)
return index(request)
else:
form = ParticipantForm()
return render(request, 'participants/add_participant.html', {'form': form})
urls.py
from django.conf.urls import url
from . import views
from .models import Participant
app_name = 'participants'
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'add_participant/$', views.add_participant, name='add_participant'),
]
I tried switching the
return index(request)
to:
return HttpResponseRedirect("http://127.0.0.1:8000/participants/")
It solves the problem...but I doubt this is the "right" way to do it. What is the correct way to fix this issue?
You can pass just the path to the redirect response:
return HttpResponseRedirect("/participants/")
This way if you change your domain, the redirect will work.
an other solution is to use reverse
from django.core.urlresolvers import reverse
# ...
return HttpResponseRedirect(reverse(index))