How to style django-multiselectfield with CSS - python

I am using 'django-multiselectfield' in my model form so users can select multiple 'areas' in my form. What I want to know now is how can I style the multiselectfield using css.
I have tried simply adding a class to the form field in my template like I normally do with all the other types of model fields, but no luck:
{% render_field form.area class="area" %}
Any help would be much appreciated.

This is described in `django-multiselectfield' documentation. Specifically,
It is possible to customize the HTML of this widget in your form template. To do so, you will need to loop through form {field}.field.choices. Here is an example that displays the field label underneath/after the checkbox for a MultiSelectField called providers:

Here is a example of what i did.
{% for field in form %}
<div class="fieldWrapper">{{ field.errors }}
<input type="{{ field.field.widget.input_type }}" name="{{ field.html_name }}" id="{{field.id_for_label}}" class="col-12 input-login" placeholder="{{field.label}}" >
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
Now you can customise the field as if it is a simple html input field.
This page has a wonderful detailed explanation. Kudos to Vitor
------edit-----
Almost forgot. This is the example for normal forms. You have to go through the official docs of django-multiselectfield to get field attribute names, and replace the respective attributes

I suggest you render the form manually and loop through it.
Say you have a Choice model with a foreignkey to a Question model, you could do it like this:
<form class="qform" action="" method="post">
{% csrf_token %}
<p class="title">{{ form.question }}</p>
{% for choice in form.choice_set.all %}
<input type="checkbox" name="{{ choice }}" id="{{ choice }}{{ forloop.counter }}"
value="{{ choice.id }}">
<label for="{{ choice }}{{ forloop.counter }}">{{ choice }}</label>
{% endfor %}
</form>
You can reference the input and label in your style.css like:
input[type="checkbox"]{
some: stuffs...;
}
label {
some: stuffs...;
}
I hope this helps.

Related

Flask-Admin: How to prevent deletion of inline_models?

I'm trying to prevent the deletion of certain entries in the inline model views with flask-admin:
The respective inline model code looks like this:
class ModelCategoryValueInline(InlineFormAdmin):
form_columns = ('id', 'display_name', 'name')
form_edit_columns = ('id', 'display_name')
can_delete = False
form_args= dict(
display_name=dict(label='Display Name', validators=[DataRequired()]),
name=dict(label='Technical Name', validators=[DataRequired()]),
)
def on_model_delete(self, model):
# Not called at all..
print('on_model_delete', model)
if model.builtin == True:
raise ValidationError(f'[{model}] is a build-in CategoryValue and cannot be deleted.')
def on_model_change(self, form, model, is_created):
# Is called, but has model already changed... - deleted models do not get this event
if not is_created:
if form.form.name.data != model.name:
raise ValidationError(f'You cannot change the internal name of a category value!')
def on_form_prefill(self, form, id):
# not called att all
form.name.render_kw = {'disabled': 'disabled', 'readonly': True}
I haven't figured out a way to prevent deletion of inline entries. on_model_delete() is not called when deleting the inline entries. can_delete has no effect either.
How can I disable the deletion of inline entries?
Ideally I want to be able to control deletion via the on_model_delete() method and prevent only deletion of values that match certain criteria.
Even though this is not an ideal solution I've managed to achieve the desired behaviour by editing the inline_list_base.html template:
{% macro render_inline_fields(field, template, render, check=None) %}
<div class="inline-field" id="{{ field.id }}">
{# existing inline form fields #}
<div class="inline-field-list">
{% for subfield in field %}
<div id="{{ subfield.id }}" class="inline-field well well-sm">
{%- if not check or check(subfield) %}
<legend>
<small>
{{ field.label.text }} #{{ loop.index }}
<div class="pull-right">
{% if subfield.get_pk and subfield.get_pk() %}
# Added if statement to check if field is builtin and disable checkbox
{% if subfield.object_data.builtin %}
<label for="del-{{ subfield.id }}" style="display: inline"><i title="This is a built-in value and cannot be deleted" data-toggle="tooltip">Built-in</i></label>
{% else %}
<input type="checkbox" name="del-{{ subfield.id }}" id="del-{{ subfield.id }}" />
<label for="del-{{ subfield.id }}" style="display: inline">{{ _gettext('Delete?') }}</label>
{% endif %}
{% else %}
<i class="fa fa-times glyphicon glyphicon-remove"></i>
{% endif %}
</div>
</small>
</legend>
<div class='clearfix'></div>
{%- endif -%}
{{ render(subfield) }}
</div>
{% endfor %}
</div>
{# template for new inline form fields #}
<div class="inline-field-template hide">
{% filter forceescape %}
<div class="inline-field well well-sm">
<legend>
<small>{{ _gettext('New') }} {{ field.label.text }}</small>
<div class="pull-right">
<span class="fa fa-times glyphicon glyphicon-remove"></span>
</div>
</legend>
<div class='clearfix'></div>
{{ render(template) }}
</div>
{% endfilter %}
</div>
<a id="{{ field.id }}-button" href="javascript:void(0)" class="btn btn-default" onclick="faForm.addInlineField(this, '{{ field.id }}');">{{ _gettext('Add') }} {{ field.label.text }}</a>
</div>
{% endmacro %}
When placing this file in templates/admin/model/inline_list_base.html this has the desired effect and prevents the user from deleting certain fields:
I would want to have a check also at the backend but I haven't found a solution for that yet.
My solution was to use something similar to
class NoDeleteInlineModelFormList(InlineModelFormList):
def display_row_controls(self, field):
return False
class NoDeleteInlineModelConverter(InlineModelConverter):
inline_field_list_type = NoDeleteInlineModelFormList
class ParentView(sqla.ModelView):
inline_models = [Child]
inline_model_form_converter = NoDeleteInlineModelConverter
You can find more details at my repo https://github.com/mapio/Flask-Admin-Inline-Models-And-Related-Fields

Django Forms: styling forms (checkboxes) manually - Input to be outside of label

I need to render checkbox form fields in the following format in html template:
<input id="tag" type="checkbox" name="check" value="1">
<label for="tag">Tag 1</label>
Currently, in my template I tried:
{{ filter.form.tags.errors }}
{% for field in filter.form.tags %}
<input id="{{ field.id_for_label }}" type="checkbox" name="check">
<label for="{{ field.id_for_label }}">{{ field.value }}</label>
{% endfor %}
This will not render {{ field.value }} (I get empty instead of Tag 1) and also is non sticky.
I also tried:
{% for field in filter.form.tags %}
{{ field.label_tag }}
{{ field }}
{% endfor %}
Which gives me nested of <label><input></input></label>, but displays everything that I need.
Is it possible to render a form such that I get the format that I'm after? (It should also preserve checked e.g. make ticks sticky).
Edit:
class TaskFilter(django_filters.FilterSet):
"""Filter for books by author"""
tags = django_filters.ModelMultipleChoiceFilter(widget=forms.CheckboxSelectMultiple, queryset=Task.tags.most_common())
title = django_filters.CharFilter(field_name='title', lookup_expr='icontains')
class Meta:
model = Task
fields = ['tags', 'title']
views.py
def task_list_filter(request):
if request.method == 'GET':
form = AdditionalForm(request.GET)
# process the form
results = Task.objects.all().order_by('-created')
f = TaskFilter(request.GET, queryset=results)
# Output final query set
results = f.qs[0:100] # only get first 100 objects
# Create pagination
# Get the view
return render(request, 'base/task_list_filter.html', {'filter': f,
'task_list': results,
'form': form })
To make sure the checkbox is in the correct state you can use the example you yourself provided with a few changes:
{% for field in filter.form.tags %}
<input type="checkbox" id="{{ field.id_for_label }}"
name="{{ field.html_name }}"
{% if field.value %}checked{% endif %}>
<label for="{{ field.id_for_label }}">{{ field.value }}</label>
{% endfor %}
And remember that you can use the {{ field.label_tag }} to generate the entire label HTML tag.
In HTML
{% for field in filter.form.tags %}
{{ field.tag }} <!-- Generates the checkbox for the field -->
{{ field.choice_label }} <!-- Generates the named label of the field -->
{% endfor %}
I learned that from this guy who has lots of helpful information specific to using Django.

Django Template to make a list to be sent as post

I am trying to make an MCQ quiz and I have used the following code in a template:
{% for MCQ in mcq %}
<input type="radio" name="MCQ" value="{{ MCQ.id }}">{{ MCQ.MCQ_Text }}
{% endfor %}
The problem is that I want to use MCQ_list = request.POST[MCQ] to access it as a list. How do I make a list in the template? Alternatively, is there a better way to approach this?
Edit:
The mcq is nested inside
{% for Questions, mcq in Quest_dic.items %}
<br>
{{ Questions.Question_Text }}
{% for MCQ in mcq %}
<br>
<input type="radio" name="ListOrAlternateHere" value="{{ MCQ.id }}">{{ MCQ.MCQ_Text }}
{% endfor %}
<hr>
{% endfor %}
change your input to type=checkbox. This will let you read the checked items as a list in python:
mcq_list = request.POST.getlist('MCQ')

django 1.6: style django's built in forgot password template

I'm trying to style django's built in forgot password registration to remove the generic Django green theme and have my own customized them. But I'm unable to do that.
here is the registration/password_reset_form.html with my header and footer that has my bootstrap and custom css files. But they are not reflected in the template. I still see the default django styling.
{% include "meddy1/header.html" %}
{% load staticfiles %}
{% block title %}Reset Password{% endblock %}
<p>Please specify your email address to receive instructions for resetting it.</p>
<form action="" method="post">
<div style="display:none">
<input type="hidden" value="{{ csrf_token }}" name="csrfmiddlewaretoken">
</div>
{{ form.email.errors }}
<p><label for="id_email">E-mail address:</label> {{ form.email }} <input type="submit" value="Reset password" /></p>
</form>
{% include "meddy1/footer.html" %}

Display objects based on attribute

This is very simple. I have a database of objects with pin attributes.
use case
user inputs 4-digit pin
displays objects with matching pin number
What is the simplest way to accomplish this in django?
index.html
<form action="/polls/" method="post">
{% csrf_token %}
<p>
<label for="pin">Enter group pin:</label>
<input id="pin" type="text" name="pin" maxlength="4" />
<input type="submit" value="View Polls" />
</p>
</form>
Currently it's hard coded in
{% for poll in latest_poll_list %}
{% if poll.pin == "1234" %}
<ul class="poll-list">
<li>{{ poll.question }} - {{poll.pin}}</li>
</ul>
{% endif %}
{% endfor %}
I am pretty new to django so there may be a better solution, but I'll give it a try.
In your view you can do something like this. Considering your code I assume you have a class
Poll
poll = Poll.objects.filter(pin=request.POST['pin'])

Categories

Resources