crispy forms tailwind with tabs - django

I want to have a form with 3 tabs using cripsyformws and tailwind.
for now it does not work:
my html:
{% extends "base.html" %}
{% load tailwind_filters %}
{% block content %}
<div class="max-w-lg mx-auto">
<div class="py-5 border-t border-gray-200">
<h1 class="text-4xl text-gray-800">Create a new company</h1>
</div>
<form method="post" class="mt-5">
{% csrf_token %}
{{ form|crispy }}
<button type='submit' class="w-full text-white bg-blue-500 hover:bg-blue-600 px-3 py-2 rounded-md">
Submit
</button>
</form>
</div>
{% endblock content %}
my form:
class CompanyModelForm(forms.ModelForm):
class Meta:
model = Company
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.layout = Layout(
TabHolder(
Tab('company_name' ,
'fiscal_end_of_year' ,
),
Tab('Addrfirm_address',
'Addrfirm_code',
'Addrfirm_country',
'Addrfirm_city',
'Addrfirm_state'
),
Tab('AddrShipping_address',
'AddrShipping_code',
'AddrShipping_country',
'AddrShipping_city',
'AddrShipping_state'
),
Tab('AddrInvoice_address',
'AddrInvoice_code',
'AddrInvoice_country',
'AddrInvoice_city',
'AddrInvoice_state'
)
)
)
self.helper.layout.append(Submit('submit', 'Submit'))
My goal is to have 3 tabs for the same form tab1 general info, tab2 shipping address, tab3 invoicing address.
Do tailwind permit this with crispy or how should I do this if not

Use this in your html, ie load the crispy_forms_tags and then render the tabbed form using {% crispy form %}.
You'll then add CSS rules based on how Django renders that form on HTML.
{% extends "base.html" %}
{% load tailwind_filters %}
{% load crispy_forms_tags %}
{% block content %}
<div class="max-w-lg mx-auto">
<div class="py-5 border-t border-gray-200">
<h1 class="text-4xl text-gray-800">Create a new company</h1>
</div>
<form method="post" class="mt-5">
{% csrf_token %}
{% crispy form %}
</form>
</div>
{% endblock content %}

Add {% load crispy_fotms_tags %} on the top of your page
And add crispy_foms
to your settings. Py

Related

How to show django form in django template?

