I've been trying to determine where this validation/error message and styling is coming from but I can't narrow it down? I've reduced the template to a basic template so that it isn't loading base.html any longer but the tooltip still appears somehow.
However the tooltip and message don't appear in safari - it just defaults to the standard django email validation message "Enter a valid email address".
Note I have selected don't use disable cache in chrome dev tools (network) but that didn't help.
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:
{% 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"),
]
Related
I am trying to handle login/registration functionality in a modal. I got successful login/registration working by importing the LoginForm and RegistrationForm into my modal view and then posting to the appropriate allauth URLs. The desired behavior is to have forms with errors rendered asynchronously in the modal.
I have not been able to get forms with errors (email doesn't exist when trying to login, passwords don't match when registering etc.) to render as an html partial in a modal with the errors. I'm not too sure where to start when trying to add this functionality into my own view/how to piggyback on the allauth views and change their functionality.
Adding the below to my views.py and url.py I've managed to get the allauth default template to load when the form is invalid (e.g. email field does not contain a valid email) but have not been able to get my template to load.
From views.py:
class LoginViewSnippet(LoginView):
success_url = reverse_lazy('home')
template_name = 'user_app/partials/loginmodal.html'
def get_context_data(self, **kwargs):
print('here1')
context = super(LoginView,self).get_context_data(**kwargs)
return context
def form_invalid(self, form):
print('here')
error_msg = 'error'
return HttpResponse(error_msg, status=400)
login = LoginViewSnippet.as_view()
From urls.py:
path('accounts/login',user_app_views.login, name='account_login'),
From user_app/partials/loginmodal.html:
...
<div class="modal-body">
<form id="loginform" method="POST" action="{% url 'account_login' %}" autocomplete="off">
{% csrf_token %}
{% for field in loginform %}
<div class="form-group mb-3">
{{ field.errors }}
{{ field | as_crispy_field }}
</div>
{% endfor %}
</form>
</div>
<div class="mx-auto">
<button form="loginform"type="submit" class="btn btn-success" hx-post="{% url 'account_login' %}" hx-target="#modals-here">Login</button>
<button type="button" class="btn btn-secondary" onclick="closeModal()">Close</button>
</div>
...
In my template I have a form that includes two input elements whose values can be adjusted with javascript. I want to be able to take these values and, on form submit, display them in a sentence in a for loop underneath.
index.html:
<form action="{% url 'workouts:workout' %}" method="post">
{% csrf_token %}
<div class="weight">
<h4>WEIGHT (kgs):</h4>
<button type="button" class="weight-dec">-</button>
<input type="text" value="0" class="weight-qty-box" readonly="" name="one">
<button type="button" class="weight-inc">+</button>
</div>
<div class="reps">
<h4>REPS:</h4>
<button type="button" class="rep-dec">-</button>
<input type="text" value="0" class="rep-qty-box" readonly="" name="two">
<button type="button" class="rep-inc">+</button>
</div>
<input type="submit" value="Save" name="submit_workout">
<input type="reset" value="Clear">
</form>
{% if exercise.workout_set.all %}
{% for w in exercise.workout_set.all %}
{{ w.content }}
{% endfor %}
{% endif %}
I have given the form above an action attribute for a url which maps to a view, and each of the inputs has a name in order to access their values in the view. I also have written this form in forms.py:
class WorkoutModelForm(forms.ModelForm):
class Meta:
model = Workout
fields = ['content']
And for context, here is my model:
class Workout(models.Model):
content = models.CharField(max_length=50)
created = models.DateField(auto_now_add=True)
updated = models.DateField(auto_now=True)
exercise = models.ForeignKey(Exercise, on_delete=models.CASCADE, default=None)
class Meta:
ordering = ('created',)
My problem from here is that I have no idea how to actually incorporate my model form in my template, or how to write a view that will do what I want it to. I am still new to this and have been searching for an answer for sometime, but so far have not found one. Please help.
This is able to help you, you should first have a look at the django Class-Based Views , more specifically the FormView, django already has generic views capable of handling data posted on forms. Your code would look like this:
# forms.py
# imports ...
class WorkoutModelForm(forms.ModelForm):
class Meta:
model = Workout
fields = ['content']
# urls.py
from django.urls import path
from . import views
app_name = 'myapp'
urlpatterns = [
path("test-form/", views.TesteFormView.as_view(), name='test-form'),
]
# views.py
from django.views.generic import FormView
from myapp import forms
from django.contrib import messages
class TesteFormView(FormView):
template_name = "myapp/index.html"
success_url = reverse_lazy('myapp:test-form')
form_class = forms.WorkoutModelForm
def get(self, request, *args, **kwargs):
return super(TesteFormView, self).get(request, *args, **kwargs)
def form_valid(self, form):
print(f"POST DATA = {self.request.POST}") # debug
content = form.cleaned_data.get('content')
# fieldx= form.cleaned_data.get('fieldx')
# do something whit this fields like :
Workout.object.create(content=content)
messages.success(self.request,"New workout object created")
return super(TesteFormView, self).form_valid(form=self.get_form())
def form_invalid(self, form):
print(f"POST DATA = {self.request.POST}") # debug
for key in form.errors:
messages.error(self.request, form.errors[key])
return super(TesteFormView, self).form_invalid(form=self.get_form())
And your template would look like:
# myapp/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>TestForm</title>
</head>
<body>
<form method="post">
{% csrf_token %}
{{ form }}
<button type="submit">submit</button>
</form>
</body>
</html>
I'm looking for a solution to update an object without having to go to the detail page but, just edit it on the page itself. What I want to achieve is when I click on edit: the object becomes a field where I can edit and save it. All the YouTube tutorials show the edit->detail page version.
So a quick/direct edit on the object itself that is on the homepage without leaving the homepage.
I have tried to use the UpdateView on this but then there is separate HTML file necessary, which would result in leaving the homepage. I would like to get some help or tips on this.
urls.py
from django.urls import path
from .views import (
HomePageView,
TaskCreateView,
TaskDeleteView,
TaskUpdateView,
)
urlpatterns = [
path('', HomePageView.as_view(), name='home'),
path('task_new/', TaskCreateView.as_view(), name='task_new'),
path('<int:pk>/task_delete/', TaskDeleteView.as_view(), name='task_delete'),
path('<int:pk>/task_edit/', TaskUpdateView.as_view(), name='task_edit'),
]
views.py
from django.views.generic import ListView
from django.views.generic.edit import CreateView, DeleteView, UpdateView
from django.urls import reverse_lazy
from .models import Task
class HomePageView(ListView):
model = Task
template_name = 'home.html'
context_object_name = 'all_tasks_list'
class TaskCreateView(CreateView):
model = Task
fields = ['text',]
class TaskDeleteView(DeleteView):
model = Task
success_url = reverse_lazy('home')
class TaskUpdateView(UpdateView):
model = Task
fields = ['text',]
home.html
<!DOCTYPE html>
<html>
<head>
<title>Todo app</title>
</head>
<body>
<h1>Todo app</h1>
<ul>
{% for task in all_tasks_list %}
<li>{{ task.text }}</li>
<form action="{% url 'task_delete' task.pk %}" method="post">{% csrf_token %}
<input type="submit" value="Delete"/></form>
<form action="{% url 'task_edit' task.pk %}" method="post">{% csrf_token %}
<input type="submit" value="Edit"/>
</form>
{% endfor %}
</ul>
<form action="{% url 'task_new' %}" method="post">{% csrf_token %}
<input type="text" name="text"/>
<input type="submit" value="Add"/>
</form>
</body>
</html>
models.py
from django.db import models
from django.urls import reverse
class Task(models.Model):
text = models.TextField()
def __str__(self):
return self.text[:50]
def get_absolute_url(self):
return reverse('home')
The error says task_form.html doesn´t exist, default template for an UpdateView. Are you sure it exists? If you want to use another template you have to specify
class TaskUpdateView(UpdateView):
model = Task
fields = ['text',]
template_name = 'todoapp/my_template.html'
Considering you are using generic view you should follow documentation for UpdateView
In this particular case you are missing form that UpdateView looks for to render GET request
The UpdateView page displayed to a GET request uses a
template_name_suffix of '_form'.
In your particular case it is todoapp/task_form.html which you should create
<form method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Update"> </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.
I am newbie to python as well as Django, and I have started a sample project "blog".
Currently blog posts are added to the database manually, but I want to do it at front end by providing a form to the user. I created my model.py and views.py files, but I am unable to see these fields on the front end. I have copied all of my code below:
models.py:
class posts(models.Model):
author = models.CharField(max_length = 30)
title = models.CharField(max_length = 100)
bodytext = models.TextField()
timestamp = models.DateTimeField()
class postForm(ModelForm):
class Meta:
model = posts
views.py:
def home(request):
content = posts.objects.all()[:5]
return render_to_response('index.html',{'posts' : content})
def save_blog(request):
form = postForm
if request.POST:
form = postForm(request.POST)
if form.is_valid():
form.save
return render_to_response('index.html',{'form' : form},context_instance=RequestContext(request))
url.py:
from django.conf.urls import patterns, include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns =
patterns('',
url(r'^$', 'blog.views.home', name='home'),
url(r'^admin/', include(admin.site.urls))
)
index.html:
<body>
<div class="container">
<h1>Welcome To</h1>
<hr />
{% for post in posts %}
<div class="posts">
<h2>{{ post.title }}</h2>
<h3>Posted on {{ post.timestamp }} by {{ post.author }}</h3>
<p>{{ post.bodytext }}</p>
</div>
<hr />
{% endfor %}
</div>
<div class="forms">
<form action="." method="post" name="posts" id="posts">{% csrf_token %}
<table>
<tr><td>{{form.author.label}}</td><td>{{form.author}}</td></tr>
<tr><td>{{form.title.label}}</td><td>{{form.title}}</td></tr>
<tr><td>{{form.bodytext.label}}</td><td>{{form.bodytext}}</td></tr>
<tr><td></td><td><input type="button" name="btnSave" id="bntSave" value="Submit" class = "default2"/></td>
</table>
</form>
</div>
</body>
settings.MIDDLEWARE_CLASSES:
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
)
Please let me know if i am missing anything. Also let me know how can I achieve this without using a Django model form.
Thanks
views.py
def home(request):
content = posts.objects.all()[:5]
form = postForm()
if request.POST:
form = postForm(request.POST)
if form.is_valid():
form.save()
return render_to_response('index.html',{'posts' : content, 'form' : form}, context_instance=RequestContext(request))
index.html
<div class="forms">
<form method="post" name="posts" id="posts">
{% csrf_token %}
{{ form.as_table }}
<input type="button" name="btnSave" id="bntSave" value="Submit" class="default2"/> //<---------------
</form>
</div>
UPDATE:
Ok I see it now why it's not submitting. You put button instead of submit in the input type
<input type="submit" name="btnSave" id="bntSave" value="Submit" class="default2"/> //<---------------
Just add auto_now_add in your timestamp field
timestamp = models.DateTimeField(auto_now_add=True)
It looks like you called your form postForm but are using posts_form in your view...
I also am unsure what form_save is, you should be calling save() on the form instance like
if form.is_valid():
form.save()
And after posting, it is common practice to redirect the user to another url to prevent resubmitting data.