Why does my Django CreateView not recognise form_valid - django

I am using the django allauth module to create a user. In views,py I am subclassing CreateView, but I cannot get form_valid to work. It seems not to be being called (I have not imported HttpResponseRedirect but it doesn't complain
class SignupPageView(generic.CreateView):
form_class = CustomUserCreationForm
success_url = reverse_lazy('login')
template_name = 'registration/signup.html'
def form_valid(self, form):
print('form_valid')
return HttpResponseRedirect(self.get_success_url())
def form_invalid(self, form):
print('form_invalid')
return HttpResponseRedirect(self.get_success_url())
What am I doing wrong?
EDIT
I have also added form_invalid and it still doesn't fail. This leads me to think that something fundamental is awry.
The user registration process seems to function correctly and no errors are reported
The html associated with the form is
{% extends '_base.html' %}
{% load crispy_forms_tags %}
{% block title %}Sign Up{% endblock title %}
{% block content %}
<h2>Sign Up</h2>
<form method="post">
{% csrf_token %}
{{ form | crispy }}
<button type="submit">Sign Up</button>
</form>
{% endblock content %}
urls.py
urlpatterns = [
path('signup/', SignupPageView.as_view(), name='signup'),
]

CreateView inherits methods of FormMixin which has both form_valid and form_invalid. So there's nothing wrong with your CBV declaration.
So I think that your form just isn't valid. Could you try to add form_invalid method and see if it would be called?

Related

Rendering the page in django with html form

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})

Django bootstrap4 - Parameter "form" should contain a valid Django Form

I am getting the following Bootstrap exception
'Parameter "form" should contain a valid Django Form.'
when running the following code from this tutorial:
{% load bootstrap4 %}
<form action="/url/to/submit/" method="post" class="form">
{% csrf_token %}
{% bootstrap_form form %}
{% buttons %}
<button type="submit" class="btn btn-primary">Submit</button>
{% endbuttons %}
</form>
Is the second'form' in 'bootstrap_form form' supposed to reference/point to something? Is it a variable? What is a valid django form? I checked several posts and answers on this issue, but haven't been able to make sense of this error.
EDIT View code:
from django.shortcuts import render
def hello_world(request):
return render(request, 'hello_world.html', {})
I got the same problem and it takes me nearly whole day to figure out.
The Quickstart part of django-bootstrap4 is not very starter-friendly.
{% bootstrap_form form %}
The form is a parameter, which should be transfered from views.py. In your situation, form should be added to return render(request, 'hello_world.html', {})
create a file called forms.py and put following code in it.
(forms.py should be put in the same folder of views.py)
from django import forms
class NameForm(forms.Form):
your_name = forms.CharField(max_length=100)
modify views.py and add the following code:
# ...
from .forms import NameForm
# ...
def hello_world(request):
form = NameForm()
return render(request, 'hello_world.html', {'form': form})
# ...

Django can't save new instance to model

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

How to add user authentication in generic delete view in django2.0.6

I have a page which displays posts of all user and user can only delete his posts.
Heres the code:
class PostDelete(generic.DeleteView):
model = Post
template_name = 'dashboard/post_delete.html'
success_url = reverse_lazy('dashboard:posts')
post_delete.html:
{% extends 'dashboard/sidebar.html' %}
{% block title %}Confirmation{% endblock %}
{% block mainpage %}
<div id="page-wrapper" align="center">
<div id="page-inner">
<h1>New post</h1>
<form method="post">
{% csrf_token %}
Are you sure you want to delete?
<br>
<button class="btn btn-danger">Yes</button>
No
</form>
</div>
</div>
{% endblock %}
Urls.py:
path('delete/<int:pk>',views.PostDelete.as_view(),name='delete'),
How do I add user authentication code?
If it were a function I would have used " if request.user.is_authenticated "
But I don't know how to achieve this thing in a class. If you need an excerpt of another code then comment. Thanks!
Try to use UserPassesTestMixin:
from django.contrib.auth.mixins import UserPassesTestMixin
class PostDelete(UserPassesTestMixin, generic.DeleteView):
model = Post
template_name = 'dashboard/post_delete.html'
success_url = reverse_lazy('dashboard:posts')
raise_exception = True
def test_func(self):
self.object = self.get_object()
return self.object.user == self.request.user

Django: Testing Formview can't submit form

I'm just doing a quick test of a CBV Formview. However for some reason the form won't submit and I've gone blind from looking at it to find out why. There is no error shown, when I click on submit nothing happens and it doesn't redirect to the success url or print out the test message.
Form:
class EmailTestForm(forms.Form):
email = forms.EmailField()
View:
class EmailTestFormView(FormView):
form_class = EmailTestForm
template_name = "site/test_email.html"
success_url = "/signup"
def form_valid(self, form):
print('form is good')
Template:
{% extends "site/signup.html" %}
{% load crispy_forms_tags %}
{% block inner %}
<form action="" method="post" >{% csrf_token %}
{% crispy form %}
<input id="submit" class="btn btn-block btn-cta-primary" type="submit"/>
</form>
{% endblock inner %}
urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^signup/$', views.signup_view, name="signup"),
url(r'^emailtest/$', views.EmailTestFormView.as_view(), name="email_test"),
]
this is caused by using cripsy forms to render the form, which automatically inserts a <form> tag when rendering the form.
From cripsy form docs:
form_tag = True
It specifies if <form></form> tags should be rendered when using a Layout. If set to False it renders the form without the <form></form> tags. Defaults to True.