I have a Flask form and it adds entries into db without issues.
However, when I click 'submit' on the empty form, it adds null entries. I already have limitation set to 'DataRequired'. What else do I need to stop this from happening?
My form:
class AddNoteForm(FlaskForm):
note = StringField('Note',[DataRequired()])
add = SubmitField('Add Note')
My model:
class Note(db.Model):
id = db.Column(db.Integer,primary_key = True)
note = db.Column(db.String(150),nullable = False)
date_added = db.Column(db.DateTime,default = datetime.utcnow)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
My routes.py:
#routes.route('/userpage',methods=['GET','POST'])
#login_required
def userpage():
print('page start')
session.get("current_user")
user_notes = Note.query.filter_by(user_id = current_user.id)
if request.method == "POST":
print('method is post')
if current_user.is_authenticated:
print ('user in session')
note = Note(note = request.form.get('addnote'), user_id = current_user.id)
db.session.add(note)
db.session.commit()
return render_template('userpage.html', note=note, user_notes=user_notes)
else:
print('user not in session"')
return render_template('userpage.html')
return render_template('userpage.html', user_notes=user_notes)
my form-html:
{% extends 'base.html' %}
{% block body %}
<p>Welcome {{ current_user.name }}</p>
<br>
<form method='post'>
<table>
<tr>
<td></td> <input type="text", name ="addnote", placeholder="Add note"/>
</tr>
</table>
<input class ="button" , type="submit" />
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
<p>
{% for item in user_notes %}
<li class = "diary"> {{ item.note }}</li>
{% endfor %}
</p>
</form>
{% endblock %}
Related
I am trying to render a formset with crispy forms in Django, utilizing an add-more forms button. However I can't figure out how to apply the same CSS to the empty form as the original form. The only way I have been successful is creating a new empty form like this solution, but this adds in another <form> tag which is a problem that isn't covered in the solution. How can I apply CSS to the dynamically added formset?
The below image is the expected result once I click the add more ingredients <button>:
forms.py
from .models import Recipe, RecipeIngredient
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Div, Layout, Field
class RecipeIngredientForm(forms.ModelForm):
class Meta:
model = RecipeIngredient
fields = ['name', 'quantity', 'unit', 'description']
labels = {
'name': "Ingredient",
"quantity:": "Ingredient Quantity",
"unit": "Unit",
"description:": "Ingredient Description"}
def __init__(self, *args, **kwargs):
super(RecipeIngredientForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_id = 'id-entryform'
self.helper.form_class = 'form-inline'
self.helper.layout = Layout(
Div(
Div(Field("name", placeholder="Chickpeas"), css_class='col-6 col-lg-4'),
Div(Field("quantity", placeholder="2 x 400"), css_class='col-6 col-md-4'),
Div(Field("unit", placeholder="grams"), css_class='col-5 col-md-4'),
Div(Field("description", placeholder="No added salt tins"), css_class='col-12'),
css_class="row",
),
)
views.py:
def recipe_create_view(request):
form = RecipeForm(request.POST or None)
RecipeIngredientFormset = formset_factory(RecipeIngredientForm, prefix="ingredient")
formset = RecipeIngredientFormset(request.POST or None)
context = {
"form": form,
"formset": formset,
}
if request.method == "POST":
#print(request.POST)
if form.is_valid() and formset.is_valid():
parent = form.save(commit=False)
parent.user = request.user
parent.save()
#recipe ingredients
for form in formset:
child = form.save(commit=False)
if form.instance.name.strip() == '':
pass
else:
child.recipe = parent
child.save()
else:
form = RecipeForm(request.POST or None)
formset = RecipeIngredientFormset()
return render(request, "recipes/create.html", context)
create.html
{% load crispy_forms_tags %}
<form action='/recipes/create/' method="POST" >
<!-- MAIN RECIPE FORM-->
{% csrf_token %}
<div class='row'>
{% for recipe in form %}
<div class="col-6 col-md-3 py-2">
{{ recipe|as_crispy_field }}
</div>
{% endfor %}
<div>
<!--RECIPE INGREDIENTS - WHERE CSS ISSUE IS -->
{% if formset %}
<h3>Ingredients</h3>
{{ formset.management_form|crispy }}
<div id='ingredient-form-list'>
{% for ingredient in formset %}
<div class='ingredient-form'>
{% crispy ingredient %}
</div>
{% endfor %}
</div>
<div id='empty-form' class='hidden'>{% crispy formset.empty_form %}</div>
<button class="btn btn-success" id='add-more' type='button'>Add more ingredients</button>
{% endif %}
</div>
<script>
//ingredients add form
const addMoreBtn = document.getElementById('add-more')
const totalNewForms = document.getElementById('id_ingredient-TOTAL_FORMS')
addMoreBtn.addEventListener('click', add_new_form)
function add_new_form(event) {
if (event) {
event.preventDefault()
}
const currentIngredientForms = document.getElementsByClassName('ingredient-form')
const currentFormCount = currentIngredientForms.length // + 1
const formCopyTarget = document.getElementById('ingredient-form-list')
const copyEmptyFormEl = document.getElementById('empty-form').cloneNode(true)
copyEmptyFormEl.setAttribute('class', 'ingredient-form')
copyEmptyFormEl.setAttribute('id', `ingredient-${currentFormCount}`)
const regex = new RegExp('__prefix__', 'g')
copyEmptyFormEl.innerHTML = copyEmptyFormEl.innerHTML.replace(regex, currentFormCount)
totalNewForms.setAttribute('value', currentFormCount + 1)
// now add new empty form element to our html form
formCopyTarget.append(copyEmptyFormEl)
}
</script>
The problem is shown in the below image, this creates another form rather that just adding the fields:
If I use {{ formset.empty_form|crispy }} instead of {% crispy formset.empty_form %} the script works fine, but the CSS is not attached to the form.
Had to use a combination of both methods for this to work, below is the changes to the questions code:
create.html
<div>
<!--RECIPE INGREDIENTS-->
{% if formset %}
<h3 class="mt-4 mb-3">Ingredients</h3>
{{ formset.management_form|crispy }}
<div id='ingredient-form-list'>
{% for ingredient in formset %}
<div class='ingredient-form'>
{% crispy ingredient %}
</div>
{% endfor %}
</div>
<div id='empty-form' class='hidden'>
<div class="row mt-4">
<div class="col-6">{{ formset.empty_form.name|as_crispy_field }}</div>
<div class="col-6">{{ formset.empty_form.quantity|as_crispy_field }}</div>
<div class="col-6">{{ formset.empty_form.unit|as_crispy_field }}</div>
</div>
</div>
<button class="btn btn-success my-2" id='add-more' type='button'>Add more ingredients</button>
{% endif %}
</div>
<div>
I would like to use Bootstrap 4 forms. This means I need to add the class form-check-label to the label of a checkbox. How can I do that?
Minimal Code Sample
requirements.txt
Flask==1.0.2
WTForms==2.2.1
Flask-WTF==0.14.2
app.py:
from flask import Flask, render_template
from flask_wtf import FlaskForm
from wtforms import BooleanField, StringField, PasswordField, SubmitField
app = Flask(__name__, template_folder="templates")
app.config['SECRET_KEY'] = 'http://flask.pocoo.org/docs/1.0/quickstart/#sessions'
class LoginForm(FlaskForm):
username = StringField('Username')
password = PasswordField('Password')
remember_me = BooleanField("Remember Me")
submit = SubmitField('Submit')
#app.route('/')
def index():
form = LoginForm()
return render_template('login.html', form=form)
app.run()
templates/login.html:
<form action="" method="post" class="form form-horizontal" role="form">
{{ form.hidden_tag() }}
<div class="form-group">
{{ form.username.label }}<br>
{{ form.username(size=32, class_="form-control") }}<br>
{% for error in form.username.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</div>
<div class="form-group">
{{ form.password.label }}<br>
{{ form.password(size=32, class_="form-control") }}<br>
{% for error in form.password.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</div>
<div class="form-check">
{{ form.remember_me.label }}<br> # form-check-label
{{ form.remember_me(value='n', class_="form-check-input") }}
{% for error in form.remember_me.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</div>
{{ form.submit(class_="btn btn-primary") }}
</form>
The solution turned out to be super simple - I can call .label also as a function identical to the other elements:
{{ form.remember_me.label(class_="form-check-label") }}
How to send information on my email from django form. Now I can see information only in my console output on my cmd
template:
{% extends 'base.html' %}
{% load widget_tweaks %}
{% block title %}
Contact Us
{% endblock %}
{% block content %}
<h2 class="mt-4 ml-4">Contact Me</h2>
<form method="post">
<div class="container mt-4">
{% csrf_token %}
<div class="col-md-4">
{{ form.subject.label }}
{% render_field form.subject class+="form-control" %}
</div>
<div class="col-md-4">
{{ form.email.label }}
{% render_field form.email type="email" class+="form-control" %}
</div>
<div class="col-md-4">
{{ form.message.label }}
{% render_field form.message class+="form-control" rows="4" cols="6" %}
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary mt-2 ml-3">Send</button>
</div>
</div>
</form>
{% endblock %}
forms.py:
from django import forms
class ContactForm(forms.Form):
email = forms.EmailField(required=True)
subject = forms.CharField(required=True)
message = forms.CharField(widget=forms.Textarea, required=False)
views.py:
from django.core.mail import send_mail, BadHeaderError
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render, redirect
from .forms import ContactForm
def emailView(request):
if request.method == 'GET':
form = ContactForm()
else:
form = ContactForm(request.POST)
if form.is_valid():
subject = form.cleaned_data['subject']
email = form.cleaned_data['email']
message = form.cleaned_data['message']
try:
send_mail(subject, message, email, ['yarik.nashivan#gmail.com'])
except BadHeaderError:
return HttpResponse('Invalid header found.')
return redirect('success')
return render(request, "email.html", {'form': form})
def successView(request):
return HttpResponse('Success! Thank you for your message. <p>You will be redirected to the main page in 3 seconds.</p> <meta http-equiv="refresh" content="3;url=/"> ')
Don't look at it: fgkjdfldfjgndfkgndfskj vdafk kjdsjaf jjjfd jdsaf dj fdsjn dnjndfj jdffjk hdsffdfgfdb sfdf
Well, you are using console backend, that is why you are seeing the message in console. If you use SMTP backend, then you can send this email to your acccount. For that, you need to configure like this:
First you need to update the backend in settings.py:
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
Then update the smtp configurations in settings.py:
# this configuration is for gmail
EMAIL_USE_TLS = True
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = 'test#gmail.com'
EMAIL_HOST_PASSWORD = 'test'
EMAIL_PORT = 587
For details, please check the email documentation for Django.
I keep getting UNIQUE constraint failed when trying to update data in my database. I am using username as the primary_key, but this code works just fine when I construct an object and add it to the database in the terminal. It is only when I try it in my views.py that I have issues.
Here is the error
IntegrityError: (sqlite3.IntegrityError) UNIQUE constraint failed: mobility.username [SQL: u'INSERT INTO mobility (username, cc_letter, sabc_cbt) VALUES (?, ?, ?)'] [parameters: (u'pass', u'tt', None)]
File "/home/jsnyder10/Documents/45/app/views.py", line 57, in mobility_edit_user
db.session.commit()
views.py - this is the one causing issue at db.session.commit()
#app.route('/mobility_edit_user', methods=['GET', 'POST'])
#login_required
def mobility_edit_user():
#build user list
data=User.query.with_entities(User.username).all()
users=[]
for i in data:
users.append(i[0])
form=MobilityForm(request.form)
if request.method == "POST":
if request.form['submit']=='SelectUser':
#moves selected user to front of form to persist with next call
users.insert(0, users.pop(users.index(request.form.get('user'))))
data=Mobility.query.filter_by(username=request.form.get('user')).first()
#form.populate_obj(data)
form=MobilityForm(obj=data)
flash("Selected User " + request.form.get('user'))
elif request.form['submit']=='Update' and form.validate():
print("validated")
u=Mobility()
form.populate_obj(u)
u.username=request.form.get('user')
db.session.add(u)
print("added")
db.session.commit()
flash("Updated User" + request.form.get('user'))
else:
#move selected user to front of form
users.insert(0, users.pop(users.index(request.form.get('user'))))
data=Mobility.query.filter_by(username=request.form.get('user')).first()
form=MobilityForm(obj=data)
flash("Form not validated")
elif request.method == "GET":
form=MobilityForm(request.form)
flash("GET")
return render_template('mobility_edit_user.html',title='Mobility Edit User',
form=form, users=users)
models.py
class MobilityForm(ModelForm):
class Meta:
model=Mobility
forms.py
class MobilityForm(ModelForm):
class Meta:
model=Mobility
mobility_edit_users.html
<!-- extend base layout -->
{% extends "base.html" %}
{% block content %}
{% from "_formhelpers.html" import render_field %}
{% include 'flash.html' %}
<div class="well">
<form class="form-horizontal" action="" method="post" name="edit">
<div class="control-group">
<input class="btn btn-primary" type="submit" name="submit" value="SelectUser">
<input class="btn btn-primary" type="submit" name="submit" value="Update">
</div>
<div class="control-group">
<select name="user">
{% for user in users %}<option value={{ user }}>{{ user }}</option>{% endfor %}
</select>
</div>
<table border="1" cellpadding="5" cellspacing="5" width="100%" style="background color:white">
{% for attr, value in form._fields.iteritems() %}
<tr>
<th>{{ attr }}</th>
<td>{{ value }}</td>
</tr>
{% endfor %}
</table>
</form>
</div>
{% endblock %}
I have following code in my twig file:
<form method ="POST" action="{{path('deleteMessages')}}">
{% for message in pmReceived %}
{% if message.isread == false %}
{% if message.showincoming == true %}
<div class="border">
<div class="pmbox">
<p class="pmsender">{{message.sender}}</p><p class="pmdate">{{message.date|date('d-m-Y H:i:s') }}</p><p class="pmsubject">{{message.subject}}</p><input type="checkbox" name="deletePm" value="{{message.pmid}}">
</div>
<div class="pmcontents">
<p class="titleContent">Contents:</p>
<p>{{message.contents}}</p>
</div>
</div>
{% endif %}
{% endif %}
{% endfor %}
{% for message in pmReceived %}
{% if message.isread == true %}
{% if message.showincoming == true %}
<div class="border">
<div class="pmbox">
<p class="pmsender">{{message.sender}}</p><p class="pmdate">{{message.date|date('d-m-Y H:i:s') }}</p><p class="pmsubject">{{message.subject}}</p><input type="checkbox" name="deletePm" value="{{message.pmid}}">
</div>
<div class="pmcontents">
<p class="titleContent">Contents:</p>
<p>{{message.contents}}</p>
</div>
</div>
{% endif %}
{% endif %}
{% endfor %}
<button class="deleteButton" type="submit">Delete selected messages</button>
</form>
This is my controller code:
public function deleteMessagesAction(Request $request) {
if (false === $this->get('security.context')->isGranted('IS_AUTHENTICATED_FULLY')) {
throw $this->createAccessDeniedException('Unable to access this page!');
}
$em = $this->getDoctrine()->getEntityManager();
$pm = $this->getDoctrine()
->getRepository('LoginLoginBundle:Privatemessage')
->findBypmid($request->get('sentValue'));
$deleteMessages = $request->get('deletePm');
var_dump($deleteMessages);
$user = $this->get('security.context')->getToken()->getUser();
$pmReceived = $this->getDoctrine()
->getRepository('LoginLoginBundle:Privatemessage')
->findByReceiver($user->getUsername());
$pmSent = $this->getDoctrine()
->getRepository('LoginLoginBundle:Privatemessage')
->findBySender($user->getUsername());
return $this->render('LoginLoginBundle:Default:pmPage.html.twig', array('pmReceived' => $pmReceived, 'pmSent' => $pmSent, 'toDelete'=>$deleteMessages));
}
Now I want to get the value of all the 'ticked' checkboxes, I supposed $deleteMessages would be an array of values, but it only holds the last checkbox that is ticked.
How can I get an array of all the values in my controller?
U need to alter the name of your inputs.
This way u will receive an array of checked checkboxes instead of only the last checked one:
<input type="checkbox" name="deletePm[]" value="{{message.pmid}}">
This will result in an array equal to :
[
0 => 1,
1 => 10,
2 => ...,
]
U then can just loop this array to delete accordingly :
$deleteMessages = $request->get('deletePm');
foreach($deleteMessages as $deleteMessageId) {
//Do something with the ID
}