Django selectdatewidget how to render manually? - django

I'm trying to render a selectdatewidget in django out manually so I can customise with bootstrap. However I'm not clear on how I render out the indvidual inputs with the selectdatewidget?
class ProfileForm(forms.Form):
first_name = forms.CharField(max_length=30)
last_name = forms.CharField(max_length=30)
eighteen_years_from_now = (datetime.datetime.now().year - 18)
date_of_birth = FieldBuilder(User, 'date_of_birth', widget=SelectDateWidget(
years=range(eighteen_years_from_now, 1919, -1)))
template to render an individual field:
<div class="form-group">
<label for="{{ field.id_for_label }}" class="sr-only">
{{ field.label }}
</label>
{% if form.is_bound %}
{% if field.errors %}
{% render_field field class="form-control is-invalid" %}
{% for error in field.errors %}
<div class="invalid-feedback">
{{ error }}
</div>
{% endfor %}
{% else %}
{% render_field field class="form-control is-valid" %}
{% endif %}
{% else %}
{% render_field field class="form-control" placeholder=field.label %}
{% endif %}
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text }}</small>
{% endif %}
</div>

The short answer is that you can't get the control needed, without overriding the inbuilt django template.
Thankfully Django 1.11 changed the widget system to use templates rather than python code making this easier to override.
From reviewing the templates in django/forms/templates/django/forms/widgets we can see that the select date widget loads the multiwidget template which for each subwidget loads the widget template:
{% for widget in widget.subwidgets %}{% include widget.template_name %}{% endfor %}
For select date widget this means the output is the 3 select tags (month, day, year) next to each other. This can't be eg made inline with bootstrap as each <select> needs to be wrapped in a div with the appropriate css class.
Templates can be overriden by following the django docs here:
https://docs.djangoproject.com/en/1.11/ref/forms/renderers/#overriding-built-in-widget-templates

Related

Setting css class to field in form depending of it's type

