MultiValueField and MultiWidget

Hello everybody.

In my app database, users’ identity card info stores like this: XA12345678 (XA is a series of a user identity card and 12345678 - its 8-digit number).
But in a form, I want users to select the series from the dropdown list and enter the number in the text field.
So, it seems appropriate to use a custom form field and widget based on MultiValueField and MultiWidget. Unfortunately, Django official documentation isn’t much help. On the Internet, I have found only a few helpful pieces of information too.

What my present code looks like:

#Custom field
class SICField(forms.MultiValueField):
widget = SICWidget

def __init__(self, reg_ex, *, is_stripped=True, **kwargs):
    fields = (
        forms.ChoiceField(),
        forms.RegexField(reg_ex, strip=is_stripped)
    )
    super().__init__(fields, **kwargs)

def compress(self, data_list):
    return ''.join(data_list)

#Custom widget
class SICWidget(forms.MultiWidget):
template_name = ‘widgets/sic_widget.html’

def __init__(self, attrs=None, series_attrs=None, number_attrs=None, options=()):
    widgets = [
        forms.Select(choices=options, attrs=attrs if series_attrs is None else series_attrs),
        forms.TextInput(attrs=attrs if number_attrs is None else number_attrs)
    ]
    super().__init__(widgets)

def decompress(self, value):
    if value:
        return [value[:2], value[2:]]
    return [None, None]

#MyForm
class MainForm(forms.Form):
SERIES_CHOICES = [(‘ХА’, ‘ХА’)]
sic = SICField(’^\d{8}$’, label=‘User Identity Card’,
widget=SICWidget(number_attrs={‘placeholder’: _(‘8-digit number of your card’)},
options=SERIES_CHOICES))

The main problem is there isn’t any value in <input type=text … in a Web-page with the form. Any suggestions?
Thanks in advance.

you can do like this
from django.forms import MultiWidget, NumberInput
from django import forms
widget = MultiWidget(widgets=[forms.Select(choices=((‘XA’, ‘XA’), (‘XB’, ‘XB’))), NumberInput])
widget.render(“identity_card”, [“XA”, None])
output -> '<select name="identity_card_0"><option value="XA" selected>XA</option><option value="XB">XB</option></select><input type="number" name="identity_card_1">'

@AlvesInfo thanks for your advice. I have already solved the problem. Maybe the solution will help someone.

#Custom field
class SICField(forms.MultiValueField):
widget = SICWidget

    def __init__(self, number_reg_ex, *, is_stripped=True, **kwargs):
        fields = (
            forms.ChoiceField(choices=kwargs.get('widget').options,
                              error_messages={'required': _('Select a sic series.')}),
            forms.RegexField(number_reg_ex,
                             error_messages={'invalid': _('Enter a valid sic number.')},
                             strip=is_stripped)
        )
        super().__init__(fields, **kwargs)

    def compress(self, data_list):
        return ''.join(data_list)

#Custom widget
class SICWidget(forms.MultiWidget):
template_name = ‘widgets/sic_widget.html’

    def __init__(self, attrs=None, options=()):
        self.options = options
        widgets = [
            forms.Select(choices=self.options),
            forms.TextInput(attrs=attrs)
        ]
        super().__init__(widgets)

    def decompress(self, value):
        if value:
            return [value[:2], value[2:]]
        return [None, None]

#MyForm
class MainForm(forms.Form):
    SERIES_CHOICES = [('ХА', 'ХА'), ('AS', 'AS')]
    sic = SICField('^[0-9]{8}$', label='Student Identity Card',
                   widget=SICWidget(attrs={'placeholder': _('8-digit number of your card')},
                                    options=SERIES_CHOICES))