Style CheckboxSelectMultiple form field. Django - python

I have a form which has one checkboxselectmultiple field:
class CreateRecipeForm(forms.ModelForm):
class Meta:
model = Recipe
fields = ('name', 'image', 'description', 'cooking_time', 'tags')
widgets = {
...
'tags': forms.CheckboxSelectMultiple(),
...
}
I can iterate through field's options like:
{% for option in form.tags %}
{{ option.tag }} {{ option.choice_label }}
{% endfor %}
How would I render {{ option.tag }} as an input field? i.e:
<input type="checkbox"...>
Thanks.

In fact after reading some django docs on this topic I understood that that the fields of CheckboxSelectMultiple are already rendered as input fields. So if you don't need to add specific values to each field you can do it straight in form by adding attrs to widget:
widgets = {
...
'tags': forms.CheckboxSelectMultiple(attrs={'class': 'anyclass'}),
...
}
But if you need to add different parameters to each field you can do it in template this way:
{% for obj_choice, obj_value in form.obj.field.choices %}
<div class="tags__item">
<input type="checkbox" name="tags" value="{{obj_choice.instance.pk}}"
id="id_{{obj_choice.instance.value}}"
class="tags__checkbox tags__checkbox_style_{{obj_choice.instance.style}}">
<label for="id_{{obj_choice.instance.value}}" class="tags__label">
{{obj_choice.instance.template_name}}
</label>
</div>
{% endfor %}

Related

Django Populate Dropdown Menu With Choices From Many To Many Database

I would like to populate my dropdown menu with records from the Subject table which is a many to many choices field that is populated with subjects by adding them manually from the admin page. A course can have many subjects such as "business" and "marketing".
Code:
https://dpaste.de/825n
How would I do that with django-select2 or use a form with model select or multiple model select?
https://docs.djangoproject.com/en/2.2/ref/forms/fields/#modelchoicefield
https://docs.djangoproject.com/en/2.2/ref/forms/fields/#modelmultiplechoicefield
https://django-select2.readthedocs.io/en/latest/
Or maybe I could do it with a for loop on the template?
For loops I have tried but no luck:
https://dpaste.de/5MVi
Desired Result:
https://imgur.com/a/Iw9lk6I
Can someone please help me figure it out? I have been stuck for a while now.
here hope this helps your missing the .all() on while querying the many to many fields. you're also not going deep enough to the actual name of the many to many fields so you're trying to print the object on your loop.
example view:
def tester(request):
tes = Test.objects.get(id=1)
testlist = tes.category.all()
context = {
'test': testlist,
}
return render(request, 'core/t.html', context)
example loop:
{% for item in test %}
<p>- {{item.cat}}</p>
{% endfor %}
example model:
class cats(models.Model):
cat = models.CharField(max_length=10,)
class Test(models.Model):
name = models.CharField(max_length=10,)
category = models.ManyToManyField(cats)
nested loop example:
{% for item in item_list %}
<h2>{{ item.name }}</h2>
<ul>
{% for sub in item.subjects.all %}
<li>{{ sub.name }}</li>
{% endfor %}
</ul>
{% endfor %}
After creating your model form you can use something like this to get a dropdown
class CourseForm(forms.ModelForm):
subjects = forms.ModelMultipleChoiceField(
queryset=Subject.objects.all(),
required=True,
)
class Meta:
model = Course
fields = [......, subjects]
or you can use the other widget, widget=forms.CheckboxSelectMultiple,depending on your requirement
<form method="post" action="">
<div>
{% csrf_token %}
{{ form }}
<input type="submit" class="btn btn-primary" id="submit" value="Save">
</div>
</form>
Add a create view to create a course something like below
class CourseCreateView(CreateView):
model = Course
form_class = CourseForm
template_name = 'course_form.html'
success_url = reverse_lazy('/')

I want to access struct block default ID in its template