I want to manually render login and signup forms in Django.
Here is my code:
{% load widget_tweaks %}
{% for field in form.visible_fields %}
<div class="field">
<label class="label">{{ field.label_tag }}</label>
<div class="control">
{% if form.is_bound %}
{% if field.errors %}
{% render_field field class="nice-looking-field"%}
{% for error in field.errors %}
{{ error }}
{% endfor %}
{% else %}
{% render_field field %}
{% endif %}
{% else %}
{% render_field field %}
{% endif %}
{% if field.help_text %}
<p>{{ field.help_text }}</p>
{% endif %}
</div>
</div>
{% endfor %}
{% if form.non_field_errors %}
<div class="box">
{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
</div>
{% endif %}
My question: is it possible to check in a loop what type the field has and, depending on the field, assign a specific CSS class?
For example:
Field_1 has type text, so we apply css-class-1 to it
Field_2 has a checkbox type, so we apply css-class-2 to it
you can use the django form that is inherited from modelform to define specific css class to the form fields.
for instance,
models.py file:
class Post(models.Model):
title=models.CharField(max_length=254)
text=models.TextField()
forms.py file
from . import models
class PostForm(forms.ModelForms):
class Meta():
model=models.Post
fields='__all__'
widgets={
'title':forms.TextInput(attrs={'class':'textinputclass'}), #--->> you can use this textinputclass as the css class in your css file to style the title field of your forms.
'text':forms.Textarea(attrs={'class':'content'})
}
now in your static>css>yourcss.css you can access the class that we defined above as normal css class.
.content{
font-size:15px;
}
That's all.

Bootstrap classes to Django UpdateView

Built-in UpdateView View class create form in my app, but I want add to form Bootstrap class in my HTML, how can i do it?
class ProfileUpdate(UpdateView):
model = Profile
fields = ['first_name', 'last_name', 'patronymic', 'profile_picture', 'bio']
template_name = 'profiles/profile_form.html'
success_url = ''
You can add class with django-widget-tweaks, but you can't add class directly to form you should use the filter render_field for customizing fields of form.
In your settings.py
INSTALLED_APPS = [
...
'widget_tweaks',
...
]
In your template you can put like this
{% load widget_tweaks %}
<form>
{% csrf_token %}
{% for field in form %}
{% if field.errors %}
<div class="form-group">
<label for="id_{{ field.name }}">{{ field.label }}:</label>
{% render_field field class="form-control is-invalid" %}
<div class="invalid-feedback">
<ul>
{% for error in field.errors %}
<li>{{error|escape}}</li>
{% endfor %}
</ul>
</div>
</div>
{% else %}
<div class="form-group">
<label for="id_{{ field.name }}">{{ field.label }}:</label>
{% render_field field class="form-control" %}
</div>
{% endif %}
{% endfor %}
</form>
Another easier way is to use django-crispy-forms, which adds bootstrap styles more automatically.
In your settings.py
INSTALLED_APPS = (
...
'crispy_forms',
)
You can render the entire form
{% load crispy_forms_tags %}
{% my_form|crispy %}
Or a field
{% load crispy_forms_tags %}
{{my_form.field|as_crispy_field}}
If you simply want to add a class to the form you can do this:
<form class="my_bootstrap_class">
{% csrf_token %}
{% for field in form %}
...
{% endfor %}
</form>

Show / hide input field or div based on RadioField choice using Flask wtf_form

I am trying to build website using Flask, and can't find solution to one problem. I am trying to hide or show input field, based on RadioFeild choice. Also, if input field showing, it have to be required. I actually have everything working, besides knowing what RadioField choice was selected. I can see the form when loading page on 127.0.0.1:5000 and I can see RadioField with 2 choices: Yes and No, but when I click on yes, there are no changes, hidden input field is still not showing. Please, help!
app.py
class MyClass(FlaskForm):
my_field = RadioField("bla-bla-bla", choices=[('Yes', 'Yes'), ('No', 'No')], validators [InputRequired()])
#app.route("/some_page")
def some_page():
form = MyClass()
return render_template("some_page.html", form=form)
_render_field.html
{% macro render_radio_field(field) %}
<div class="form__item">
<label class="form__label">{{field.label.text }}</label>
<div class="form-group">
{{ field(class_='form__input', **kwargs)|safe }}
{% for subfield in field %}
<div class="form__item">
<label>
{{ subfield }}
{{ subfield.label.text }}
</label>
</div>
{% endfor %}
</div>
</div>
{% endmacro %}
some_page.html
{% from "_render_field.html" import render_field, render_radio_field %}
{% extends "layout.html" %}
{% block title %}My Title{% endblock %}
{% block content %}
<div style="width:600px; margin:0 auto;">
<h3>Some Text</h3>
<form class="form" action="{{url_for('some_page')}}" method="POST">
{% from "_render_field.html" import render_field, render_radio_field %}
{{ form.csrf_token }}
{{ render_field(my_field, title="", style="list-style:none") }}
{% if form.my_field.option == "Yes" %}
{{ render_field(form.some_other_StringField, placeholder="Please explain:", title="") }}
{% endif %}
<input type="submit" name="" value="login" class="form__btn">
</form>
</div>
{% endblock %}

Django, best way to print a field key

I want to print fields of a model differently than by first_name
I want to print something like "key: value" but it prints "first_name: Georges", I would prefer that it's looks like "First name: Georges"
Currently i'm using a file named form.html that I include in every form template:
{% load widget_tweaks %}
{% for field in form %}
<div class="form-group">
{{ field.label_tag }}
{% if form.is_bound %}
{% if field.errors %}
{% render_field field class="form-control is-invalid" %}
{% for error in field.errors %}
<div class="invalid-feedback">
{{ error }}
</div>
{% endfor %}
{% else %}
{% render_field field class="form-control is-valid" %}
{% endif %}
{% else %}
{% render_field field class="form-control" %}
{% endif %}
{% if field.help_text %}
<small class="form-text text-muted">
{{ field.help_text }}
</small>
{% endif %}
</div>
{% endfor %}
And a model that looks like this:
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
What is the best way to print first_name as "First name"?:
Is it by setting verbose_name for every fields in the models.py?
Or by setting label in the forms.py for every fields in each form?
Or by not using a dynamic template and hardcode it in my form.html?
Like what Aleksei Maide said to change that you need to alter the Label, here is an example:
in your form class add a method:
def __init__(self, *args, **kwargs):
super(YourFormName, self).__init__(*args, **kwargs)
self.fields['first_name'].label = "First name"
this is how i'm displaying it in my template:
<label class="bmd-label-static">{{ field.label }}</label>
{{ field.name }}
Think by a moment that you have a Model Form with 30 fields, and as this form, you have other 30 more Model Forms, now, you have to set every time your field labels, is a very complicated task, don't you think?
i could suggest you that use the verbose name feature to each model field and build a simple template tag that can help you to get dinamicaly the verbose name of your fields i your templates
This template tag will try to get the model field's verbose name
# yourapp/templatetags/yourapp_extras.py
from django import template
register = template.Library()
#register.simple_tag
def field_name(model, field):
field_name = field
if model:
try:
field_name = model._meta.get_field(field).verbose_name.title()
except Exception as ex:
print ex
return field_name
And in your template you can display your field label as follow
# sometemplate.html
{% load widget_tweaks %}
{% load yourapp_extras %}
{% for field in form %}
<div class="form-group">
{% field_name model field.name %} <!-- here -->
{% if form.is_bound %}
{% if field.errors %}
{% render_field field class="form-control is-invalid" %}
{% for error in field.errors %}
<div class="invalid-feedback">
{{ error }}
</div>
{% endfor %}
{% else %}
{% render_field field class="form-control is-valid" %}
{% endif %}
{% else %}
{% render_field field class="form-control" %}
{% endif %}
{% if field.help_text %}
<small class="form-text text-muted">
{{ field.help_text }}
</small>
{% endif %}
</div>
{% endfor %}

ListField is showing <ul> instead of <input> in edit/create post

I am using Flask, mongoengine for a project and I am trying to get basic stuff working from http://docs.mongodb.org/manual/tutorial/write-a-tumblelog-application-with-flask-mongoengine/
After implementing everything from above link I added a new field for "tags" in Post and when I try to create a post, my tags doesn't show a input box.
Any help is appreciated.
My code and screenshot below
class Post(db.DynamicDocument):
created_at = db.DateTimeField(default=datetime.datetime.now, required=True)
title = db.StringField(max_length=255, required=True)
slug = db.StringField(max_length=255, required=True)
comments = db.ListField(db.EmbeddedDocumentField('Comment'))
tags = db.ListField(db.StringField(max_length=30)) # New field I added
template form
{% macro render(form) -%}
<fieldset>
{% for field in form %}
{% if field.type in ['CSRFTokenField', 'HiddenField'] %}
{{ field() }}
{% else %}
<div class="clearfix {% if field.errors %}error{% endif %}">
{{ field.label }}
<div class="input">
{% if field.name == "body" %}
{{ field(rows=10, cols=40) }}
{% else %}
{{ field() }}
{% endif %}
{% if field.errors or field.help_text %}
<span class="help-inline">
{% if field.errors %}
{{ field.errors|join(' ') }}
{% else %}
{{ field.help_text }}
{% endif %}
</span>
{% endif %}
</div>
</div>
{% endif %}
{% endfor %}
</fieldset>
{% endmacro %}
rendering form code
{% extends "admin/base.html" %}
{% import "_forms.html" as forms %}
{% block content %}
<h2>
{% if create %}
Add new Post
{% else %}
Edit Post
{% endif %}
</h2>
<form action="?{{ request.query_string }}" method="post">
{{ forms.render(form) }}
<div class="actions">
<input type="submit" class="btn primary" value="save">
Cancel
</div>
</form>
{% endblock %}
From what I can gather, your problem is you're telling WTF to render the tags field, but WTForms doesn't know how to handle that information.
From looking at the Flask-MongoEngine documentation, it seems the ListField is just a FieldList as WTForms refers to it.
Currently you're not actually defining the form independently in WTForms, you're just using the magic included in Flask-MongoEngine, so my first attempt would be to add some more logic to your macro, add a {% elif field.type == 'ListField' %} and try and discover what's contained in there to iterate through to produce your form. From having a quick look at the source-code, something like the following might work.
{% elif field.type == 'ListField %}
{# render_the_group_label #}
{% for subfield in field.entries %}
{% if subfield.type == 'StringField' %}
{# render_the_subfield #}
{% endif %}
{% endfor %}
...
That code will need to be worked on, but hopefully it'll point you in the right direction. Otherwise, I'd actually define the form seperately in WTForms to give you a bit more control on the code-side. Luckily they provide a csv tag example which should help you if you need to go that route. I wrote a guide that takes a different route using #property decorators to achieve a similar effect, which again, might at least point you towards the finish line.