I have these two functions, one of them (first one) adds a new entry and the second one edits the entry:
def add_entry(request):
if request.method == 'POST':
form = AddForm(request.POST)
if form.is_valid():
title = form.cleaned_data["title"]
content = form.cleaned_data["content"]
if util.get_entry(title) is None:
util.save_entry(title, content)
return redirect('entry', title)
else:
return render(request, "encyclopedia/add_entry.html", {
"form": AddForm(),
"title": title
})
return render(request, "encyclopedia/add_entry.html", {
"form": AddForm()
})
def edit_entry(request, title):
content = util.get_entry(title)
if request.method == 'POST':
form = AddForm(request.POST)
if form.is_valid():
title = form.cleaned_data["title"]
content = form.cleaned_data["content"]
util.save_entry(title, content)
return redirect('entry', title)
return render(request, "encyclopedia/edit_entry.html", {
"title": title,
"content": content
Here is my edit_entry.html page:
{% extends "encyclopedia/layout.html" %}
{% block title %}
Edit page
{% endblock %}
{% block body %}
<form action="{% url 'edit_entry' title %}" method="POST">
{% csrf_token %}
<h5>Title</h5>
<input type="text" value="{{ title }}">
<h5>Content</h5>
<textarea cols="30" rows="10">{{ content }}</textarea>
<input type="submit" value="Save Editing">
</form>
{% endblock %}
This is add_entry.html template
{% extends "encyclopedia/layout.html" %}
{% block title %}
Add new entry
{% endblock %}
{% block body %}
<h1>Create a new page</h1>
{% if title %}
<h6 style="color: red;">"{{title}}" page is already exists. Please, enter a different title</h6>
{% endif %}
<form action="{% url 'add_entry' %}" method="POST">
{% csrf_token %}
{{ form }}
<input type="submit" value="Create">
</form>
{% endblock %}
And here is my urls.py:
from django.urls import path
from . import views
urlpatterns = [
path("", views.index, name="index"),
path("wiki/<str:title>", views.entry, name="entry"),
path("search", views.search, name="search"),
path("add_entry", views.add_entry, name="add_entry"),
path("wiki/<str:title>/edit_entry", views.edit_entry, name="edit_entry")
]
My entry view:
def entry(request, title):
if title not in util.list_entries():
return render(request, "encyclopedia/error.html", {
"error": "Page Not Found",
"query": title
})
else:
return render(request, "encyclopedia/entry.html", {
"entry": markdown2.markdown(util.get_entry(title)),
"title": title
})
The issue here when I click to save the content of the page doesn't change, I want to save the edits and display it with new content. Instead, it returns an old form with the old content (like doesn't change).
EDIT: based on your comments, I think it is better to start over.
Since you are doing some simple create and update, it maybe better to use generic views. Here is an example.
1.First and formost, you need a model.
in models.py,
from django.db import models
class Entry(models.Model):
title = models.CharField(max_length=200)
content = models.TextField(max_length=2000)
2. in your forms.py
Note: this is not necessary if you want to just use django default form. Because class-based generic views will automatically generate forms for you. However, if you need to add widget, or to add attributes (for example, add css class or id), you need to generate a customform.
from django import forms
from .models import Entry
class EntryForm(forms.ModelForm):
class Meta:
model = Entry
fields = ('title', 'content')
widgets = {
'title': forms.TextInput(attrs={'placeholder': 'Title'}),
'content': forms.TextInput(attrs={'class': 'content'}),
}
3. views.py
from .models import Entry
from django.views.generic.edit import CreateView, UpdateView
class CreateEntry(CreateView):
model=Entry
template_name = 'create_edit_entry.html' # this is the template, you might need to change its path.
form_class= EntryForm # this is added because we are using customform
success_url = '/' #this can be changed
class UpdateEntry(UpdateView):
model=Entry
template_name = 'create_edit_entry.html'
form_class= EntryForm
4. urls.py
from django.urls import path
from .views import CreateEntry, UpdateEntry
urlpatterns = [
path('entry/', CreateEntry.as_view(), name='create_entry'),
path('entry/<int:pk>', UpdateEntry.as_view(), name='update_entry'),
]
5. admins.py
from django.contrib import admin
from .models import Entry
class EntryAdmin(admin.ModelAdmin):
list_display = (('id', 'title', 'content'))
admin.site.register(Entry, EntryAdmin)
6. templates (create_edit_entry.html)
{% extends 'base.html' %}
{% block extrahead %}
{% load static %}
{% endblock %}
{% block content %}
<form action="." method="POST">
{% csrf_token %}
{{ form }}
<button type="submit">SUBMIT</button>
</form>
{% endblock %}
After you update all these files and update mysite/urls.py, you will 1) open http://127.0.0.1:8000/entry to add an entry. Check if the entry is created in your admin page. 2) then you will open http://127.0.0.1:8000/entry/1 (if the id=1) to see if your original entry is shown. 3) then you will update the form, and check if the update is successful or not in your admin.
This backbone should be able to get you started. Note that I did not put DetailView, ListView, so you need to check if the object is created and updated in your admin page. Of cause, you can add DetailView and ListView by yourself (check out django document here to learn more about generic views).
**************************************earlier answer **************
1. First thing first, it is always helpful to access form.errors when you are having trouble with forms. What you do is to add else: print(form.errors) like the following:
if form.is_valid():
# other code
else:
print(form.errors)
2.
Your edit_entry.html change to something like below: I guess you wanted use your own styling (add Title, Content etc) to the form, so you did not use {{form}}. If what I suggest worked, you can add form styling later.
{% extends "encyclopedia/layout.html" %}
{% block title %}
Edit page
{% endblock %}
{% block body %}
<form action="{% url 'edit_entry' title %}" method="POST">
{% csrf_token %}
{{form}}
</form>
{% endblock %}
3. your edit_entry view:
def edit_entry(request, title):
entry = get_object_or_404(Entry, title=title) # i assume your Model name is "Entry"
if request.method == 'POST':
form = AddForm(request.POST, instance = entry)
if form.is_valid():
print('under form.is_valid) # add this line to keep track
title = form.cleaned_data["title"]
content = form.cleaned_data["content"]
form.save()
return redirect('entry', title=entry.title)
else:
print(form.errors)
else:
form = AddForm(instance = entry)
return render(request, "encyclopedia/edit_entry.html", {
'form': form})
Related
I have been currently working on an easy Django website.
An error came up when I tried to implement a function that users can add comments to blogs. I succeeded to show the form where users can write their comments, but even if I pressed the add button, didn't save properly.
I don't even know where I made a mistake coz I knew how to post and save information to the database.
so, I ask you to help!!
# add_comment.html
{% extends 'base.html' %}
{% block title %}|コメント追加{% endblock %}
{% block content %}
<div class="header-bar">
← 戻る
</div>
<div class="body-container blog">
<div class="body-header">
<h1>コメント追加</h1>
</div>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button class='button' type="submit">追加</button>
</form>
</div>
</div>
{% endblock %}
# views.py
#login_required
def add_comment(request, pk):
blog = get_object_or_404(Blog, pk=pk)
if request.method == 'post':
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.blog = blog
comment.save()
return redirect('blog', pk=blog.pk)
else:
form = CommentForm()
context = {
'form': form,
}
return render(request, 'blog/add_comment.html', context)
# urls.py
from django.urls import path
from . import views
from .views import BlogCreate, BlogUpdate, BlogDelete, BlogList
# blogs
urlpatterns = [
path('', views.index, name='latest_blogs'),
path('my_blogs/', views.my_blogs, name='my_blogs'),
path('my_blogs/my_blog_search', views.my_blogs_search, name='my_blogs_search'),
path('drafts/', views.drafts, name='drafts'),
path('blog/<int:pk>/', views.blog, name='blog'),
path('blog/<int:pk>/comment/', views.add_comment, name='add_comment'),
path('create/', BlogCreate.as_view(), name='blog-create'),
path('update/<int:pk>/', BlogUpdate.as_view(), name='blog-update'),
path('delete/<int:pk>/', BlogDelete.as_view(), name='blog-delete'),
path('all_blogs/', BlogList.as_view(), name='all_blogs'),
path('all_blogs/all_blogs_search/', views.all_blogs_search, name='all_blogs_search'),
]
Any comments help me and thanks for your time in advance!!
#MODS- Although it has been asked on here before I can not find a suitable answer in Django 3, please read through all I have tried before deleting
Preamble:
I am working through This Tutorial that is taught in Django 1, I am following it but making necessary changes for Django 3.
QUESTION:
I receive an error when loading my page with a form on it.
HTML for the form page:
{% block title %}Start a New Topic{% endblock %}
{% block breadcrumb %}
<li class="breadcrumb-item">Boards</li>
<li class="breadcrumb-item">{{ board.name }}</li>
<li class="breadcrumb-item active">New topic</li>
{% endblock %}
{% block content %}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-success">Post</button>
</form>
{% endblock %}
Base HTML:
{% block title %}Start a New Topic{% endblock %}
{% block breadcrumb %}
<li class="breadcrumb-item">Boards</li>
<li class="breadcrumb-item">{{ board.name }}</li>
<li class="breadcrumb-item active">New topic</li>
{% endblock %}
{% block content %}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-success">Post</button>
</form>
{% endblock %}
urls.py
from django.contrib import admin
from django.urls import path , re_path
#uses path and re_path for regex when needed.
from boards import views
urlpatterns = [
path('admin/', admin.site.urls),
re_path('boards/(?P<pk>\d+)/$', views.board_topics, name='board_topics'),
re_path('boards/(?P<pk>\d+)/new/$', views.new_topic, name='new_topic'),
path('', views.home,name='home'),
]
Forms.py
from .models import Topic
class NewTopicForm(forms.ModelForm):
message = forms.CharField(
widget=forms.Textarea(
attrs={'rows': 5, 'placeholder': 'What is on your mind?'}
),
max_length=4000,
help_text='The max length of the text is 4000.'
)
class Meta:
model = Topic
fields = ['subject', 'message']
views.py
from .models import Board, Topic, Post
from django.contrib.auth.models import User
from .forms import NewTopicForm
from django.http import HttpResponseRedirect
# Create your views here.
def home(request):
boards = Board.objects.all()
return render(request, 'home.html', {'boards': boards})
def board_topics(request, pk):
try:
board = Board.objects.get(pk=pk)
except Board.DoesNotExist:
raise Http404
return render(request, 'topics.html', {'board': board})
def new_topic(request, pk):
board = Board.objects.get(pk=pk)
user = User.objects.first() # TODO: get the currently logged in user
if request.method == 'POST':
form = NewTopicForm(request.POST)
if form.is_valid():
topic = form.save()
return HttpResponseRedirect('/')
else:
form = NewTopicForm()
return render(request, 'new_topic.html', {'form': form})
I believe my issue is coming from return HttpResponseRedirect('/').
in the tutorial they use a redirect
return redirect('board_topics', pk=board.pk)
However to my knowledge this is not possible in django 3. Also when I looked on the official django 3.1 documentation in forms they use a HttpResponseRedirect aswell.
I have tried using a render but was not able to make it work either.
Any suggestions? I have been stuck on this for a few hours and want to get past it.
Try using reverse:
from django.shortcuts import reverse
... your form ...
return redirect(reverse('board_topics', kwargs={'pk': board.pk}))
btw the regular redirect should also work, try it.
edit
you actually need to pass board as a parameter in your context in your form view:
return render(request, 'new_topic.html', {'form': form, 'board': board})
I am trying to implement basic search functionality with Django. Could use help with accessing query inputs from forms in templates in functional or class based views. Intended functionality:
If exact search query page exists, display that page
If there is a page title that contains what was queried, show results of all
If neither, display a message stating no results found
I'm just learning, so I tried functional views and class based views. I've spent a really long time on documentation/videos/textbooks and don't see how to get the intended behavior out of class-based view. I understand collecting object_list and getting query_set, but how do you then route to those three different conditions. I tried overriding dispatch() and as_views() method to no avail. Tried with a Django form class and without.
For some reason, the functional view keeps executing the first try statement instead of throwing a DoesNotExist exception when the exact match isn't found. So it shows the entry page instead of the search results page. It seems like the request.GET is None type no matter what, as when I try to print nothing shows up.
urls.py
from re import search
from django.urls import path
from . import views
from .views import IndexPageView, SearchView
app_name = "wiki"
urlpatterns = [
# ex: /wiki/
path("", views.index, name="index"),
# path("", IndexPageView.as_view(), name="index"),
# ex: /wiki/EntryPageName
path("wiki/<str:entry>/", views.displayEntry, name="displayEntry"),
# path("wiki/search/", views.searchView, name="searchView")
path("wiki/search/", SearchView.as_view(), name="searchView")
]
model
class Entry(models.Model):
title = models.CharField(max_length=64)
def __str__(self):
return f"{self.title}"
content = models.TextField()
views.py
def searchView(request):
searchedTerm = request.GET.get('q')
try:
exactMatch = Entry.objects.get(title=searchedTerm)
entryTitle = exactMatch.title
entryHTML = markdown2.markdown(exactMatch.content)
return render(request, "encyclopedia/displayEntry.html", {
"entryTitle": entryTitle,
"entryHTML": entryHTML
})
except:
try:
searchResults = Entry.objects.filter(Q(title__icontains=searchedTerm))
return render(request, "encyclopedia/searchResults.html", {
"searchResults": searchResults,
"searchedTerm": searchedTerm
})
except:
return render(request, "encyclopedia/searchResults.html", {
"emptyResults": f"No entries found matching: {searchedTerm}",
"searchedTerm": searchedTerm
})
class SearchView(ListView):
template_name = "encyclopedia/searchResults.html"
model = Entry
context_object_name = "searchList"
def get_queryset(self):
searchedTerm = self.request.GET.get('q')
try:
searchResults = Entry.objects.get(title=searchedTerm)
return searchResults
except:
try:
searchResults = Entry.objects.filter(Q(title__icontains=searchedTerm))
return searchResults
except:
pass
def as_view():
searchedTerm = self.request.GET.get('q')
try:
exactMatch = Entry.objects.get(title=searchedTerm)
entryTitle = exactMatch.title
entryHTML = markdown2.markdown(exactMatch.content)
return render(request, "encyclopedia/displayEntry.html", {
"entryTitle": entryTitle,
"entryHTML": entryHTML,
})
except:
searchResults = Entry.objects.filter(Q(title__icontains=searchedTerm))
return render(request, "encyclopedia/searchResults.html", {
"searchResults": searchResults,
"searchedTerm": searchedTerm
})
else:
return render(request, "encyclopedia/searchResults.html", {
"emptyResults": f"No entries found matching: {searchedTerm}",
"searchedTerm": searchedTerm
})
search form from layout.html
<form action="{% url 'wiki:search' %}" method="GET">
<input class="search" type="text" name="q" placeholder="Search Encyclopedia">
<!-- <input type="submit" value="submit"> -->
</form>
display entry page template
{% extends "encyclopedia/layout.html" %}
{% block title %}
{% if entryTitle %}
{{ entryTitle }}
{% else %}
Page Not Found!
{% endif %}
{% endblock %}
{% block body %}
{% if entryHTML %}
{{ entryHTML|safe }}
{% else %}
<p>This page does not exist yet.</p>
<p>Check your spelling or create a new entry!</p>
<p>?? {{ testPrint }}</p>
{% endif %}
{% endblock %}
search results page
{% extends "encyclopedia/layout.html" %}
{% block title %}
Search Results: {{ searchedTerm }}
{% endblock %}
{% block body %}
{% if searchResults %}
<h3>Search Results</h3>
<ul>
{% for result in searchResults %}
<li>{{ result.title }}</li>
{% endfor %}
</ul>
{% else %}
<h3>{{ emptyResults }}</h3>
{% endif %}
{% endblock %}
Models
class Entry(models.Model):
title = models.CharField(max_length=64)
content = models.TextField()
def __str__(self):
return self.title
Views
from django.views.generic.list import ListView
from django.views.generic.detail import DetailView
from app.models import Entry
class EntryListView(ListView):
model = Entry
paginate_by = 100 # if pagination is desired
def get_queryset(self):
queryset = super().get_queryset()
q = self.request.GET.get("q")
if q:
queryset = queryset.filter(title__icontains=q)
return queryset
class EntryDetailView(DetailView):
model = Entry
Urls
from django.urls import path
from app.views import EntryListView, EntryDetailView
urlpatterns = [
path('', EntryListView.as_view(), name='entry-list'),
path('<int:pk>/', ArticleDetailView.as_view(), name='entry-detail'),
]
I cannot save the data taken from the form to database. The form is displayed properly and it seems that I can submit. Whenever I was redirected to "project_list.html", I cannot see the new project.
I also checked the admin site to whether new instance is saved to model but it seems that something is wrong with my code.
Here is my files:
model.py
class Project(models.Model):
project_id = models.CharField(max_length=30)
project_name = models.CharField(max_length=100)
view.py
def projects_list(request):
projects = Project.objects.all()
table = ProjectTable(Project.objects.all())
RequestConfig(request, paginate={'per_page':25}).configure(table)
return render(request, 'portal/project/list.html', {'projects':
projects, 'table': table})
def project_add(request):
if request.method == 'POST':
form = ProjectAddForm(request.POST)
if form.is_valid():
form.save()
return redirect('project_list',)
else:
form = ProjectAddForm()
return render(request, 'portal/project/add.html', {'form': form})
forms.py
from django import forms
from .models import Project
class ProjectAddForm(forms.ModelForm):
class Meta:
model = Project
fields = ['project_id', 'project_name',]
add.html
{% extends 'portal/base.html' %}
{% block title %}Add Project{% endblock title %}
{% block content %}
<div class="col-sm-10 offset-sm-1 text-center">
<form action="{% url 'portal:projects_list' %}" method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit">
</form>
</div>
{% endblock content %}
projects_list.html
{% extends 'portal/base.html' %}
{% load render_table from django_tables2 %}
{% block content %}
<h1>Projects List</h1>
{% render_table table %}
{% endblock content %}
urls.py
from django.urls import path
from . import views
app_name = 'portal'
urlpatterns = [
path('', views.homepage, name='homepage'),
path('password_generator/', views.password_generator,
name='password_generator'),
path('projects_list/', views.projects_list, name='projects_list'),
path('project/<str:project_id>/', views.project_detail,
name='project_detail'),
path('add/', views.project_add, name='project_add'),
]
I found the issue in my code. In my project_add view, I was trying to redirect to "project_list" url but it didnt exists. That was the mistake....
I have designed a model in Django and a form according to it. The below are the both files.
models.py
from django.db import models
class TotalEvent(models.Model):
CustomerID = models.CharField(max_length=30)
eventID = models.CharField(max_length=100)
eventPlace = models.CharField(max_length=100)
eventStartTime = models.TimeField(auto_now=False)
eventDate = models.DateField(auto_now=False)
forms.py
from django import forms
from django.forms import ModelForm
from catering.models import TotalEvent
class TotalEventForm(ModelForm):
class Meta:
model = TotalEvent
fields = '__all__'
Now, When in my html file I tried this:
{% extends "base.html" %}
{% block title %}Log-in{% endblock %}
{% block content %}
<h1>Detail page</h1>
<p>Enter your schedule details here</p>
<form method="post">{% csrf_token %}
{% for field in forms %}
{{field}}
<input type="submit" value="Submit"/>
{% endfor %}
</form>
{% endblock %}
views.py
from django.shortcuts import render
from catering.forms import TotalEvent
def add(request):
if request.method == 'POST':
form = TotalEvent(request.POST)
if form.is_valid():
form.save()
return render(request, 'index.html', { 'form': TotalEvent()
})
In the output it shows no input fields except the following output
Enter your schedule details here
Please have a look and let me know where is the error.
Use TotalEventForm instead TotalEvent as TotalEvent is model class not form class, update your views.py
def add(request):
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = TotalEventForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
return HttpResponseRedirect('/thanks/')
# if a GET (or any other method) we'll create a blank form
else:
form = TotalEventForm()
return render(request, 'index.html', {'form': form})
and you can use form directly in your html file.
<form method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit"/>
</form>
type
{% for field in form %}
instead of
{% for field in forms %}