I am trying to create a form using django and css.
views.py
from django.shortcuts import render
from .forms import ContactForm
def home(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
pass
else:
form = ContactForm()
return render(request, 'home.html', {'form':form})
forms.py
from django import forms
class ContactForm(forms.Form):
name = forms.CharField(max_length = 30)
email = forms.EmailField(max_length = 254)
message = forms.CharField(max_length = 2000, widget = forms.Textarea(),help_text = "Write Your Message here")
def clean(self):
cleaned_data = super(ContactForm, self).clean()
name = cleaned_data.get('name')
email = cleaned_data.get('email')
message = cleaned_data.get('message')
if not name and not email and not message:
raise forms.ValidationError('You have to write something!')
When I try to add the form to my html page like the following it doesn't show up. Just the button shows up, no form fields -
{% extends 'store/main.html' %}
{% load static %}
{% block content %}
<h3>Store</h3>
<form method = "post" novalidate>
{% csrf_token %}
{{ form }}
<button type='submit'>Submit</button>
</form>
{% endblock content %}
If I do css form instead it obviously show up the way it should.
{% extends 'store/main.html' %}
{% load static %}
{% block content %}
<h3>Store</h3>
<form>
<label for="fname">First Name</label>
<input type="text" id="fname" name="fname">
<button type='submit'>Submit</button>
</form>
{% endblock content %}
So I decided to add the form fields individually to the css form. Where does the {{form.name}} or {{form.email}} tag go?
EDIT:
Hey Vivek, the contact form code is this -
class ContactForm(forms.Form):
name = forms.CharField(max_length = 30)
email = forms.EmailField(max_length = 254)
message = forms.CharField(max_length = 2000, widget = forms.Textarea(),help_text = "Write Your Message here")
The html template looks like this-
{% extends 'store/main.html' %}
{% load static %}
{% block content %}
<h3>Store</h3>
<form method = "post" novalidate>
{% csrf_token %}
<label class="float-left" for="name">Name</label>
{{ form.name }}
<button type='submit'>Submit</button>
</form>
{% endblock content %}
Thanks for any input.
Accessing form fields individually will make you to render the form errors individually as well. {{form}} encapsulates everything:- Form fields , errors, non_field_errors..So if you have to access the fields individually do not forget to add the form errors.
I have written a sample code which will server the purpose.
{% csrf_token %}
{% if form.errors %}
<div class="alert alert-danger" style="text-align:left">
<ul>
{% for field in form %}
{% for error in field.errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}
</ul>
</div>
{% endif %}
<div class="form-row">
<div class="col-md-4 mb-3">
<label class="float-left" for="id_name">Name</label>
{{ form.name }}
</div>
<div class="col-md-8 mb-3">
<label class="float-left" for="id_email">Email ID</label>
{{ form.email }}
</div>
</div>
<br>
<input type="submit" class="btn btn-primary" value="Pay" id="submit">
</form>

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>

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

HTML layout object doesn't work

I quite new with Django Crispy Form and I have tried to add a HTML object in my form but it's not working. All the other elements are rendered but not the HTML.
This is my form:
forms.py
from crispy_forms.layout import Layout, Fieldset, HTML
class MyUserRegistrationForm(forms.ModelForm):
class Meta:
model = MyUser
fields = ['title', 'privacy_disclaimer_accepted']
def __init__(self, *args, **kwargs):
super(MyUserRegistrationForm, self).__init__(*args, **kwargs)
helper = FormHelper()
helper.form_method = 'post'
helper.form_class = 'form-horizontal'
helper.label_class = 'col-sm-2'
helper.field_class = 'col-sm-6'
helper.form_error_title = 'Form Errors'
helper.error_text_inline = True
helper.help_text_inline = True
helper.html5_required = True
helper.form_tag = False
helper.layout = Layout(
Fieldset('Information', 'title'),
Fieldset('Privacy Statement',
HTML("""
<div id="iframe" class="mt-5">
<h6>Notice/Disclaimer:</h6>
<div class="privacy-policy">
{% if privacy_disclaimer %}
{{ privacy_disclaimer }}
{% else %}
{% include "registration/privacy_policy.html" %}
{% endif %}
</div>
</div>
"""),
'privacy_disclaimer_accepted', )
)
I have a basic HTML file, where I have the normal html, header and body tags.
This is the HTML registration page:
register.html
{% extends "base.html" %}
{% block title %}Create an account{% endblock %}
{% block content %}
<div class="registration-page">
<h3 class="text-center">Create an account</h3>
<div class="registration-page__form">
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-error">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<div class="alert alert-error">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endif %}
<form action="" method="post">
{% csrf_token %}
{% load crispy_forms_tags %}
{{ form_myuser|crispy }}
<br/>
<div class="text-right">
<input type="submit" class="btn btn-primary btn--action" value="Create the account">
</div>
</form>
</div>
</div>
{% endblock %}
EDIT:
views.py
class RegisterView(View):
template_name = 'registration/register.html'
def _get_context_data(self, **kwargs):
context = {}
privacy_disclaimer = ''
context['privacy_disclaimer'] = privacy_disclaimer
if kwargs:
context.update(kwargs)
return context
def get(self, request, *args, **kwargs):
extra_context = {
'form_myuser': MyUserRegistrationForm(),
}
context = self._get_context_data(**extra_context)
return render(request, self.template_name, context)
I fixed the issue and the problem was the form loading.
I was loading it in the wrong way.
Instead of this {{ form_myuser|crispy }} I have to use this code {% crispy form_tolauser %}.

User settings in django admin

I want to be able to change some settings from django admin, for example: site title or footer. I want to have app with model which includes this settings, but this settings should be in single copy. What the best way to do it?
You can create a view with #staff_member_required decorator, which renders/saves a form:
from django.contrib.admin.views.decorators import staff_member_required
...
#staff_member_required
def edit_config(request, ):
saved = False
if request.method == "POST":
form = ConfigForm(request.POST)
if form.is_valid():
...
# Do saving here
saved = True
else:
form = ConfigForm()
...
context = {
'form': form,
'saved': saved,
}
return render_to_response('staff/edit_config.html', context, context_instance=RequestContext(request))
Use django forms in the view, and pass it to the template.
then, in the template extend 'admin/base_site.html' so your form has a admin look and feel. Here's a sample template:
{% extends 'admin/base_site.html' %}
{% load i18n adminmedia %}
{% block title %}Edit Configuration {{ block.super }} {% endblock %}
{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% admin_media_prefix %}css/forms.css" />{% endblock %}
{% block breadcrumbs %}
<div class="breadcrumbs">
{% trans "Home" %} > Edit Configuration
</div>
{% endblock %}
{% block content %}
<h1>Edit Configuration</h1>
{% if saved %}
<p class="success" style="background-color:#9F9; padding: 10px; border: 1px dotted #999;">
Settings were saved successfully!
</p>
{% endif %}
<form method="POST" action="">
{% csrf_token %}
<fieldset class="module aligned">
<h2>Configuration</h2>
<div class="description"></div>
{% for field in form %}
<div class="form-row {% if field.errors %}errors{% endif %}">
{{ field.errors }}
<div class="field-box">
{{ field.label }} : {{ field }}
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
</div>
{% endfor %}
</fieldset>
<div class="submit-row">
<input type="submit" value="{% trans 'Save' %}" class="default" name="_save"/>
</div>
</form>
{% endblock %}
You can use database, ini files, redis, ... for storing your configuration. You may define some general backend, and inherit your custom backends from it so it's flexible.
Sounds like django-constance would be a good fit.
Though django-flatblocks might be sufficient.
django-flatblocks is a simple application for handling small
text-blocks on websites. Think about it like django.contrib.flatpages
just not for a whole page but for only parts of it, like an
information text describing what you can do on a site.