Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question about accessing and styling the prefix and phone number field separately. #622

Open
Jascha57 opened this issue Oct 15, 2024 · 2 comments

Comments

@Jascha57
Copy link

I have read the documentation and the issues that have been resolved, namely the #502, and cannot seem to figure it out. I want to access the prefix with the form in the context like so:

{{ form.phone.prefix_field }}
{{ form.phone.number_field }}

I understand that this is wrong and does not work, but was wondering if something like this is present or is it necessary to define a custom field for those specific widget to then style them. While using JS works for styling, it is a rather messy solution that I would like to avoid. I apologize if this has been answered somewhere else. I am a beginner and have just not uset multi value fields and widgets before. An example of how to separate these for styling without losing the validation process would be welcome. Thank you in advance.

@bikash829
Copy link

I think i have same issue. I am using SplitPhoneNumberField() but i want to set a custom bootstrap class in it. I didn't find any solution. If you found out the way please let me know.

@Jascha57
Copy link
Author

Jascha57 commented Nov 6, 2024

I think i have same issue. I am using SplitPhoneNumberField() but i want to set a custom bootstrap class in it. I didn't find any solution. If you found out the way please let me know.

You can define custom fields as:

class CustomPhonePrefixField(forms.ChoiceField):
    def __init__(self, *, choices=None, **kwargs):
        if choices is None:
            language = translation.get_language() or settings.LANGUAGE_CODE
            choices = localized_choices(language)
            choices.sort(key=lambda item: item[1])
        super().__init__(choices=choices, **kwargs)

class CustomPhoneNumberField(forms.CharField):
    def validate(self, value):
        super().validate(value)
        if not re.match(r'^\d+$', value):
            raise ValidationError(_("The phone number must contain only digits."))

And then:

class CustomSignUpForm(SignupForm):
    email = forms.EmailField(help_text=_("Email"))
    first_name = CustomNameField(help_text=_("First name"))
    last_name = CustomSurnameField(help_text=_("Last name"))
    phone_prefix = CustomPhonePrefixField(help_text=_("Country prefix"))
    phone_number = CustomPhoneNumberField(help_text=_("Phone number"))

    def clean(self):
        cleaned_data = super().clean()
        phone_prefix = cleaned_data.get("phone_prefix")
        phone_number = cleaned_data.get("phone_number")

        if phone_prefix and phone_number:
            full_number = f"+{phone_prefix}{phone_number}"
            try:
                parsed_number = phonenumbers.parse(full_number)
                if not phonenumbers.is_valid_number(parsed_number):
                    raise ValidationError(_("The phone number entered is not valid."))
            except phonenumbers.NumberParseException:
                raise ValidationError(_("The phone number entered is not valid."))

    def save(self, request):
        user = super(CustomSignUpForm, self).save(request)
        user.first_name = self.cleaned_data['first_name']
        user.last_name = self.cleaned_data['last_name']
        user.phone = f"+{self.cleaned_data['phone_prefix']}{self.cleaned_data['phone_number']}"
        user.save()
        return user

This way you just call it with the usual form syntax. I suggest using the package django-widget-tweaks that allows you to add classes quite easily. Your other option is to add the classes with Javascript by targeting the ID of the field as that is always the same, just F12 to find them. But I do not recommend this as it is very limiting. This implementation keeps you defining everything in the form. I just wish it was included in the package by default as these fields are just copied from their code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants