I'm trying to populate in my template a <select> element with data from a form field like this:
forms.py
class CreatePlayerForm(forms.Form):
size = forms.CharField()
views.py
class CreatePlayer(FormView):
...
def get(self, request, *args, **kwargs):
...
boots = Boots.objects.filter(...).values_list('size', flat=True) # return a list
form.initial['boots'] = boots
template
<select id="leftValues4" size="5" multiple>
{% for boot in form.boots %}
<option>{{ boot }}</option>
{% endfor %}
</select>
With the above code I don't get any results.
Any suggestion?
You are not approaching this in the right way at all.
initial is specifically for pre-setting the chosen value. You are trying to populate the list of values. For that, you will need to use an actual field that supports such a list; and that is a ChoiceField, not a CharField.
Secondly, choices need to have an ID value as well as a display value; so you need a list/tuple of 2-tuples.
form:
class CreatePlayerForm(forms.Form):
size = forms.ChoiceField(choices=[])
def __init__(self, *args, **kwargs):
sizes = kwargs.pop('sizes')
super(CreatePlayerForm, self).__init__(*args, **kwargs)
self.fields['sizes'].choices = sizes
view:
class CreatePlayer(FormView):
...
def get_form_kwargs(self, *args, **kwargs):
form_kwargs = super(CreatePlayer, self).get_form_kwargs(*args, **kwargs)
boots = Boots.objects.filter(...).values_list('id', 'size')
form_kwargs['sizes'] = boots
return form_kwargs
template:
{{ form.boots }}
Related
There is a possibility in Django templates to refer to attributes of the field directly in a template. For example to .help_text or .label. Like that:
{% for field in form %}
{{field.label|safe}}
{{field}}
{% endfor %}
What is the right way to refer to a custom defined field property?
For example:
{{field.myproperty}}
I use ModelForm and in models.py I use my own ModelField. Everything works perfectly but any attempts to add my own property fail. In a sense that everything is ok but if I refer to this property in a template it just doesn't get it :-(
Models.py:
class MyFormField(forms.IntegerField):
MyProperty = 'whatever'
def __init__(self,active1='default',*args, **kwargs):
self.MyProperty = 'whatever'
super(MyFormField, self).__init__(*args, **kwargs)
class MyOwnField(models.IntegerField):
def __init__(self, active1='asdf',*args, **kwargs):
super(MyOwnField, self).__init__(*args, **kwargs)
def formfield(self, **kwargs):
defaults = {'form_class': MyFormField}
defaults.update(kwargs)
return super().formfield(**defaults)
class MyModel(Model):
ns6_1 = MyOwnField()
Firstly, case is significant; field.myproperty is not the same as field.MyProperty.
Secondly, when you iterate through a form you don't directly get the form fields, you get BoundField instances. Each of these has a field property which is the field itself. So:
{{ field.field.MyProperty }}
I succesfully implemented the django-selectable AutoCompleteSelectField in a simple form that lets you enter an note description and a corresponding domain category ( domain and foreign key picked from other Many-to-One relationship
See: most relevant code:
# MODEL
class Note(models.Model):
notetext = models.TextField(default='nota')
domain = models.ForeignKey(Domain)
def __str__(self):
return self.notetext
def get_absolute_url(self):
return reverse('note:note_detail', args= [self.id])
# FORM
class NoteForm(forms.ModelForm):
domainselect = AutoCompleteSelectField(lookup_class= DomainLookup, label='Pick a domain category', required=True,)
def __init__(self, *args, **kwargs):
super(NoteForm, self).__init__(*args, **kwargs)
domaintext = self.instance.domain.title
self.fields['domainselect'].widget = AutoCompleteSelectWidget(DomainLookup , { 'value': self.instance.domain.title } )
def save(self, commit=True):
self.instance.domain = self.cleaned_data['domainselect']
return super(NoteForm, self).save(commit=commit)
class Meta:
model = Note
fields = ('notetext',)
widgets = {
'domain' : AutoCompleteSelectWidget(DomainLookup), }
# VIEW
class EditNoteView(generic.edit.UpdateView):
model = Note
form_class = NoteForm
success_url = "/note/"
def get_queryset(self):
base_qs = super(EditNoteView, self).get_queryset()
return base_qs.filter()
def get_object(self):
object = get_object_or_404(Note,id=self.kwargs['id'])
return object
# TEMPLATE
{% extends "base_sidebar.html" %}
{%block content%}
<form action="" method="post">
{{form.as_p}}
<button type="submit">Save</button>
{% csrf_token %}
{% load selectable_tags %}
{{ form.media.css }}
{{ form.media.js }}
</form>
{%endblock%}
Now, when an existing record is selected for editing via generic.edit.UpdateView in a Modelform, I want to populate the AutocompleteSelectField with the corresponding values ( domain description and id ) formerly saved into the database upon loading the form.
By overwriting the init(self, *args, **kwargs) method of the NoteForm, I was able to get almost this far in the sense that the first HTML input field gets populated.
However, the hidden input value gets set to the same value and pushing the save button results in posting a non valid form as if no domain category was selected.
Here's the page source that is sent back to the Browser:
<p><label for="id_domainselect_0">Pick a domain:</label>
<input data-selectable-allow-new="false" data-selectable-type="text" data-selectable-url="/selectable/domain-domainlookup/" id="id_domainselect_0" name="domainselect_0" type="text" value="politics" />
<input data-selectable-type="hidden" id="id_domainselect_1" name="domainselect_1" type="hidden" value="politics" /></p>
I don't know how to change the context (by setting self.fields['domainselect'].widget) in order to get the title into the domainselect_0 input value and the corresponding pk into the hidden domainselect_1 input value. ?
Thanks for helping me out.
After digging down into the django-selectable and Django code it appears the AutocompleteSelectWidget is based on the Django forms.MultiWidget class.
The Django MultiWidget accepts 1 single value (list) that is decomposed into the values corresponding to the respective 'subWidgets' through a mechanism implemented in a decompress method. ( see https://github.com/mlavin/django-selectable/blob/master/selectable/forms/widgets.py class SelectableMultiWidget )
So, all you have to do is assign a list containing title and id to the widget:
def __init__(self, *args, **kwargs):
super(NoteForm, self).__init__(*args, **kwargs)
self.initial['domainselect'] = [self.instance.domain.title , self.instance.domain.id ]
I want to show empty form field if there is nothing to show, otherwise a form field with the value inside:
{% if somevalue %}
{{form.fieldname}} #<---- how do i set the `somevalue` as value of fieldname here?
{% else %}
{{form.fieldname}}
{% endif %}
In your view, if it is a class-based view, do it like so:
class YourView(FormView):
form_class = YourForm
def get_initial(self):
# call super if needed
return {'fieldname': somevalue}
If it is a generic view, or not a FormView, you can use:
form = YourForm(initial={'fieldname': somevalue})
There are multiple ways to provide initial data in django form.
At least some of them are:
1) Provide initial data as field argument.
class CityForm(forms.Form):
location = ModelChoiceField(queryset=City.objects.all(), initial='Munchen')
2) Set it in the init method of the form:
class CityForm(forms.Form):
location = ModelChoiceField(queryset=City.objects.all())
def __init__(self, *args, **kwargs):
super(JobIndexSearchForm, self).__init__(*args, **kwargs)
self.fields['location'].initial = 'Munchen'
3) Pass a dictionary with initial values when instantiating the form:
#views.py
form = CityForm(initial={'location': 'Munchen'})
In your case, I guess something like this will work..
class CityForm(forms.Form):
location = ModelChoiceField(queryset=City.objects.all())
def __init__(self, *args, **kwargs):
super(JobIndexSearchForm, self).__init__(*args, **kwargs)
if City.objects.all().exists():
self.fields['location'].initial = ''
else:
self.field['location'].initial = City.objects.all()[:1]
That all is just for demonstration, you have to adapt it to your case.
I have a like model that collects likes that users select on books.
So, each record has the user_id, like_id and book_id.
I want a url that is something like:
(?P<top_num>\d+)/likes/
Wich would be directed to a view that does something like this:
class TopLikes(ListView):
""" Get all the archived projects """
queryset = Like.objects.filter(display=True)
template_name = "books/TopLikes.html"
paginate_by = 10
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(TopLikes, self).dispatch(*args, **kwargs)
What I don't know is how to take that top_num as the number to pass to the view to return the top ten books with the most likes.
it would make sense to me to do something like queryset = Like.objects.filter(display=True).annotate(num_books=Count('books')).order_by('num_books')
It makes sense to me to get the likes and then use the likes to do something like this in the template:
{% for object in object_list %}
{{ object.book.title }} with {{ object|length }}
{% endfor %}
Would this just be easier to do as a custom view?
Thanks
Override get_queryset() method, so that you can add custom filtering
Use self.kwargs, so that you can use top_num url parameter to limit your queryset
Use {{ object.num_books }}, because well what is {{ object|length }} supposed to do anyway :)
Example:
class TopLikes(ListView):
""" Get all the archived projects """
queryset = Like.objects.filter(display=True)
template_name = "books/TopLikes.html"
paginate_by = 10
def get_queryset(self):
qs = super(TopLikes, self).get_queryset()
qs = qs.annotate(num_books=Count('books')).order_by('num_books')
qs = qs[:self.kwargs['top_num']]
return qs
I have a template:
...
<form action="/reportform/" method="post">
<p><label>Aircraft system:</label>
<br>{{ Querry.system }}
...
it looks like this
How can I set a Size option for this box? for example, 10.
Use the attrs attribute to define the size.
class MyForm(forms.Form):
system = forms.ChoiceField(choices=SYSTEM_CHOICES,
widget=forms.SelectMultiple(attrs={'size':'40'}))
Sometimes, it is useful to override the widget in the forms init method.
class MyForm(forms.Form):
<snip>
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
self.fields['system'].widget = forms.SelectMultiple(attrs={'size':'40'}))