Hov can get the translated values in select? - django

I get select with values Without and With. How can I get already translated values Без and С in django.po in a select?
models.py
CONFIRMATION_WITHOUT = 'without'
CONFIRMATION_OTHER = 'other'
CONFIRMATION_WITH = 'with'
CONFIRMATION_CHOICES = (
(CONFIRMATION_WITHOUT, _('Without')), #Без
(CONFIRMATION_OTHER, _('Other')), #Другое
(CONFIRMATION_WITH, _('With')), #С
)
income_proof = models.CharField(_('proof'), max_length=255, choices=CONFIRMATION_CHOICES, default=CONFIRMATION_WITHOUT)
#[u'without', u'with']
forms.py
income_proof = forms.ModelChoiceField(queryset=CreditPayment.objects.values_list('income_proof', flat=True).distinct(), widget=forms.Select(attrs={'class': 'selectpicker form-control', 'title':_("Income proof")}))
html
{{ form.income_proof }}
It is possible to make in the form, for example?
<select>
<option value = "CONFIRMATION_WITHOUT">Без</option>
</select>

For the form, you should not use a ModelChoiceField [Django-doc]. Indeed, you here do not select a model object, but a value. You thus should use a ChoiceField [Django-doc] instead.
As for the options, I think you want to use CONFIRMATION_CHOICES, since by using a queryset, you query the database, and you thus are only able to pick income_proofs that are already picked by other records.
from app.models import CONFIRMATION_CHOICES
from django import forms
class MyForm(forms.ModelForm):
income_proof = forms.ChoiceField(
choices=CONFIRMATION_CHOICES,
widget=forms.Select(
attrs={'class': 'selectpicker form-control', 'title':_('Income proof')}
)
)
or if you only want the values that were selected, you can use:
from app.models import CONFIRMATION_CHOICES
from django import forms
class MyForm(forms.ModelForm):
income_proof = forms.ChoiceField(
choices=[],
widget=forms.Select(
attrs={'class': 'selectpicker form-control', 'title':_('Income proof')}
)
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
render = dict(CONFIRMATION_CHOICES)
self.fields['income_proof'].choices = [
(k, render.get(k, k))
for k in CreditPayment.objects.values_list('income_proof', flat=True).distinct()
]
Here the __init__ is called when we construct the form. We first let the super constructor do the work to create the fields, then make a dictionary of the CONFIRMATION_CHOICES.
Next, we perform a query (the same one you used) to get the database values for income_proof, and we use the dictionary to map these to the corresponding translations. We thus yield a list of 2-tuples as choices for that form field.
We here thus use the choices= parameter [Django-doc] which should contain:
choices
Either an iterable of 2-tuples to use as choices for this field, or a
callable that returns such an iterable. This argument accepts the same
formats as the choices argument to a model field. See the model
field reference documentation on choices for more details. If the
argument is a callable, it is evaluated each time the field's form is
initialized. Defaults to an empty list.

Related

Django get choice display on using .values

For a Model with field type, is there any way to get the choice display value on using Model.objects.values() ? I tried Model.objects.values('get_type_display') but it doesn't work.
You can't do that. values is a built in django queryset method which is used to get dictionaries of data instead of model instances you can read more about it here.
The conventional (and proper) way of attaching choices with model for a field is using static variable like this.
class MyModel(models.Model):
TYPE_CHOICES = (
# (<DB VALUE>, <DISPLAY_VALUE>)
('a', 'Choice A'),
('b', 'Choice B'),
)
type = models.CharField(max_length=1, choices=TYPE_CHOICES)
You can access choices for type field outside model like this.
MyModel.TYPE_CHOICES
Where I do call .values of choice fields into my queryset I deal with this in the following way:
Assume the following model
from enum import Enum
class TypeChoice(Enum):
a = 'class A'
b = 'class B'
class MyModel(models.Model):
type = models.CharField(max_length=1, choices=[(tag.name,tag.value) for tag in TypeChoice])
Using the query my_qset = MyModel.objects.values('type') the display values are available as:
for item in my_qset:
print(TypeChoice[item].value)
To deal with this in my templates I write a custom template filter, say type_display:
from django import template
import TypeChoice
register = template.Library()
#register.filter
def type_display(var):
return TypeChoice[var].value
I had a similar need and unfortunately you can't do so with only values; however, you can do something similar with some crafty annotations and django's custom enums (IntegerChoices/TextChoices) classes.
I created this from another SO question but I can't remember where I got the inspiration from. Basically, you can pass in the corresponding model or the choices you'd like to map back to labels via annotations on the queryset.
class ChoicesLabelCase(Case):
def __init__(self, field: str, model: Model = None, choices: list = None, *args, **kwargs) -> None:
if choices is None and model is None:
raise ValueError("Either a model or a choices parameter must be provided.")
elif choices is None:
choices = model._meta.get_field(field).flatchoices
cases_list = [When(**{field: val, "then": Value(label)}) for (val, label) in choices]
super(ChoicesLabelCase, self).__init__(*cases_list, output_field=CharField(), *args, **kwargs)
As an example take this model:
class FruitType(models.IntegerChoices):
APPLE = 1, 'Apple'
BANANA = 2, 'Banana'
ORANGE = 3, "Orange"
class Fruit(models.Model):
type = models.IntegerField(choices=FruitType.choices)
You can annotate the labels like so:
>>> Fruit.objects.all().annotate(
type_label=ChoicesLabelCase('type', FruitType)
).values("type", "type_label")
[
{'type': 1, 'type_label': 'Apple'},
{'type': 2, 'type_label': 'Banana'},
...
]

Filter on a field with choices

I have this field:
operation = models.CharField(max_length=10, choices=OPERATIONS)
Having this filter works:
class OperationFilter(django_filters.Filter):
def filter(self, qs, value):
try:
qs = qs.filter(operation=value.upper())
except:
pass
return qs
With url:
/api/v1/operation/?operation=CREATE
But having the default filter (without an extra OperationFilter) fails with:
{
"operation": [
"Select a valid choice. %(value)s is not one of the available choices."
]
}
Why is a filter on a field with choices failing?
For other, non-choice fields, default filters are working fine:
/api/v1/operation/?recipient=recipient-19
EDIT
The OPERATIONS:
from enum import Enum
def enum_as_choices(enum_class):
"""From an enum class, generate choices for a django field"""
return ((entry, entry.value) for entry in enum_class)
class OperationType(Enum):
CREATE = 'CREATE'
STATUS = 'STATUS'
EXPAND = 'EXPAND'
DELETE = 'DELETE'
OPERATIONS = enum_as_choices(OperationType)
You are using django_filters package, I suggest reading docs, since you already have support for this
https://django-filter.readthedocs.io/en/master/ref/filters.html#choicefilter
Just point out your choices to the value suggested by the other answers (or check the example in docs)
The choices you written would be converted to this pythonic representation:
(
('OperationType.CREATE', 'CREATE'),
('OperationType.STATUS', 'STATUS'),
('OperationType.EXPAND', 'EXPAND'),
('OperationType.DELETE', 'DELETE')
)
As you can see the actual values stored in your operation field (in DB) are 'OperationType.CREATE', etc.
So you should change your choices to normal constant choices or you should filter by something like 'OperationType.CREATE' which is not a good option IMO.
also you can change your enum_as_choices method like this:
def enum_as_choices(enum_class):
"""From an enum class, generate choices for a django field"""
return ((entry.name, entry.value) for entry in enum_class)
You haven't defined a blank/default choice in your OPERATIONS. To do so, add something like this:
OPERATIONS = (
('', 'NONE'),
# the rest of your choices here...
)
But you would also need to update your model to be:
operation = models.CharField(max_length=10, choices=OPERATIONS, default='NONE')

Django forms: Is it possible to have multiple drop down menus for different tags within a field?

I have a form in a formset where I would like to display multiple drop down menus under a single field 'tests'. I have achieved this in the form of having a single dropdown menu within 'optgroup' tags (see image below).
I guess this way you can only choose a single value.
However, is it possible to 'nest' these drop downs? I.e have them all under one field 'tests', but be able to have several dropdowns with 'tags' and choose results for each tag? Or do I need a field for each 'tag'?
My forms.py:
class ReportForm(forms.ModelForm):
summary = forms.CharField(
widget=forms.Textarea(attrs={'rows':3, 'cols':70}),
label='',
required=False)
tests = forms.CharField(widget=forms.HiddenInput())
class Meta:
model = ClinicallyReportedSample
fields = ('id', 'summary', 'tests', 'hilis_reported')
def __init__(self, *args, **kwargs):
json_data = kwargs.pop('json_data', None)
super(ReportForm, self).__init__(*args, **kwargs)
crs_obj = self.instance
for j in json_data:
if j['lab_no'] == str(crs_obj):
json = j
summary = json['summary']
self.fields['summary'].initial = summary
self.fields['reported'].label = crs_obj
tests = json.get('tests', None)
if tests:
test_choices = (
('mutated', 'mutated'),
('mutated - see comments', 'mutated - see comments'),
('awaiting confirmation', 'awaiting confirmation'),
)
self.fields['tests'] = forms.ChoiceField(
required=True,
label='Current or repeat samples?',
choices=((k, test_choices) for k in tests),
)
What I get now:
I would instead want a dropdown for each gene, and those choices. Do I need to make a field for each gene? The problem I have with doing this is that each result can have 0-10 genes, and this would be incredibly difficult to render in a HTML table.
Thanks
You probably want to implement something template/client-side to handle that, such as Chosen or Selectize.js (see the option groups examples).
Then on your form class implement a clean and/or clean_[field_name] method if you need to get your selected data in the format you want.

Django: Deal Wizard and Auto ID

Say I have field named address_line_1 at form, once I render this it is generated as such:
<input id="id_1-address_line_1" type="text" name="1-address_line_1">
And I use this form at different pages however it doesn't have a consistency, one is generated as id_1-address_line_1 while some other same form at another view as id_1-address_line_1 thus it hurty my javascript side. How can I drop the id_X part so that the rendered id has the exact same name as the field name address_line_1
FormClass(prefix="prefix_to_display")
You can get rid of id_ by using the auto_id parameter. In your view class:
def get_form_kwargs(self, step=None):
kwargs = super().get_form_kwargs(step)
kwargs['auto_id'] = True
return kwargs
In order to get rid of the X- you'll have to render the fields manually. This can be done with custom templates, or in the field definitions:
address_line_1 = forms.CharField(
widget=forms.TextInput(attrs={'id': 'address_line_1'})
)

Blank option in required ChoiceField

I want my ChoiceField in ModelForm to have a blank option (------) but it's required.
I need to have blank option to prevent user from accidentally skipping the field thus select the wrong option.
This works for at least 1.4 and later:
CHOICES = (
('', '-----------'),
('foo', 'Foo')
)
class FooForm(forms.Form):
foo = forms.ChoiceField(choices=CHOICES)
Since ChoiceField is required (by default), it will complain about being empty when first choice is selected and wouldn't if second.
It's better to do it like this than the way Yuji Tomita showed, because this way you use Django's localized validation messages.
You could validate the field with clean_FOO
CHOICES = (
('------------','-----------'), # first field is invalid.
('Foo', 'Foo')
)
class FooForm(forms.Form):
foo = forms.ChoiceField(choices=CHOICES)
def clean_foo(self):
data = self.cleaned_data.get('foo')
if data == self.fields['foo'].choices[0][0]:
raise forms.ValidationError('This field is required')
return data
If it's a ModelChoiceField, you can supply the empty_label argument.
foo = forms.ModelChoiceField(queryset=Foo.objects.all(),
empty_label="-------------")
This will keep the form required, and if ----- is selected, will throw a validation error.
You can also override form's __init__() method and modify the choices field attribute, reasigning a new list of tuples. (This may be useful for dynamic changes):
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
self.fields['my_field'].choices = [('', '---------')] + self.fields['my_field'].choices
in argument add null = True
like this
gender = models.CharField(max_length=1, null = True)
http://docs.djangoproject.com/en/dev/ref/models/fields/
for your comment
THEME_CHOICES = (
('--', '-----'),
('DR', 'Domain_registery'),
)
theme = models.CharField(max_length=2, choices=THEME_CHOICES)