Bootstrap classes to Django UpdateView - django

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>

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.

How to create and submit multiple instances of a form on a single page?

I want 3 instance of a URL input form so I can submit up to 3 different URLs.
forms.py
class AdditemForm(forms.Form):
url = forms.URLField(
label='Add Item',
widget=forms.URLInput(
attrs={
"class": "form-control",
}))
view.py
def ItemDetail(request, pk):
listitem = comparelist.objects.get(id=pk)
if request.method == 'POST':
form = AdditemForm(request.POST)
if form.is_valid():
url = form.cleaned_data.get("url")
items.objects.create(
link=url,
name=product_name,
price=price,
store=store,
)
return HttpResponseRedirect(request.path_info)
else:
form = AdditemForm()
template = 'itemdetail.html'
context = {
"comparelist": listitem,
"form": form,
}
return render(request, template, context)
I'm using a form snippet I found in a tutorial:
{% load widget_tweaks %}
<form method="post" class="form">
{% csrf_token %}
{% for hidden_field in form.hidden_fields %}
{{ hidden_field }}
{% endfor %}
{% if form.non_field_errors %}
<div class="alert alert-danger" role="alert">
{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
</div>
{% endif %}
{% for field in form.visible_fields %}
<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 %}
<button type="submit" class="btn btn-primary">Submit</button>
</form>
So how do I get 3 of those forms on my page and be able to submit 3 different URLs?
I can only think of having to create 3 different form classes and paste the form snippet 3 times into the template. But that seems like a lot of unnecessary repetition.
Why "create 3 different form classes" ??? You can just create three instances of the same form.
paste the form snippet 3 times into the template
Ever heard about lists and loops ? You can put the three (or more) forms in a list and loop over it.
BUT that's actually not the best solution here - Django has Formsets for this use case.

How to fix pagination after making a search for specific data in django_tables2

In my project I am using with success django_tables2 in order to achieve server side processing.
The only thing that I do not know how to handle is that after searching, for example by name in a template rendering clients for my application, the search despite the fact that gives some returned results based on the name, it is not working properly if the result records are spread in more than one page based on my pagination.
In other words, when I am clicking the 2 (second page of my returned results), the app is showing all the pages concerning the clients 1 2 3 ...45 next (as i want to reach the /clients/ url, and not the 1 2 next structure for only the custom search data.
This happening also when I am clicking the next and previous buttons.
One easy solution It could be to increase my pagination limit in order to show all the possible results in one page, but this solution is not proper for big result sets.
Is there any solution to avoid loading and showing all the pages in the search bar and only keeping the results of my custom search?
Below is my snippets.
url.py
url(r'^clients/$', views.client_list, name='client_list'),
models.py
class Client(models.Model):
name = models.CharField(max_length=50, verbose_name="Name")
surname = models.CharField(max_length=50, verbose_name="Surname")
activity = models.IntegerField(choices=ACTIVITY_OPTIONS, null=True,default=ACTIVE)
views.py
def client_list(request, template_name='clients/client_list.html'):
if request.method == 'POST':
search_string = request.POST['search_client']
current_client=Client.objects.filter(Q(activity=1) & Q(name=search_string)| Q(surname=search_string))
single_table=ClientTable(current_client)
RequestConfig(request).configure(single_table)
return render(request,template_name, {'single_table': single_table})
else:
clients=Client.objects.filter(activity=1)
table = ClientTable(clients)
RequestConfig(request).configure(table)
return render(request,template_name, {'table': table})
tables.py
class ClientTable(tables.Table):
class Meta:
#define the model
model = Client
exclude=('..')
template_name = 'django_tables2/bootstrap.html'
sequence = ("surname", "name",)
template
{% extends 'base.html' %}
{% load has_group %}
{% load render_table from django_tables2 %}
{% load bootstrap3 %}
{% load static %}
{% load staticfiles %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-md-12">
<form class="well" method="post" action="">
{% csrf_token %}
Client Search:<br>
<input type="text" class="form-control" id="search" name="search_client">
<br>
{% buttons %}
<button type="submit" class="btn btn-primary">
{% bootstrap_icon "like" %} Submit
</button>
{% endbuttons %}
</form>
{% if single_table %}
{% render_table single_table %}
{% endif %}
{% if table %}
{% render_table table %}
{% endif %}
</div>
</div>
</div>
{% endblock %}
Finally after searching I found a solution.
Django filters https://django-filter.readthedocs.io/en/master/index.html can be used in situations like this one.
The steps I followed are:
1) import the 'django_filters', to settings.py
2) Define the filters.py
import django_filters
from .models import Patient
class ClientFilter(django_filters.FilterSet):
name = django_filters.CharFilter(lookup_expr='icontains')
class Meta:
model = Client
fields = ['id','name','surname']
3) Modify the views.py
class FilteredClientListView(SingleTableMixin, FilterView):
table_class = ClientTable
model = Client
template_name ='clients/client_list2.html'
filterset_class = ClientFilter
4) Modify urls.py accordingly since I used class based function
url(r'^clients2/$', views.FilteredClientListView.as_view(), name='client_list2'),
5) Modify my template
{% extends 'base.html' %}
{% load has_group %}
{% load render_table from django_tables2 %}
{% load bootstrap3 %}
{% load static %}
{% load staticfiles %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-md-12">
<form class="well" method="post" action="">
{% csrf_token %}
Client Search:<br>
<input type="text" class="form-control" id="search" name="search_client">
<br>
{% buttons %}
<button type="submit" class="btn btn-primary">
{% bootstrap_icon "like" %} Submit
</button>
{% endbuttons %}
</form>
{% if filter %}
<form action="" method="get" class="form form-inline">
{% bootstrap_form filter.form layout='inline' %}
{% bootstrap_button 'filter' %}
</form>
{% endif %}
{% if single_table %}
{% render_table single_table %}
{% endif %}
{% if table %}
{% render_table table %}
{% endif %}
</div>
</div>
</div>
{% endblock %}
P.S : importing in the views.py the appropriate tables and filters

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

Django selectdatewidget how to render manually?

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