Using quick_form Flask-Bootstrap to generate the form is very convenient for me, however, I could not find in their documentation a way that I can add extras class to label as required by my template theme.
My forms.py class look like this:
from flask_wtf import Form
from wtforms import StringField,PasswordField,TextField,SubmitField
from wtforms.validators import InputRequired,EqualTo,Email,ValidationError
class Building_Form(Form):
BuildingName = TextField('Building Name')
BuildingType = TextField('Building Type')
FloorNums = TextField('Numers of Floor')
BuildUnits = TextField('Units in Building')
BuildSize = TextField('Building Size')
BuiltYear = TextField('Built in (year)')
BuildOpeningTime = TextField('Open Time')
BuildClosingTime = TextField('Close Time')
My routes.py is like following:
from app.import_core import *
from flask_wtf import FlaskForm
from wtforms import Form, BooleanField, StringField, PasswordField, validators
from wtforms.validators import DataRequired
from flask_wtf.file import FileField, FileRequired
from werkzeug.utils import secure_filename
from werkzeug.security import generate_password_hash, check_password_hash
from .forms import Building_Form
# from app.user.models import TBL_USER
import pdb
#app.route('/building')
def show_building_listing():
return render_template('building_listing.html')
#app.route('/builing/new',methods=['GET','POST'])
def add_new_builing():
form = Building_Form()
if request.method=='POST':
return '<h1>Ok Building added</h1>'
return render_template('new_building.html',form=form)
My new_building.html to render a form:
{% extends "__dashboard.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block include_css %}
<link rel="stylesheet" href="{{url_for('static',filename='css/login.css')}}">
<link rel="stylesheet" href="{{url_for('static',filename='css/bt-social-button/bootstrap-social.css')}}">
{% endblock %}
{% block content %}
<div class="card">
<div class="card-body">
{{ wtf.quick_form(form, extra_classes='bmd-label-floating') }}
</div>
</div>
{% endblock %}
I would like to add classes bmd-label-floating to my form label however it ended up with those classes in <form> instead.
How can I add that class my labels? Thanks.
I had a similar problem. A list of items was used to generate a form with multiple checkboxes. I needed to add a label class for styling them horizontally. I was able to loop through my form object and change class for the form field.label.
<form action="" method="post">
{% with test = form.example %}
{% for field in test %}
{{ field.label(class_='checkbox-inline') }}
{{ field }}
{% endfor %}
{% endwith %}
<p>{{ form.submit() }}</p>
</form>
Related
I am trying to create a webpage which has two parts.
An index list of all items (that persists throughout)
Detail of the selected index item
I created a LIST VIEW and a DETAIL VIEW for the same but the problem is both views cannot be called on the same template.
I tried to list all the items in 'reports_list.html' and then inherit this template to 'report_detail.html' to see if the index list stays but it doesn't.
Is there a way to accomplish this?
CODE:
views.py
from django.shortcuts import render
from django.views.generic import TemplateView, DetailView, ListView
from .models import Reports
from django.utils import timezone
class index(TemplateView):
template_name = 'reports_list.html'
class ReportsListView(ListView):
model = Reports
def get_queryset(self):
return Reports.objects.filter(create_date__lte=timezone.now()).order_by('-create_date')
class Detail(DetailView):
model = Reports
reports_list.html
<ul class="index-list">
{% for report in reports_list %}
<li data-id= {{ report.pk }}>
<a class="index-link" href="{% url 'reports:reports_detail' pk=report.pk %}">
<span class="index-name">{{report.title}}</span>
</a>
</li>
{% endfor %}
</ul>
report_detail.html
{% extends './reports_list.html' %}
{% block contentblock %}
<h1>THIS IS DETAIL VIEW</h1>
<div class="read-header">
<div class="read-title">
{{ reports.title }}
</div>
</div>
<div class="read-subtitle">
{{ reports.subtitle }}
</div>
<div class="read-content">
{{reports.content}}
</div>
{% endblock %}
All you have to do is pass additional context data to DetailView for the list to see since you are extending the template here. Docs
class Detail(DetailView):
model = Reports
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# Add in the reports list to context
context['reports_list'] = Reports.objects.filter(create_date__lte=timezone.now()).order_by('-create_date')
return context
I have a model called Publication and I'd like to add a button to the list view in Django Admin which would allow triggering a Celery task.
admin.py:
from django.contrib import admin
from .models import Publication
class PublicationAdmin(admin.ModelAdmin):
change_list_template = "variants/admin_publication_list.html"
def update(self, request):
# trigger task
# redirect to admin list
admin.site.register(Publication, PublicationAdmin)
variants/admin_publication_list.html:
{% extends 'admin/change_list.html' %}
{% block object-tools %}
<li>
<a href="/admin/variants/publication/update/">
Update
</a>
</li>
{{ block.super }}
{% endblock %}
However when I press a button I only get a notice:
Publication with ID “update” doesn’t exist. Perhaps it was deleted?
Method name update or route name update is too generic and sometimes used by frameworks automatically, try naming it to match your functionality. revoke-publications or sync-publications.
admin.py:
from django.contrib import admin
from django.urls import path
from django.http import HttpResponseRedirect
from .models import Publication
from .tasks import your_celery_task
#admin.register(Publication)
class PublicationAdmin(admin.ModelAdmin):
change_list_template = "variants/admin_publication_list.html"
def get_urls(self):
urls = super().get_urls()
my_urls = [
path('update-publications/', self.publication_update),
]
return my_urls + urls
def publication_update(self, request):
result = your_celery_task.delay("some_arg")
self.message_user(
request,
f"Task with the ID: {result.task_id} was added to queue. Last known status: {result.status}"
)
return HttpResponseRedirect("../")
variants/admin_publication_list.html:
{% extends 'admin/change_list.html' %}
{% block object-tools %}
<div>
<form action="update-publications/" method="POST">
{% csrf_token %}
<button type="submit">Run Celery Task</button>
</form>
</div>
<br />
{{ block.super }}
{% endblock %}
I have looked at other similar problems on here and a few other places, but the solutions don't seem to help with my problem. Even though, I am not seeing too much of a difference between this simple code that I've got and other similar code. Especially this one Flask - wtforms: Validation always false
forms.validate_on_submit() is always false and I can't see why.
I'm going through the Flask Web Development Book by Miguel Grinberg, but I wanted to change some things in order to learn more.
It works when using the wtf.quick_form(form) in the html template, but if I remove the quickform entry and put in form fields , then it doesn't work
The screen just refreshes and it doesn't change Stranger to whatever name is entered
HTML index template
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}Flasky{% endblock %}
{% block page_content %}
<div class="page-header">
<h1>Hello, {% if name %}{{ name }}{% else %}Stranger{% endif %}!</h1>
</div>
<form action="" method='POST'>
{{ form.name.label }} <br>
{{ form.name }}
{{ form.submit }}
</form>
{% endblock %}
relevant code hello.py
from flask import Flask, render_template, request
from flask.ext.script import Manager
from flask.ext.bootstrap import Bootstrap
from flask.ext.moment import Moment
from flask.ext.wtf import Form
from wtforms import StringField, SubmitField, RadioField, TextField, validators
from wtforms.validators import Required
from wtforms.validators import DataRequired
app = Flask(__name__)
class NameForm(Form):
name = StringField('What is your name?',validators=[Required()] )
submit = SubmitField('Submit')
#app.route('/', methods=['GET', 'POST'])
def index():
name = None
form = NameForm(request.form) #From the docs I read I don't need
# request.form but it
# doesn't work either with it or without it
if form.validate() == True:
name='True' #never happens is not validating or is always set to False for
# some reason
if form.validate_on_submit(): #isn't validating or working
name = form.name.data #'Stranger' will disappear from the html template and
#replaced with the name the user entered in the
# Stringfield
form.name.data = '' #clear stringfield for next round
return render_template('index.html',form=form, name=name)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=80, debug=True)'
what am I not understanding\missing?
Thanks
g
The problem is with wtf not finding the CSRF Tokens as part of your form data. Add {{ form.hidden_tag() }} or {{ form.csrf_token }} as the top element of your form.
Just a small remind for anyone who uses bootstrap template form like me.
Be sure to add "name" attribute into the input tag as well. For example,
<label>Your name</label>
<input name = 'name' required>
<label>Your email</label>
<input name = 'email' required>
I have a ModelForm that posts news items to a database, and it uses a javascript textarea to allow the authorized poster to insert certain pieces of HTML to style text, like bold and italics. However, since I have the template output using the "safe" filter, it outputs all the HTML the form widget tries to pass on. This includes a bothersome <br> tag that never goes away, making it so you can submit without form validation reading the field as empty and stopping you. How can I make that I can not only filter the <br> tag, but completely remove it from the data? Here is relevant code:
Models.py:
from django.db import models
from django.forms import ModelForm, forms
from django.contrib.auth.models import User
# Create your models here.
class NewsItem(models.Model):
user = models.ForeignKey(User)
date = models.DateField(auto_now=True)
news = models.TextField(max_length=100000, blank=False, help_text='HELP TEXT')
def __unicode__(self):
return u'%s %s %s' % (self.user, self.date, self.news)
class NewsForm(ModelForm):
class Meta:
model = NewsItem
exclude=('user','date',)
Views.py:
from news.models import NewsForm, NewsItem
from django.shortcuts import render
from django.http import HttpResponseRedirect, HttpResponse
def news(request):
if request.method == 'POST':
item = NewsItem(user=request.user)
form = NewsForm(request.POST, instance=item)
if form.is_valid():
form.save()
return HttpResponseRedirect('/news/')
else:
form = NewsForm()
news_list = NewsItem.objects.all()
return render(request, 'news_list.html', {'news_list': news_list, 'form': form})
news_list.html:
{% extends "base.html" %}
{% block title %}News in the Corps{% endblock %}
{% block content %}
<h2 id="page_h">News in the Corps</h2>
{% if user.is_authenticated %}
<h3>Post News</h3>
<script src="{{ STATIC_URL }}nicEdit.js" type="text/javascript"></script>
<script type="text/javascript">bkLib.onDomLoaded(nicEditors.allTextAreas);</script>
<div id="news_poster">
<form id="news_poster" action="/news/" method="POST">{% csrf_token %}
{{ form }}
<input type="submit" value="Submit" />
</form>
</div>
{% endif %}
<ul id="events_list">
{% if news_list %}
<div id="news_list">
{% for news in news_list %}
{% if news.id == 1 %}
<hr />
{% endif %}
<div id="{{ news.id }}" class="news_item">
<p class="poster">Posted By: {{ news.user }} | Posted On: {{ news.date }} | Link</p>
<div id="news_item">
{{ news.news|safe }}
</div>
</div>
<hr />
{% endfor %}
</div>
{% endif %}
</ul>
{% endblock %}
You can try the removetags template filter:
{{ news.news|removetags:"br"|safe }}
I can't help but thinking that the "removetags" as Timmy O'Mahony suggested might work if it was structured like this:
{{ news.news|safe|removetags:"br"}}
Give it a shot and see if it works. I would reply, but my karma's not height enough to directly reply to an answer with a suggestion.
I was changing some views earlier related to some geolocation (that failed) and upon restoring the previous views, I'm receiving this error:
TemplateSyntaxError at /report/all/
Caught NoReverseMatch while rendering: Reverse for 'profiles_profile_detail' with arguments '('',)' and keyword arguments '{}' not found.
What's odd is that the views I altered and restored had nothing to do with this view or template. The urls.py file was not touched at all. All other pages in the application are displaying normally. I can't figure out what the problem might be.
Views:
from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.shortcuts import render_to_response, get_object_or_404, redirect
from django.template import RequestContext
from django.core.urlresolvers import reverse
from myapp.report.models import Story, UserProfile
from myapp.report.forms import ProfileForm, StoryForm
from django.contrib.auth.decorators import login_required
from django.contrib.gis.utils import GeoIP
def all_stories(request):
if not request.user.is_authenticated():
return redirect("django.contrib.auth.views.login")
all_stories = Story.objects.all().order_by("-date")
return render_to_response("report/storyline.html",
{'stories': all_stories},
context_instance=RequestContext(request))
def story_detail(request, story_id):
story = get_object_or_404(Story, id=story_id)
return render_to_response('report/detail.html',
{'story': story},
context_instance=RequestContext(request))
#login_required
def submit_story(request):
if request.method =="POST":
story_form = StoryForm(request.POST, request.FILES)
if story_form.is_valid():
new_story = story_form.save(commit=False)
new_story.author = request.user
new_story.save()
return HttpResponseRedirect("/report/all/")
else: # GET request
story_form = StoryForm()
return render_to_response("report/report.html", {'form': story_form}, context_instance=RequestContext(request))
Forms (changed but restored; appear to be working):
from django import forms
from stentorian.report.models import UserProfile, Story
from django.contrib.gis.utils import GeoIP
class ProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
class StoryForm(forms.ModelForm):
class Meta:
model = Story
exclude = ('author',)
Template:
{% extends 'base.html' %}
{% block page_title %}Stentorian{% endblock %}
{% block headline %}Stentorian Storyline{% endblock %}
{% block content %}
<div class="row">
<div class="span12">
<h2>Welcome {{ user.username }}</h2>
<div class="accordion" id="story_accordion">
{% for story in stories %}
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle story-header" data-toggle="collapse" data-parent="#story_accordion" href="#story_{{ story.id }}">
{{ story.title }} - {{ story.author.username }} - {{ story.date }}
</a>
</div>
<div id="story_{{ story.id }}" class="accordion-body collapse{% if forloop.counter0 == 0 %} in{% endif %}">
<div class="accordion-inner">
<!-- <h2>{{story.title}}</h2>-->
<span>{{story.author}} </span><br>
<span>{{story.topic}}</span><br>
<span>{{story.zip_code}}</span><br>
<span>{{story.date}}</span><br>
<p>{{story.copy}}</p>
</div>
</div>
</div>
<br>
{% endfor %}
</div>
</div>
</div>
{% endblock content %}
The error is coming up on the line:
{% for story in stories %}
If anyone can provide an idea of why this is happening, it would be most appreciated. Again, the url wasn't changed, which seems to be the chief reason for this error.
Seems like u r not getting user.username
Try with this.
<h2>Welcome {{ request.user.username }}</h2>