I want to save stream field ID into it's template.
In short, in text_question.html I am giving id = {{ self.id }} but that return Nothing.
I want this because in question.html file I want it to compare with {{
field.id }} which return stream field ID
In another word, I want to store {{ field.id }}'s value in id field of text_question.html
models.py
class TextQuestionBlock(blocks.StructBlock):
"""Text Question"""
question = blocks.CharBlock(required=True, help_text="Add your Question")
is_save = blocks.BooleanBlock(label="Want to save this field ?", required=False)
is_email = blocks.BooleanBlock(label="Want to get this field as an email ?", required=False)
class Meta: # noqa
template = "question/question_field/text_question.html"
icon = "edit"
label = "Text Question"
#register_setting(icon='fa-commenting')
class QuestionSettings(BaseSetting):
body = StreamField([
("text_question", TextQuestionBlock()),
], verbose_name='Question', blank=True)
panels = [
StreamFieldPanel('body')
]
class Meta:
verbose_name_plural = 'Question'
verbose_name = 'Questions'
text_question.html
{% load tag_library %}
<input issave="{{self.is_save}}" isemail="{{ self.is_email }}" class="text_question" type="text" name="{{ self.question|to_name }}" id="{{ self.id }}" data-conv-question="{{ self.question }}"
question.html
<form name="question_form" action="" method="post" class="hidden">
<div id="unique_id"></div>
{% for field in question.body %}
{{ field.id }}
{% endfor %}
<input type="text" data-conv-question="test">
</form>
Thank You!!!
The ID is not a built-in property of the block value - rather, it's a mechanism used by the StreamField container to keep track of its contents. It's not always meaningful for a block value to have an ID property: for example, the value of a CharBlock is a string, and you can't really have an .id property on a string. Similarly, child blocks of StructBlock won't be given one.
As a result, the id is not automatically available on a block's template - if you want it, you need to pass it explicitly from the calling template, via the {% include_block %} template tag. For example:
{% for field in question.body %}
{% if field.block_type == 'text_question' %}
{% include_block field with block_id=field.id %}
{% endif %}
{% endfor %}
This will make the ID available on text_question.html as the variable block_id.

Django how to set custom properties for a ModelForm

I have a forms.ModelForm 'CreateUserForm'.
I want to set a property for each form field to be later used in the template.
In this case, I want to set a icon name to specify which icon name should be used for each field.
class CreateUserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
icon_names = ['person', 'email', 'enhanced_encryption']
class Meta:
model = User
fields = ['username', 'email', 'password']
I've had trouble iterating over both the field AND the field's property 'icon_names'. I can't really zip() without losing functionality.
Currently I've hacked together iteration by using the 'forloop.parentloop.counter'
{% for field in form %}
<div class="form-group">
<div class="input-field">
<i class="icons">
{% for icon in form.icon_names %}
{% if forloop.parentloop.counter == forloop.counter %}
{{ icon }}
{% endif %}
{% endfor %}
</i>
<input type="text" id="autocomplete-input" class="autocomplete">
<label class="control-label" for="autocomplete-input">{{ field.label_tag }}</label>
</div>
</div>
{% endfor %}
Which produces the intended result, but it seems redundant, especially if I wanted to add another field property in the future.
What's the proper way to do this?
One idea would be to pass the zipped list in the context, such as:
context = {'fields_with_icons': zip(form.icon_names, [field for field in form])}
and then
{% for field, icon in fields %}
{{ field }}
{{ icon }}
{% endfor %}
There are two ways i could do this both involving adding an extra html attribute on the fields widget
see age field below, i would use the self.fields to get the field widget and add the extra icon attribute on its attrs dictionary...for this to work you should ensure it comes after the call to super().__init__(*args, **kwargs) others the self.fields will not have been populated....i'd use this when i dont have anything else i need to adjust on the widget class.
https://docs.djangoproject.com/en/2.0/ref/forms/widgets/#styling-widget-instances
see name field below, You could do this on the Meta class https://docs.djangoproject.com/en/2.0/topics/forms/modelforms/#overriding-the-default-fields
The form
class PersonForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['age'].widget.attrs['icon'] = 'age'
class Meta:
model = models.Person
fields = ('name', 'age')
widgets = {
'name': forms.TextInput(attrs={'icon': 'email'})
}
And on the template when looping over the fields id get it like this
{% for field in form %}
{{ field.field.widget.attrs.icon }}
{% endfor %}

Put model's id in hidden input in template

