So I have a form
class DownloadForm(forms.Form):
title = forms.CharField()
device_family = forms.ChoiceField(label="Device Family",
widget=forms.Select(attrs={'class': 'form-control',
'data-toggle': 'select'}),
choices=LOG_ENTRY_TYPES, required=True
)
and in view.py I do
LOG_ENTRY_TYPES = (
('', 'All'),
('auth', 'Auth'),
('error', 'Error'),
('info', 'Info'),
('proxy', 'Proxy'),
)
DownloadFormSet = formset_factory(DownloadForm)
formsets = DownloadFormSet(initial=[
{'title': 'Django is now open source', 'device_family': LOG_ENTRY_TYPES},
{'title': 'Django source 2', 'device_family': LOG_ENTRY_TYPES},
{'title': 'Django source 3', 'device_family': LOG_ENTRY_TYPES}
])
This creates the device_family field but the LOG_ENTRY_TYPES choices are not generated. So how can I pass the LOG_ENTRY_TYPES choices to the device_family choices field so that the drop down shows the choices.
Related
I use Django formset factory and update view don't fill subform with
raw SQL query and return 'RawQuerySet' object has no attribute 'ordered'
error.
object query set fine but raw SQL query return this error.
'''python
formset = modelformset_factory(model=GiftVoucherSub,
form=GiftVoucherSubForm,
extra=0,
can_delete=True,
min_num=1,
validate_min=True,
)
formset = formset(request.POST or None,
queryset=queryset,
# initial=initial,
prefix='rlt_giftvoucher',
)'''
fixed by adding extra field to forms.py and views queryset with django object.
passanger name with autocomplete.
views
queryset = GiftVoucherSub.objects.filter(main_id=id, is_deleted=False).order_by('id')
forms
class GiftVoucherSubForm(forms.ModelForm):
passanger_id = forms.CharField(max_length=30,
required=False,
widget=forms.HiddenInput()
)
passanger_name = forms.CharField(widget=forms.TextInput(attrs={
# 'id': 'form_fatura_cari_isim',
'class': 'formset-field table-condensed clearable',
'required': 'True',
'autocomplete': 'off',
'type': 'search',
'onfocus': 'fn_search_passanger(this.id)',
}
)
)
class Meta:
model = GiftVoucherSub
fields = [
'id',
'main_request_type',
'sub_request_type',
'passanger_id',
'passanger_name',
'is_deleted',
]
def __init__(self, *args, **kwargs):
super(GiftVoucherSubForm, self).__init__(*args, **kwargs)
if self.instance.passanger_id:
extra_value = BoYolcuListesi.objects.get(usertableid=self.instance.passanger_id)
self.fields['passanger_name'].initial = extra_value.isim
self.helper = FormHelper()
self.helper.form_tag = True
for field in self.fields:
self.fields[field].widget.attrs.update({'class': 'formset-field table-condensed'})
self.fields[field].label = ''
I am trying to render my django forms in the template using bootstrap and I keep getting an error:
BoundField' object has no attribute 'fields'
This is what I try:
{% for field in layer_form %}
{{ field | as_bootstrap }}
{% endfor %}
If I try this:
{{ layer_form|as_bootstrap }}
then it works. But I need to loop through the form fields and append some if statements in between.
Any idea what's going on here?
The above works with another form but not with this one:
lass ResourceBaseForm(TranslationModelForm):
"""Base form for metadata, should be inherited by childres classes of ResourceBase"""
owner = forms.ModelChoiceField(
empty_label="Owner",
label="Owner",
required=False,
queryset=Profile.objects.exclude(
username='AnonymousUser'),
widget=autocomplete_light.ChoiceWidget('ProfileAutocomplete'))
_date_widget_options = {
"icon_attrs": {"class": "fa fa-calendar"},
"attrs": {"class": "form-control input-sm"},
"format": "%Y-%m-%d %H:%M",
# Options for the datetimepickers are not set here on purpose.
# They are set in the metadata_form_js.html template because
# bootstrap-datetimepicker uses jquery for its initialization
# and we need to ensure it is available before trying to
# instantiate a new datetimepicker. This could probably be improved.
"options": False,
}
date = forms.DateTimeField(
localize=True,
widget=DateTimePicker(**_date_widget_options)
)
temporal_extent_start = forms.DateTimeField(
required=False,
localize=True,
widget=DateTimePicker(**_date_widget_options)
)
temporal_extent_end = forms.DateTimeField(
required=False,
localize=True,
widget=DateTimePicker(**_date_widget_options)
)
poc = forms.ModelChoiceField(
empty_label="Person (fill form)",
label="Point Of Contact",
required=False,
queryset=Profile.objects.exclude(
username='AnonymousUser'),
widget=autocomplete_light.ChoiceWidget('ProfileAutocomplete'))
metadata_author = forms.ModelChoiceField(
empty_label="Person (fill form)",
label="Metadata Author",
required=False,
queryset=Profile.objects.exclude(
username='AnonymousUser'),
widget=autocomplete_light.ChoiceWidget('ProfileAutocomplete'))
keywords = TaggitField(
required=False,
help_text=_("A space or comma-separated list of keywords"),
widget=TaggitWidget('TagAutocomplete'))
regions = TreeNodeMultipleChoiceField(
required=False,
queryset=Region.objects.all(),
level_indicator=u'___')
regions.widget.attrs = {"size": 20}
With this simple form it works:
class UploadCSVForm(forms.Form):
def __init__(self, *args, **kwargs):
super(UploadCSVForm, self).__init__(*args, **kwargs)
self.fields['selected_country'] = forms.MultipleChoiceField(choices=get_country_names(), required=True)
title = forms.CharField(max_length=80, required=True)
LAYER_TYPE = (
('1', 'Global Layer'),
('2', 'Layer by Region'),
('3', 'Layer by Province'),
)
layer_type = forms.ChoiceField(choices=LAYER_TYPE, required=True)
csv = forms.FileField(required=True)
permissions_json = forms.CharField(max_length=500, widget=forms.HiddenInput())
With a ForeignKey relationship, is it possible display the form of the object being pointed to inline? The documentation shows how to do the reverse, with inline formsets; but I was unable to find how to replace the default selection box with an inline form.
For example, consider the case:
class Address(models.Model):
line_1 = models.CharField(max_length=100)
line_2 = models.CharField(max_length=100)
town = models.CharField(max_length=50)
state = models.ForeignKey(State,
on_delete=models.PROTECT)
post_code = models.CharField(max_length=4)
class Person(models.Model):
# ...
residential_address = models.ForeignKey(Address, unique=True)
postal_address = models.ForeignKey(Address, unique=True)
By default, the form for Person will display two drop-down selections: one for the residential address and one for the postal address. Could I display the form instead? Perhaps through a widget and/or custom field?
So, since there has been no answer yet, I've been working on making my own field and widgets. The display aspect (mostly) works fine now, but I get errors when I try and save the object as the referenced object needs to be created beforehand; however, I'm not sure if I can (or should?) save the object or not.
Here's what I have:
model.py
class Address(models.Model):
# as above
class AddressField(models.OneToOneField):
description = "An address"
def __init__(self, **kwargs):
"""The foreign key should always be to an Address class."""
kwargs['to'] = 'address.Address'
kwargs['related_name'] = '+'
super().__init__(**kwargs)
def formfield(self, **kwargs):
"""See https://docs.djangoproject.com/en/1.10/ref/models/fields/#django.db.models.Field.formfield.
Change the default form field.
"""
from address.forms import AddressField as AddressFormField
defaults = dict(form_class=AddressFormField)
defaults.update(kwargs)
return super(AddressField, self).formfield(**defaults)
forms.py
class AddressField(fields.MultiValueField):
"""Address (multi-value) field."""
def __init__(self, *args, **kwargs):
error_messages = {
'incomplete': _("Please ensure all required fields are completed.")
}
sub_fields = (
# Unique key
models.ModelChoiceField(queryset=kwargs.pop('queryset'),
limit_choices_to=kwargs.pop('limit_choices_to'),
to_field_name=kwargs.pop('to_field_name'),
required=False,
error_messages={
'invalid': _("Invalid address.")
}),
# Line 1
fields.CharField(max_length=256,
error_messages={
'incomplete': _("Enter a first address line.")
}),
# Line 2
fields.CharField(max_length=256,
required=False),
# Town
fields.CharField(max_length=100,
error_messages={
'incomplete': _("Enter a town name.")
}),
# State
models.ModelChoiceField(queryset=State._default_manager.get_queryset(),
error_messages={
'incomplete': _("Select a state."),
'invalid': _("Invalid state.")
}),
# Post code
fields.CharField(max_length=4,
validators=[
RegexValidator(
regex=r"^[0-9]{4}$",
message=_("Invalid post code."),
code='invalid-postcode'
)
],
error_messages={
'incomplete': _("Enter a post code.")
}),
)
super().__init__(
error_messages=error_messages,
fields=sub_fields,
require_all_fields=False,
widget=AddressWidget,
*args, **kwargs
)
# TODO: Need to set the State choices
def compress(self, values):
"""See https://docs.djangoproject.com/en/1.10/ref/forms/fields/#django.forms.MultiValueField.compress.
Converts a list of values into an Address instance, unless no values
were given in which case None is returned.
"""
if not values:
return None
# If we have been given a PK, then fetch the object and updates its values
if values[0]:
try:
address = Address.objects.get(pk=values[0])
address.line_1 = values[1]
address.line_2 = values[2]
address.town = values[3]
address.state = values[4]
address.post_code = values[5]
except Address.DoesNotExist:
# TODO Handle this properly (if it every comes up)
raise Exception("Tried to get the address with key '{}', but could not find it.")
# Otherwise, instantiate a new Address
else:
address = Address(
line_1=values[1],
line_2=values[2],
town=values[3],
state=values[4],
post_code=values[5]
)
return address
class AddressWidget(widgets.MultiWidget):
"""Address widget."""
# TODO: Need ot handle the setting of choices (or not?)
choices = None
def __init__(self, *args, **kwargs):
sub_widgets = (
widgets.HiddenInput,
widgets.TextInput(attrs={
'title': _("Line 1"),
'size': 50,
'required': True,
'class': "address-line address-line1",
}),
widgets.TextInput(attrs={
'title': _("Line 2"),
'size': 50,
'required': False,
'class': "address-line address-line2",
}),
widgets.TextInput(attrs={
'title': _("Town"),
'size': 30,
'required': True,
'style': "flex-grow: 4;",
'class': "address-town",
}),
widgets.Select(attrs={
'title': _("State"),
'size': 3,
'required': True,
'style': "flex-grow: 1;",
'class': "address-state",
}),
widgets.TextInput(attrs={
'title': _("Post Code"),
'size': 4,
'required': True,
'style': "flex-grow: 1;",
'class': "address-postcode",
}),
)
super().__init__(
widgets=sub_widgets,
*args, **kwargs
)
self.widgets[4].choices=[[1, 2]]
print("widgets: {}".format(self.widgets))
def decompress(self, value):
"""See https://docs.djangoproject.com/en/1.10/ref/forms/widgets/#django.forms.MultiWidget.decompress.
Converts an Address object into a list of values; that is, performs the
converse of `compress` above.
"""
if not value:
return [None] * 6
if isinstance(value, Address):
return [
value.pk,
value.line_1,
value.line_2,
value.town,
value.state,
value.post_code
]
raise Exception("Unable to decompress the given value.")
def format_output(self, rendered_widgets):
"""See https://docs.djangoproject.com/en/1.10/ref/forms/widgets/#django.forms.MultiWidget.format_output.
Ensure that line 1 and 2 are on their own line, and place the town,
state and post code on the third line.
"""
print("choices: {}".format(self.choices))
return """
<div class="address-widget" style="display: flex; flex-direction: column;">
{pk}
{line_1}
{line_2}
<div class="address-locality" style="display: flex; flex-direction: row; flex-wrap: wrap">
{town}
{state}
{post_code}
</div>
</div>
""".format(
pk=rendered_widgets[0],
line_1=rendered_widgets[1],
line_2=rendered_widgets[2],
town=rendered_widgets[3],
state=rendered_widgets[4],
post_code=rendered_widgets[5],
)
I have two fields in a form:
names_field = CharField(
label='Names',
widget=Textarea(attrs={'rows': '10', 'placeholder': 'input names here ...'}))
file_field = FileField(label='Upload from file')
Both are not required, but I can pass form.is_valid() only if I fill the both fields. It fails when I submit only one field names_field or file_field.
My view part:
form = AddNamessForm(request.POST, request.FILES)
if form.is_valid():
...
I thought that required=False is a default value but it's not true.
names_field = CharField(
label='Names',
reuired=False,
widget=Textarea(attrs={'rows': '10', 'placeholder': 'input names here ...'}))
file_field = FileField(label='Upload from file', reuired=False)
I'm struggling to get my tests to throw a form validation error in Django. This is using standard/default input types.
# forms.py
class NewUserForm(forms.Form):
first_name = floppyforms.CharField(widget=floppyforms.TextInput(attrs={'class': 'form-control input-lg', 'placeholder': 'First Name'})),
last_name = floppyforms.CharField(widget=floppyforms.TextInput(attrs={'class': 'form-control input-lg', 'placeholder': 'Last Name'})),
email = forms.EmailField(),
mobile = floppyforms.CharField(
required=False,
widget=floppyforms.TextInput(attrs={'class': 'form-control input-lg', 'placeholder': 'Mobile number', 'autocomplete': 'false'})),
postcode = floppyforms.CharField(widget=floppyforms.TextInput(attrs={'class': 'form-control input-lg', 'placeholder': 'Postcode'})),
super_balance = floppyforms.CharField(widget=floppyforms.RangeInput(attrs={'class': 'bar', 'type': 'range', 'id': 'rangeinput',
'value': '492500', 'min': '75000', 'max': '1000000',
'step': '5000', }))
# tests.py
class NewUserFormTest(TestCase):
def setUp(self):
self.valid_data = {
'first_name': 'herp',
'last_name': 'derp',
'email': 'herp#derp.com',
'mobile': '0412345678',
'postcode': '00000',
'relationship_status': 'S',
'super_balance': '100000',
'current_super_provider': '49'
}
...
def test_invalid_fields(self):
form = NewUserForm({})
self.assertFalse(form.is_valid()) # correct
data = self.valid_data
data['email'] = 24234 # this field should fail
form = NewUserForm(data)
form.is_valid() # returns True
When I pass a blank dictionary to the initial form. form.errors displays {'super_balance': ['This field is required.']}. This is more confusing because the documentation states that unless explicitly declared then all fields are assumed to be required.
I'm using 1.8.5
Cheers in advance
You need to remove the trailing commas from all the fields in your form.
Instead of
class NewUserForm(forms.Form):
...
email = forms.EmailField(),
...
it should be
class NewUserForm(forms.Form):
...
email = forms.EmailField()
...
At the moment, NewUserForm.email is a tuple, not a field, so any values for that field in the data dictionary are ignored. The only field without the trailing comma is super_balance, which is why it is the only error that appears when you pass a blank dictionary to the form.