I'm creating my first Django notes app and I'm trying to insert and display notes on the main page. Unfortunately I managed only how to insert them in data base, but I can't display them on the main page.
Here is my views.py file:
from django.shortcuts import render, render_to_response
from django.template import RequestContext, loader
from django.http import HttpResponse
from .models import Note
from .forms import NoteForm
def home(request):
notes = Note.objects
template = loader.get_template('note.html')
form = NoteForm(request.POST or None)
if form.is_valid():
save_it = form.save(commit=False)
save_it.save()
context = {'notes': notes, 'form': form}
return render(request, 'note.html', context)
And here is my html file:
<link href="http://codepen.io/edbond88/pen/CcgvA.css" media="screen" rel="stylesheet" type="text/css">
<style>
body {<br />
background: rgba(222,222,222,1);<br />
margin: 20px;<br />
}<br />
</style>
<h1>Notes App</h1>
<form method="POST" action="">
{% csrf_token %}
{{ form.as_p }}
<td> </td>
<input type="submit" value="Add note">
</form>
I'm trying to make the app from this tutorial: https://pythonspot.com/django-tutorial-building-a-note-taking-app/
You need Note.objects.all() instead of Note.objects in views.py:
def home(request):
notes = Note.objects.all()
template = loader.get_template('note.html')
form = NoteForm(request.POST or None)
if form.is_valid():
save_it = form.save(commit=False)
save_it.save()
context = {'notes': notes, 'form': form}
return render(request, 'note.html', context)
and also, you need to iterate over them to show them in the template:
<h1>Notes App</h1>
{% for note in notes %}
<p>{{ note }}</p>
{% endfor %}
try this :
return render(request, 'note.html', context=context)
instead of this :
return render(request, 'note.html', context)
and this :
notes = Note.objects.all()
instead of this :
notes = Note.objects
The first problem I see is that you didn't add any action into your form. The action attribute should be the view where you want to submit the form to.
So this is what you should do first:
<h1>Notes App</h1>
<form method="POST" action="whatever_your_url_for_this_page_is">
{% csrf_token %}
{{ form.as_p }}
<td> </td>
<input type="submit" value="Add note">
</form>
Related
My form seems to never be returning the input from one template to the other and I am having a hard time understanding why.
forms.py:
class textForm(forms.Form):
message = forms.CharField(widget=forms.Textarea)
views.py:
from django.shortcuts import render
from django.http import HttpResponse
from .forms import textForm
from django.http import HttpResponseRedirect
# The nbar statement is used to show which one is active
def index(Request):
return render (Request, 'index/home.html')
def article(Request):
if Request.method == 'POST':
form = textForm(Request.POST)
if form.is_valid():
message = form.cleaned_data['message']
form = textForm()
context = {'message': message, 'form': form}
#if request is valid and post, send info to next template
return render(Request, 'index/article.html', context)
else:
form = textForm()
#else return to the template where user fills out input
return render(Request, 'index/translate.html', {'form': form})
def translate(Request):
return render (Request, 'index/translate.html', {'nbar': 'translate'})
def most_popular(Request):
return render (Request, 'index/most_popular.html', {'nbar': 'most_popular'})
def the_news(Request):
return render (Request, 'index/news.html', {'nbar': 'news'})
def sports(Request):
return render (Request, 'index/sports.html', {'nbar': 'sports'})
def science(Request):
return render (Request, 'index/science.html', {'nbar': 'science'})
def politics(Request):
return render (Request, 'index/politics.html', {'nbar': 'politics'})
def funny(Request):
return render (Request, 'index/funny.html', {'nbar': 'funny'})
index/translate.html where the form is, where the user inputs the text:
{% extends "index/header.html" %}
{% block content %}
<div class="container">
<h5 style="padding-top: 20px; padding-bottom: 40px;"><strong>welcome!</strong></h5>
<form action="/article" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit" />
</form>
</div>
{% endblock %}
index/article.html where I'd like to return the value from the form:
{% extends "index/header.html" %}
{% block content %}
<!-- the first div functionality will be created later -->
<div>
<h2 style="font-size:45px; margin-top: 35px; margin-bottom: -15px;"> article title </h2>
</div>
<div class="card border border-dark" style = "padding-left: 0px;">
<div class="card-body" style="margin-top: -10px; margin-bottom: -10px; margin-left: -10px;">
<p class="card-title"><strong> result:</strong> </p>
<p class="card-text"> {{ message }} </p>
</div>
</div>
{% endblock %}
The result I am getting is that {{message}} in the second HTML file is always blank - it does not return anything
Error in your template. It should be:
<form action="/article" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit" />
</form>
And edit your view like this:
def article(request):
if request.method == 'POST':
form = TextForm(request.POST)
if form.is_valid():
message = form.cleaned_data['message']
form = TextForm()
context = {'message': message, 'form': form}
return render(request, 'index/article.html', context)
else:
form = TextForm()
return render(request, 'index/article.html', {'form': form})
The user enters the data in the form. But the data entered in the form doesn't get displayed in the Database.
views.py
def add(request):
if request.method=='POST':
form=FilesCreate(request.POST)
if form.is_valid():
form.save()
return render(request,'plagiarism/page1.html',{'form':FilesCreate()})
def add2(request):
if request.method=='POST':
form2=FilesCreate2(request.POST)
if form2.is_valid():
form2.save()
return render(request,'plagiarism/page2.html',{'form':FilesCreate2})
models.py
from django.db import models
class File1(models.Model):
#user=models.ForeignKey(User)
firstfile=models.CharField(max_length=1000, default="")
#secondfile=models.CharField(max_length=1000)
def __str__(self):
return self.firstfile
plagiarism/page1.html
<h1>Enter your first file</h1>
<form action="file2/" method="post">
{% csrf_token %}
{% for field in form %}
{{field}}
<input type="submit" value="Submit file1"/>
{% endfor %}
</form>
plagiarism/page2.html (displays page after clicking submit in page 1)
<h1>Enter your second file</h1>
<form action="plagiarism/file2/result/" method="post">
{% csrf_token %}
{% for field in form %}
{{field}}
<input type="submit" value="Get Results"/>
{% endfor %}
</form>
{% block h1 %}
{% endblock %}
<body>
plagiarism/page3.html (displays page after clicking submit in page 2)
<h1> Here is your Result </h1>
<h2>
{{data}}
</h2>
</body>
forms.py
from django.forms import ModelForm
from django import forms
from plagiarism.models import File1,File2
class FilesCreate(ModelForm):
class Meta:
model=File1
exclude=()
widgets={'firstfile':forms.Textarea(attrs={'cols':50,'rows':100})}
example.py
from django.shortcuts import render
def getresult(request):
data=95.5
return render(request,'plagiarism/page3.html',{'data': data})
urls.py
from django.conf.urls import url
from . import views
from . import example3
urlpatterns=[
url(r'^$',views.add,name='add'),
url(r'file2/$',views.add2,name='add2'),
url(r'file2/result/$',example3.getresult,name='getresult')
]
You seem to want a kind of wizard, where you process a form and it redirects you to the next, but you're not doing the basics of form processing well. For simple form handling, you can do this:
urls.py
from django.conf.urls import url
from . import views
from . import example3
urlpatterns=[
url(r'^$',views.add,name='add'),
url(r'file2/result/$', example3.getresult, name='getresult')
]
In the template, you are calling file2 with the form's action, but you really want to call the same page, to process the form with the add view:
plagiarism/page1.html
<h1>Enter your first file</h1>
<form method="post">
{% csrf_token %}
{% for field in form %}
{{field}}
{% endfor %}
<input type="submit" value="Submit file1"/>
</form>
Note the missing action attribute in the <form> element.
When you visit the root of the website, the add view will be called with a GET request. When you submit the form, the same add view will be called, with a POST request, which will then be processed:
views.py
def add(request):
if request.method == 'POST':
form = FilesCreate(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('getresult'))
else:
form = FilesCreate()
return render(request,'plagiarism/page1.html',{'form': form})
Note the HttpResponseRedirect, which redirects to a new page on success, and the else, which creates an empty form for the first time you visit the page (i.e. request.method is not POST, it is GET). This way, if the form isn't valid, the last line will render it bound to the data that was submitted and display the errors.
This should get you the data into the database, which was your first goal. If you want to go to another form upon submission, you can redirect there (instead of the result page) and do the same as above in the view add2.
There used to be a Django Form Wizard, but you can see this project to do multi-step forms.
I am trying to implement the login field using django's authenticationForm.
the problem im having is that,because im trying to display two different forms inside one page (post_list) it seem to cause many errors.
one is for login field, and one is for the posting articles.
i also seem to have problem with duplicate forms as the two forms use the samename for the form which i do not know how to change.
also, there an error occurring when i try to post something using the post form.
to blatantly put, how do i make the login field visible?
i refer you to the working site : http://mtode.com( this is just a representation site, and do not contain login field part)
this is my views py which contains the definitions
from django.contrib import messages
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render, get_object_or_404, redirect
from .forms import PostForm, AuthenticationForm
from .models import Post
from django.contrib.auth import authenticate, login
from django.contrib.auth import login
from django.http import HttpResponseRedirect
from django.template.response import TemplateResponse
from django.contrib.auth.decorators import login_required
def post_detail(request, id=None):
#instance = Post.objects.get(id=1)
instance = get_object_or_404(Post, id=id)
context = {
"title": instance.title,
"instance": instance,
}
return render(request, "post_detail.html", context)
def post_list(request):
if request.method == "POST":
form = AuthenticationForm(request, data=request.POST)
if form.is_valid():
login(request, form.get_user())
return HttpResponseRedirect('/post-list/')
else:
form = AuthenticationForm(request)
return TemplateResponse(request, 'login.html', {'form': form})
form = PostForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
print (form.cleaned_data.get("title"))
instance.save()
# message success
messages.success(request, "Successfully Created")
return HttpResponseRedirect(instance.get())
#else:
#messages.error(request, "Not Successfully Created")
queryset = Post.objects.all()#.order_by("-timestamp")
context = {
"object_list": queryset,
"title": "List",
"form": form,
}
return render(request, "post_list.html", context)
#return HttpResponse("<h1>List</h1>")
def post_update(request, id=None):
instance = get_object_or_404(Post, id=id)
form = PostForm(request.POST or None, instance=instance)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
# message success
messages.success(request, "Saved")
return HttpResponseRedirect(instance.get_absolute_url())
context = {
"title": instance.title,
"instance": instance,
"form":form,
}
return render(request, "post_form.html", context)
def post_delete(request, id=None):
instance = get_object_or_404(Post, id=id)
instance.delete()
messages.success(request, "Successfully deleted")
return redirect("posts:list")
and this is the forms.py that contains the forms
from django import forms
from .models import Post
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = [
"title",
"content"
]
from django.contrib.auth import authenticate
class AuthenticationForm(forms.Form):
username = forms.CharField(max_length=254)
password = forms.CharField(widget=forms.PasswordInput)
def clean(self):
username = self.cleaned_data['username']
password = self.cleaned_data['password']
user = authenticate(username=username, password=password)
if user is None:
raise forms.ValidationError('invalid_login')
return self.cleaned_data
and this is the post_list.html
{% extends "base.html" %}
{% block content %}
<form method="post" action="">
{% csrf_token %}
Username: {{ form.username }} {{ form.username.errors }}<br>
Password: {{ form.password }} {{ form.password.errors }}<br>
{{ form.errors }}<br>
<input type="submit" value="login" />
</form>
<div class='two columns right mgr'>
<h1>Form</h1>
<form method='POST' action=''>{% csrf_token %}
{{ form.as_p }}
<input class="button-primary" type='submit' value='Create Post' />
</form>
</div>
<div class='four columns left'>
<h1>{{ title }}</h1>
{% for obj in object_list %}
<div class="row">
<div>
<a href='{{ obj.get_absolute_url }}'>
<div class="thumbnail">
<!--<img src="..." alt="...">!-->
<div class="caption">
<h3>{{ obj.title }}<small> {{ obj.timestamp|timesince }} ago</small></h3>
<p>{{ obj.content|linebreaks|truncatechars:120 }}</p>
<!-- <p>View </p>-->
</div>
</div></a>
</div>
<hr />
</div>
{% endfor %}
</div>
{% endblock content %}
Thank you.
When your page is initially displayed, request.method is GET. Therefore the post_list view is creating a PostForm instance and passing that into your template as the form element.
PostForm does not have username or password attributes, so those items are treated as empty strings and do not render at all.
If you want a template to render two forms, you need to pass them as separate names. You can't call them both "form".
I recently tried the forms validations and faced an issue with ValidationError().
The form error does not appear in my website when I submit the form.
Here is the code:
forms.py
class ArticleForm(forms.ModelForm):
def clean_titre(self):
titre = self.cleaned_data['titre']
if len(titre) < 5:
raise ValidationError('myError')
return titre
form = ArticleForm()
template.html
<div class="form-group">TITRE
{{ form.titre.errors }}
{{ form.titre }}
</div>
views.py
def AddArticle(request):
form = ArticleForm(request.POST, request.FILES)
if form.is_valid():
save_it = form.save(commit=False)
save_it.user = request.user
save_it.save()
form.save_m2m()
return HttpResponseRedirect('/')
What did I do wrong?
--- EDIT ---
Full template.html
<form class="form" action="{% url "article.views.AddArticle" %}" method="post" enctype='multipart/form-data'>
{% csrf_token %}
<div class="form-group">TITRE
{{ form.titre.errors }}
{{ form.titre }}
</div>
<div class="form-group">SUMMARY
{{ form.media }}
{{ form.summary.errors }}
{{ form.summary }}
</div>
<div class="form-group">CONTENU
{{ form.media }}
{{ form.contenu.errors }}
{{ form.contenu }}
</div>
<div class="form-group">
{{ form.image.errors }}
{{ form.image }}
</div>
<div class="form-group">TAGS
{{ form.tags.errors }}
{{ form.tags }}
</div>
<input type="submit" class="btn btn-default" value="Submit" autocomplete="off" autocorrect="off" />
</form>
I'll post the full forms.py too, it may help.
forms.py
class ArticleForm(forms.ModelForm):
def clean_titre(self):
titre = self.cleaned_data['titre']
if len(titre) < 5:
raise ValidationError('myError')
return titre
class Meta:
model = Article
exclude = ['date', 'rating', 'user']
widgets={
"titre":forms.TextInput(attrs={'placeholder':'Le titre', 'class':'form-control'}),
"contenu":forms.Textarea(attrs={'placeholder':'Le Contenu de votre message', 'class':'form-control'}),
"image":forms.FileInput(attrs={'placeholder':'Votre Image', 'id':'uploadBtn'}),
"tags":TagWidget(attrs={'placeholder':'Vos Tags', 'class':'form-control'}),
}
form = ArticleForm()
You are missing the else portion within your view. Here is the general flow of what forms usually do:
Users navigate to a page via GET which presents them with a form
Users fill in the form and submit it by using POST
If the form is valid, users are directed to a different page
If the form is not valid, users are presented with the same page as in step 1 with the validation errors displayed. After users correct them, they are process to step 2.
Here is that flow in django view:
def AddArticle(request):
if request.method == 'POST':
form = ArticleForm(request.POST, request.FILES)
if form.is_valid():
save_it = form.save(commit=False)
save_it.user = request.user
save_it.save()
form.save_m2m()
return HttpResponseRedirect('/')
else:
form = ArticleForm()
return render(request, 'template.html', {'form': form'})
I would however look into using class based views in Django. Initially they can seem very confusing but over time you will learn to appreciate them. Docs. Another useful resource when learning CBV.
By using CBV, the above can be simplified to:
class AddArticleView(CreateView):
success_url = 'name_of_view_here'
form_class = ArticleForm
template_name = 'template.html'
# urls.py
urlpatterns = patterns('', url(r'^articles/add/$', AddArticleView.as_view()))
Template
You also need to include the overall form error in the template, in addition to each field errors:
<form class="form" action="{% url "article.views.AddArticle" %}" method="post" enctype='multipart/form-data'>
{% csrf_token %}
{{ form.non_field_errors }}
...
</form>
Please note that you might need to wrap the errors with some bootstrap markup. More info in docs
The example in https://docs.djangoproject.com/en/1.6/topics/forms/ demonstrates usage of form and has the following code:
def contact(request):
if request.method == 'POST': # If the form has been submitted...
form = ContactForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
return HttpResponseRedirect('/thanks/') # Redirect after POST
else:
form = ContactForm() # An unbound form
return render(request, 'contact.html', {'form': form,})
and contact.html template is
<form action="/contact/" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
I am wondering if it's possible in render(request,...,{'form':form,}) instead of specifying template file contact.html to pass variable with the contents of template, something like this:
html = """
<html>
<head> bla bla bla</head>
<body>
<form action="/contact/" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
</body>
"""
return render(request, html, {'form': form,})
If it's possible what could be the drawbacks and risks associated with such approach?
Thanks in advance!
Not with render, which is a shortcut for loading a template, rendering it and returning a response. But you can do it with separate calls:
from django.template import RequestContext, Template
tpl = Template(html)
rendered = tpl.render(RequestContext(request, {'form': form}))
return HttpResponse(rendered)
The main drawback is that you're mixing the HTML in the python file, which makes it hard to read. Buy you could use this technique to load templates from the database or an api, for example.