I have a Django form in which for some fields I pull choices from my database, shown below.
I have another field in which the user has to manually type in the data. Is it possible to give that field choices that are present from the database and an option to enter the data if the choice isn't there?
Example: The field name is player and I would like to have all the players already in database as options to choose from and if it is a new player, the option to enter it.
Is that what a TypedChoiceField is? I have been trying to find examples but no luck.
thanks!
forms
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
team_names = TeamName.objects.filter(league__name='MLB').order_by('name')
teams = [(team.id, team.name)for team in team_names]
self.fields['team'].choices = teams
TypedChoiceField is not what you think it is. It simply starts on a default value instead of a "------" blank value.
You could not define choices= on your model. But instead define a list of default choices outside of the model.
my_choices = (
"foo",
"bar",
"pop",
)
class MyModel(models.Model):
my_field = models.CharField(max_length=100)
Then in your view you'd want to import that tuple and pass it to you template:
from my_app.models import my_choices
def my_view(request, *a, **kw):
# view logic
return render(request, "path/to/my/template", choices=my_choices)
Then in your template you can have a select box with the default choices and string values. And also have an optional input type=text that will save to that field if populated.
Something like:
<select name="my_field">
<option value="" selected="selected">-----</option>
{% for choice in choices %}
<option value="{{ choice }}">{{ choice }}</option>
{% endfor %}
</select>
Will give you default choices. Then add an input with the same name, this will act as an optional new choice.
<input type="text" name="my_field"/>
Optionally you could write javascript logic that will ensure only the selectbox or the textfield gets submitted.
Related
I'm looking for a crispy forms version of this:
Django form with choices but also with freetext option?
Models.py
class Animals(models.Model):
animal_id = models.AutoField(primary_key=True)
animal_name = models.CharField(max_length=100, verbose_name='Animal Name')
forms.py
from django import forms
from django.forms import ModelForm
from .models import Animals
class CustomSelection(Field):
template = 'custom_selectbox.html'
class AnimalsForm(ModelForm):
class Meta:
model = Animals
fields = [
'animal_name',
]
def __init__(self, *args, **kwargs):
super(AnimalsForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = True
self.helper.layout = Layout(
Div(
Fieldset(CustomSelection('animal_name'))
FormActions(
Button('submit','Submit')
)
)
)
So if I have:
custom_selectbox.html
{% load crispy_forms_field %}
<div class="form-group">
{{ field.label_tag }}
{% crispy_field field 'class' 'custom-select' %}
</div>
this renders a box OK, which is the first thing I want.
Next, I would like to know if it's possible to somehow inject all of the existing animal_names,
something like this:
{% load crispy_forms_field %}
<input list="options" name="test-field" required="" class="form-control" id="test-field-add">
<datalist id="options">
{% for option in field.subwidgets %}
<option value="{{ option.choice_label }}"/>
{% endfor %}
</datalist>
but with support for crispy-forms. Essentially I want the user to be presented with a list of existing CharField entries - but if the thing they're looking for isn't around, then I want them to be able to add it. Note: it doesn't need to be a charfield - I could do an independent model and use a Foreign Key but if I do that I'm not sure if that means I need to make a separate form to add new entries to every model (the example is animal_name - in reality the form I need to build has lots of equivalent fields). I would accept the reduced control of a charfield over a foreignkey if it is easier for users to add new entries.
I think the datalist approach would work if I'm making the form directly (forgive me, I'm very new to django) but it feels like I'm (hopefully) missing a more django-esque solution. Ideally one that is compatible with my existing crispy-forms. These forms are very large, so I'm using the Layout() helper heavily, so I would really like to avoid re-creating all of this manually.
I have seen this: Django crispy forms work with custom widgets?
but it's very old and I don't understand django well enough to know if the answer still applies.
I have also seen: https://leaverou.github.io/awesomplete/ - this looks equivalent to the datalist approach.
Then finally, https://pypi.org/project/django-awesomplete/ - the only example is for the admin panel so I'm not sure if I can do the same thing with crispy-forms.
I did it using django-floppyforms. I found the solution here: Django form with choices but also with freetext option?
My code:
forms.py
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('sexo', 'data_nascimento', 'foto', 'sobre_mim', 'telefone', 'paroquia','cidade','estado', 'cep', 'possui_filhos', 'facebook', 'instagram')
widgets = {
'cidade': floppyforms.widgets.Input(datalist=CIDADES, attrs={'autocomplete': 'off'}),
}
Note:
CIDADES is my list containing cities.
atrrs is optional.
I am very new to Django, to Stackoverflow and to coding in general, so I'd appreciate any help.
I am trying to add a form to my website, which would have only select fields. After a user selects all options, I want to redirect them to another page, where I return different information in several tables from my database, based on all selects (all selected options together influence information shown in the tables).
I know this example is awkward, this is all made up just to give an idea of what I want to achieve in the end.
An example:
First page has 3 options:
book genre
city
age
Redirected page has three tables:
Most read books in this genre in this city by people around this age
List of libraries in this city, sorted based on how many books in this genre are there
How to sign up to top 3 libraries
A user does not modify the database in any way, so I suppose the form can have GET method.
So my question is what would be the best way to get values from the user and get a unique value based on that from the database? I want to return one list for each table, which I am planning to be regularly updating for each city, for each age group and for each genre.
I am trying to do this with the select widget now. For now I do not return anything, because I am not sure how to get the data from the user and use it.
forms.py:
class MyForm(forms.Form):
select1 = forms.ChoiceField(widget=forms.Select,
choices=Select1.objects.all().values_list('id', 'name'))
select2 = forms.ChoiceField(widget=forms.Select,
choices=select2.objects.all().values_list('id', 'name'))
select3 = forms.ChoiceField(widget=forms.Select,
choices=select3.objects.all().values_list('id', 'name'))
views.py
class Page(TemplateView):
template_name = 'project/index.html'
def get(self, request):
form = MyForm()
return render(request, self.template_name, {'form': form})
html:
<select name="{{ form.select1.name }}">
<option class="dropdown-menu" value="" disabled selected>Please
select</option>
{% for choice in form.select1.field.choices %}
<option value="{{ select1.0 }}">{{ select1.1 }}</option>
{% endfor %}
</select>
and the same code for the other two selects. I rendered them separately because of the way I designed the website.
class form(forms.ModelForm):
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
u = User.objects.get(user=user)
super(form, self).__init__(*args, **kwargs)
self.fields['phone'].queryset = Phone.objects.filter(user=u)
class Meta:
model = MyModel
fields = ["name", "description", , "phone"]
This form pre-populates the field phones with phones that belong to the currently logged in user. I got the template to display using {{ form.as_p }}, but I dont know how to manually display the fields with the pre-populated phone names to be chosen, in an html template.
I tried the snippet below as part of the bigger form, but it did not work.
<select multiple="multiple" id="id_phone" name="phone" required>
{% for p in phone %}
<option value="{{ p.id }}">{{ p.name }}</option>
{% endfor %}
</select>
Also, how can I allow a user to choose multiple phones at once with this pre-population method. I tried to use ModelMultipleChoiceField but it did not work.
There are two things that you need in this situation
Set an initial value for the field
Set the field widget to be able to select multiple values
Luckily, Django already has a widget for that!
The following code will achieve what you want:
class form(forms.ModelForm):
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
u = User.objects.get(user=user)
kwargs["initial"].update({
"phone": Phone.objects.filter(user=u)
})
super(form, self).__init__(*args, **kwargs)
class Meta:
model = MyModel
widgets = {
"phone": SelectMultiple
}
fields = ["name", "description", "phone"]
With these two pieces in place, the template becomes easy!
{{ form.phone.errors }} {# shows on page any errors during clean #}
{{ form.phone }} {# renders the widget #}
If you do not want to use the built in widget that Django provides, look into creating your own
For other ways to set initial values checkout this post
I am setting up a simple html page, the page captures the information that the user entered and based on the information that the user entered makes a new page. The problem is that I cant get back the information entered by the user at the backed and I dont understand where I am going wrong.
My views file is setup like this:
def suggestion(request):
if request.method == 'POST':
form = BusinessName(request.POST)
if form.is_valid():
data=form.cleaned_data
context = insert_function_here(data)
return render( request,'mainpage.html', context)
else:
form = BusinessName()
context = {'form':form}
return render( request,'mainpage.html', context)
My forms.py is setup like this:
class BusinessName(forms.Form):
business_name = forms.CharField(widget = forms.HiddenInput(), required = False)
The relevant part of my html is set up like this:
<form id="user_input_form" method="post" action="http://127.0.0.1:8000/textinsighters/suggestion">
Enter Your Business Name : <input type="text" list="browsers" name="browser" id="user_input">
{% csrf_token %}
{{ form }}
<datalist id="browsers">
<option value="Internet Explorer">
<option value="Firefox">
<option value="Chrome">
<option value="Opera">
<option value="Safari">
</datalist>
<button onclick="myFunction()">Submittt</button>
</form>
<script>
function myFunction() {
document.getElementById("id_business_name").value = document.getElementById("user_input").value;
document.getElementById("user_input_form").submit();
}
</script>
I want an auto-completing list so thats why I am creating a form in html. I get the user input, set the value of the Django form field to the value that the user entered and submit it. I should get something back but the variable 'data' in views doesnt contain the user input.
Thanks
You are using a forms.HiddenInput() as the widget and then add the form field yourself. This doesn't work that way. What if you change the field class to TextInput:
class BusinessName(forms.Form):
business_name = forms.CharField(widget = forms.TextInput())
If you're goal is to add custom attributes to the widget, then this can be done by providing an attrs dictionary:
class BusinessName(forms.Form):
business_name = forms.CharField(widget = forms.TextInput(attrs={
'list': 'browser'
}))
Or you could have a look at the django-widget-tweaks package to add attributes in the template.
A have a field in model (name model is Users_data):
bir_date = models.DateField(verbose_name="")
And form which represents model:
class Form_registration (ModelForm):
class Meta:
model = Users_data
in html:
<form name="registration" method="post" action="save_data_user/">
{% csrf_token %}
{{ form_registration.as_p }}
<input type="submit" value="SignUp">
</form>
View which saves form:
def saves_data_user_on_registration (request):
if request.method == 'POST':
c = {}
c.update(csrf(request))
form_user_data = Form_registration(request.POST, request.FILES)
if form_user_data.is_valid():
print form_user_data.errors
form_user_data.save()
return render_to_response('see_you_later.html', c, context_instance=RequestContext(request))
else:
print form_user_data.errors
return render_to_response('error.html', c, context_instance=RequestContext(request))
I can save simple data in form.
But I need save a data in drop-down list from html in field from my model Users_data.
<select name="DateOfBirth_Month">
<option>Month</option>
<option value="1">January</option>
<option value="2">February</option>
...
<select id="cd-dropdown" class="cd-select">
<option value="-1" selected>Day</option>
<option value="1">01</option>
<option value="2">02</option>
...
<select name="DateOfBirth_Year">
<option>Year</option>
<option value="2011">2011</option>
<option value="2010">2010</option>
<option value="2009">2009</option>
...
And I don't understand how I can to connect drop-down list with my form or model.
Thanks for answers.
You need to define a widget and set it for the DateField using widgets on the Meta class.
A good example of the particular widget that splits year, month and day into separate dropdowns can be found in Django documentation, see DateSelectorWidget:
class Form_registration (ModelForm):
class Meta:
model = Users_data
widgets = {'bir_date': widgets.DateSelectorWidget()}
This code assumes you've created a widgets.py module with DateSelectorWidget class inside.
Another good widget for the task is django.forms.extras.widgets.SelectDateWidget:
Wrapper around three Select widgets: one each for month, day, and
year.
Also see:
Django SelectDateWidget to show month and year only
django-datetime-widget
Hope that helps.
The answer is to use a choices attribute for your DateField in the model.
Here is how to do it: https://docs.djangoproject.com/en/dev/ref/models/fields/