0

I'm trying to use custom CHOICE in MultipleChoiceField. I can save everything but not Employees.

models.py

class Employee(models.Model):
    employee_id = models.CharField(max_length=20, unique=True)

    def __str__(self):
        return '%s' % self.employee_id


class Task(models.Model):
    employee = models.ManyToManyField(Employee, blank=True, null=True)
    task = models.CharField(max_length=100)
    comment = models.CharField(max_length=200)

    def __str__(self):
        return '%s' % self.task

forms.py

class TaskCreateForm(forms.ModelForm):

    CHOICES = (
        ('123', 'Adam'),
        ('321', 'John'),
        ('666', 'Lucy'),
    )

    employee = forms.MultipleChoiceField(choices=CHOICES, required=True)


    def __init__(self, custom_choices=None, *args, **kwargs):
        super(TaskCreateForm, self).__init__(*args, **kwargs)
        if custom_choices:
            self.fields['employee'].choices = custom_choices

    class Meta:
        model = Task

So basically I added custom_choices, because I want to show in MultipleChoiceField Employee's names ('Adam', 'John' ,'Lucy') and save their

employee_id ('123','321', 666').

views.py

class TaskCreateView(CreateView):
    model = Task
    form_class = TaskCreateForm
    template_name = "task/create.html"

    def form_valid(self, form):
        self.object = form.save()
        return redirect('/task_page/')

I can see form on my page and I can choose employees, but employee_id is not saving. Only other fields task and comment are being saved.

Update for clarification:

There are no names in my models. I just want to show custom names for employee_id. That's why I need ('123','Adam') - I want to save '123' but display in my form 'Adam'

HereHere
  • 734
  • 1
  • 7
  • 24

2 Answers2

1

Well, the basic solution still stays the same:

queryset=Employee.objects.filter(employee_id__in=['some_id', 'other_id'])

The key point is that you should use a ModelMultipleChoiceField.

If you want to display the names rather than the IDs, there are a couple of ways to do that, e.g. a get_name method on the model and a custom ModelMultipleChoiceField, as described here: https://stackoverflow.com/a/3167840/1180983

So that would look roughly like this:

EMPLOYEE_NAMES = {
    '123': 'Adam',
    '321': 'John',
}

class Employee(models.Model):
    employee_id = models.CharField(max_length=20, unique=True)

    def get_name(self):
        return EMPLOYEE_NAMES.get(self.employee_id, 'unknown')

class EmployeeMultipleChoiceField(ModelMultipleChoiceField):
    def label_from_instance(self, obj):
        return obj.get_name()

class TaskCreateForm(forms.ModelForm)
    employees = EmployeeMultipleChoiceField(
        queryset=Employee.objects.filter(employee_id__in=['123', '321'])
    )
Community
  • 1
  • 1
René Fleschenberg
  • 2,418
  • 1
  • 15
  • 11
  • Hey I have ``AttributeError: 'module' object has no attribute 'EmployeeMultipleChoiceField'`` PyCharm highlighted `EmployeeMultipleChoiceField` in `TaskCreateForm` – HereHere Jun 25 '15 at 11:14
  • You should change `forms.EmployeeMultipleChoiceField` to `EmployeeMultipleChoiceField` – HereHere Jun 25 '15 at 11:22
  • Unfortunately I can see only ids. I followed exactly your way – HereHere Jun 25 '15 at 11:37
  • I did a quick test. This method works for me. Did you maybe use my suggested plural name (``employees``) on the form, but forgot to change your field name on the model (``employee``) accordingly? – René Fleschenberg Jun 25 '15 at 12:07
  • Here is a hg repo with a small demo: https://bitbucket.org/rfleschenberg/so-31047499/ Please note: This is not clean code, it is only meant as a very quick & dirty demo to help you track down your problem. Do not follow my example when it comes to things such as ``import *``. – René Fleschenberg Jun 25 '15 at 12:55
  • Unfortunately, my problem is more complex. And your solution doesn't fit my problem. However If your solution works for you, then I'll accept it. Here is my real problem: http://stackoverflow.com/questions/31053098/display-full-names-in-form-choicefield-but-saving-ids – HereHere Jun 25 '15 at 14:26
0

Your ModelForm does not know what to do with the employee field on save(), because you do not tell it anywhere, and that field is not connected to any model. Use a ModelMultipleChoiceField instead.

If you need to restrict the choices the ModelMultipleChoiceField allows, use the queryset argument:

employees = forms.ModelMultipleChoiceField(
    queryset=Employee.objects.filter(name__in=['Alice', 'Bob'])
)

Also, think about where to use plural and where to use singular names, so you do not confuse yourself (employees instead of employee above).

René Fleschenberg
  • 2,418
  • 1
  • 15
  • 11
  • No, no you guys don't understand. I need only display names and save `employee_id`. In my models there are no names. I just want to display in choicefield names, but saving only ids. – HereHere Jun 25 '15 at 10:33
  • Employee model only contains `employee_id`. I dont have any names. I just want to display custom names for `employee_id`. I updated my post – HereHere Jun 25 '15 at 10:43