Creating a Custom Choices Field in Django Model

152 Views Asked by At

I'm working on a Django project and need to implement a charfield field "Custom" in the dropdown menu in the UserProfile model. The requirements are as follows:

  1. Users should be able to select their gender from predefined options (Male or Female).

  2. Additionally, there should be an option to select "Custom" if the user's gender is not represented by the predefined options.

  3. If a user selects "Custom," a text field should appear, allowing them to enter their gender description.

I've already created the UserProfile model with predefined gender choices, but I'm not sure how to dynamically show or hide the text field based on the user's selection of "Custom."

Note: I want this to be done in both Django Admin and DRF API.

Feature should look like this: a screenshot of a custom field taken from Instagram

Here's my UserProfile model:

class UserProfile(models.Model):

    user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)

    FEMALE = 'FEMALE'
    MALE = 'MALE'
    CUSTOM = 'CUSTOM'
    NONE = 'NONE'

    GENDER = [
        (FEMALE, "Female"),
        (MALE, "Male"),
        (CUSTOM, "Custom"),
        (NONE, "Prefer not to say"),
    ]

    gender = models.CharField(
        max_length=20,
        choices=GENDER,
        default=NONE,
    )

    custom_gender = models.CharField(
        max_length=255,
        blank=True,  # Allow it to be optional
        null=True,   # Allow it to be null
    )

Here's my admin.py:

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.utils.translation import gettext_lazy as _
from core import models
from core.models import UserProfile


class ProfileInline(admin.StackedInline):
    model = UserProfile
    can_delete = False
    verbose_name_plural = 'User Profiles'
    fk_name = 'user'


class UserAdmin(BaseUserAdmin):
    """Define the admin pages for users."""

    inlines = (ProfileInline, )

    def get_inline_instances(self, request, obj=None):
        if not obj:
            return list()
        return super(UserAdmin, self).get_inline_instances(request, obj)

    ordering = ['id']  # order users by id
    list_display = ['email', 'name']  # list these items

    fieldsets = (
        (None, {'fields': ('email', 'password')}),
        (_('Personal Info'), {'fields': ('name',)}), 
        (
            _('Permissions'),
            {
                'fields': (
                    'is_active',
                    'is_staff',
                    'is_superuser',
                )
            }
        ),
        (_('Important dates'), {'fields': ('last_login',)}),
    )

    readonly_fields = ['last_login']

    add_fieldsets = (
        (None, {
            'classes': ('wide',),  # used for page look
            'fields': (
                'email',
                'password1',
                'password2',
                'name',
                'is_active',
                'is_staff',
                'is_superuser',
            ),
        }),
    )


admin.site.register(models.User, UserAdmin)

I would greatly appreciate any guidance on how to implement this feature, especially the part about conditionally showing the custom_gender field when "Custom" is selected.

Thank you!

1

There are 1 best solutions below

0
McPherson On

When rendering the form in the templates, you could initially hide the custom_gender field (or its parent). You can then simply toggle it's visibility based on the selected gender value by listening to a change event on gender field.

If you know some JavaScript, this shouldnt be too difficult to implement. Let me know if you need an example code.