I would like to put a hidden input in my template containing my model's id. This is what I have:
models.py:
class MyModel(models.Model):
name = models.CharField(max_length=10)
class MyModelForm(ModelForm):
class Meta:
model = MyModel
fields = ['name']
widgets = {
'name': TextInput(),
}
index.html:
{{ form.name.label_tag }}
{{ form.name }}
This works fine and displays a simple form with a text input. What I want to do is add a hidden input that contains the model's id. I tried:
models.py:
class MyModel(models.Model):
name = models.CharField(max_length=10)
class MyModelForm(ModelForm):
class Meta:
model = MyModel
fields = ['name', 'id']
widgets = {
'name': TextInput(),
'id': HiddenInput(),
}
index.html:
{{ form.name.label_tag }}
{{ form.name }}
{{ form.id }}
But it doesn't work. If possible I wanted to avoid manually doing this:
index.html:
{{ form.name.label_tag }}
{{ form.name }}
<input type="hidden" name="id" value="{{ form.instance.id }}">
Thanks!
UPDATE
My overall goal is to have a form that edits an existing model. So I retrieve a model using the ORM and display it on the form. When I submit the form to update the object, I need to know its id in order for the ORM to know which object to update. Thanks!

Mongoengine, Flask and ReferenceField in WTForms

Hy everybody,
I'm realizing a Flask/MongoDB project and since I am new to this world, I've followed the tutorial at this page:
http://docs.mongodb.org/ecosystem/tutorial/write-a-tumblelog-application-with-flask-mongoengine/
After that, I've started to code my own application and this is part of the code:
MODELS:
class Generic(db.Document):
descrizione = db.StringField(max_length=255, required=True)
meta = {
'allow_inheritance': True,
'indexes': [
{'fields': ['descrizione'], 'unique': True}
]
}
class Category(Generic):
def __call__(self, *args):
pass
class User(db.Document):
email = db.EmailField(max_length=255, required=True)
nickname = db.StringField(max_length=255, required=True)
password = db.StringField(max_length=16, required=True)
categoria = db.ReferenceField('Category', required=True)
meta = {
'indexes': [
{'fields': ['nickname', 'email'], 'unique': True}
]
}
As you can see above, I've a "Category" class which inherits the "Generic" class. The "User" class finally has a ReferenceField to the Category. This way when I create a user, the category field on mongo db is stored as an ObjectID, related to the "generic" collection which has all the categories I've created.
The next step is to create the form to insert new documents into the user collection.
In my Views python file I've this cose:
def iscrizione():
form = model_form(User, only=['email', 'nickname', 'password', 'categoria'])(request.form)
if request.method == 'GET':
ctx = {
'form': form
}
return render_template('users/iscrizione.html', **ctx)
The template uses the Jinja macro reported in the tutorial page:
{% 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 %}
And finally, this is my problem
(If you have reached this text, you are my hero)
When I visit the webpage with the rendered form, the macro correctly show the text fields, and for the ReferenceField in my model it show a combo box.
The options values in the select combo are perfectly aligned with the object id of the category documents I've created. Choosing one of these and submitting the form, my application correctly creates the new user document.
Unfortunately, the select box labels doesn't show a human readable value, reporting "Category object".
<select id="categoria" name="categoria">
<option value="530536363c74031c24ee7ab6">Category object</option>
<option value="5305362d3c74031c24ee7ab5">Category object</option>
<option value="530535793c74031b73dd07b4">Category object</option>
</select>
How can I manage to show a correct label for the select box?
Finally I've made it!
Suppose that the field "categoria" of the User document is a ReferenceField to the "Category" collection.
Just add the "label_attr" attribute to "form.categoria" using the field name of the Category model that you want as label.
def iscrizione():
form = model_form(User, only=['email', 'nickname', 'password', 'categoria'])(request.form)
form.categoria.label_attr='descrizione' #<< add this line
if request.method == 'GET':
ctx = {
'form': form
}
return render_template('users/iscrizione.html', **ctx)
This can also be made through the field args in the model_form function:
form = model_form(
User,
only=['email', 'nickname', 'password', 'categoria'],
field_args={'categoria': {'label_attr': 'descrizione'}}
)
Maybe its will be useful to someone. You can use standard approach, like define
def __str__(self):
return self.descrizione
for your Category class

Categories

Resources