What is the best way for connecting Django models choice fields with React js select options

Viewed 980

I find myself stuck in dealing with Django models choice fields and react select options. May someone kindly help. This is my models code:

class AccountType(models.Model):

    category = models.SmallIntegerField(
        choices=(
            (AccountCategories.ASSET, "Asset"),
            (AccountCategories.LIABILITY, "Liability"),
            (AccountCategories.EQUITY, "Equity"),
            (AccountCategories.REVENUE, "Revenue"),
            (AccountCategories.EXPENSE, "Operating Expense"),
        )
    )

    classification = models.SmallIntegerField(
        choices=(
            (AccountClassifications.NONE, ""),
            (AccountClassifications.CURRENT, "Current"),
            (AccountClassifications.NONCURRENT, "Long-Term"),
        )
    )

I cant seem to figure out on how to make these choices to be my select options in React form. Was thinking maybe the solution may be in validating or cleaning these choices in my serializers but I am stuck on the how especially on linking with a React Form. Thanks in advance

3 Answers

So I remembered Beazley's Tutorial on Python builtin SuperHeros or something like that and came up with this solution. Might not be the best as far as the DRY principle is concerned, but it works like a charm and for anyone who has struggled with the same issue and has no other way around, here is how I did it:

  ACCOUNT_TYPES_CATEGORY_CHOICES = [
        (100, 'Do Not Choose Me'),
        (0, 'Asset'),
        (1, 'Liability'),
        (2, 'Equity'),
        (3, 'Revenue'),
        (4, 'Operating Expense')

    ]

I put the choices in a seperate file.

class AccountType(models.Model):
    class Meta:
        ordering = ['order']

    objects = AccountTypeManager()

    category = models.IntegerField(choices=ACCOUNT_TYPES_CATEGORY_CHOICES)

    classification = models.IntegerField(choices=ACCOUNT_TYPES_CLASSIFICATION_CHOICES)

I imported the file and put it in my model and called python manage.py makemigrations

 class AccountingPeriodsChoicesAPIView(views.APIView):


    def get(self, request, format=None):

        my_choices = []
        choice_dict = dict(ACCOUNTING_PERIODS_CHOICES)
        for key, value in choice_dict.items():

            itered_dict = {"key": key, "value": value}
            my_choices.append(itered_dict)
        return Response(my_choices, status=status.HTTP_200_OK)

I created an api endpoint for it. I know that might be too much of work but it does work. Converting it into a dictionary and then unpacking it through .items(), and assigning the value and key and then returning it in Response did the trick. Calling it as an endpoint allows me to manage it under redux state and its doing what its suppose to do. Violla!!!!!

You can use django-js-choices

From the docs, the usage is simple:

Overview Django JS Choices is a small Django app that makes handling of model field choices in javascript easy.

For example, given the model…

# models.py:

class Student(models.Model):
    FRESHMAN = 'FR'
    SOPHOMORE = 'SO'
    JUNIOR = 'JR'
    SENIOR = 'SR'
    YEAR_IN_SCHOOL_CHOICES = (
        (FRESHMAN, 'Freshman'),
        (SOPHOMORE, 'Sophomore'),
        (JUNIOR, 'Junior'),
        (SENIOR, 'Senior'),
    )
    year_in_school = models.CharField(
        max_length=2,
        choices=YEAR_IN_SCHOOL_CHOICES,
        default=FRESHMAN,
    )

…the choices are accesible in javascript.

Choices.pairs("year_in_school");

Result:

[
    {value: "FR", label: "Freshman"},
    {value: "SO", label: "Sophomore"},
    {value: "JR", label: "Junior"},
    {value: "SR", label: "Senior"}
]

Display values are also accesible.

Choices.display("year_in_school", "FR")
Choices.display("year_in_school", {"year_in_school": "FR"})

In both cases the result is

"Freshman"

The preferred way for me was to save the choices data in json format and convert the file in models.py.

So the choices.json file would look like that:

// choices.json
{
"ACCOUNT_TYPES_CATEGORY_CHOICES": [
        {"value": 100, "display": 'Do Not Choose Me'),
        {"value": 0, "display": 'Asset'),
        {"value": 1, "display": 'Liability'),
        {"value": 2, "display": 'Equity'),
        {"value": 3, "display": 'Revenue'),
        {"value": 4, "display": 'Operating Expense')
],
...
}

In the models.py file convert the json file to a list of dict with tuples:

# models.py
def json2Tuples(jsonData):
    """
    Django only takes tuples (actual value, human readable name) so we need to repack the json in a dictionay of tuples
    """
    dicOfTupple = dict()
    for key, valueList in jsonData.items():
        dicOfTupple[str(key)] = [(dic["value"], dic["display"])
                                 for dic in valueList]
    return dicOfTupple

with open('choices.json') as f:
    choices_json = json.load(f)
choices = json2Tuples(choices_json)

class AccountType(models.Model):

    category = models.SmallIntegerField(
        choices=choices[“ACCOUNT_TYPES_CATEGORY_CHOICES“]
    )
...

For React you would need to install json-loader:

npm install json-loader

And adjust your react form:

import React from "react";
import { Form } from "react-bootstrap";
import jsonData from import jsonData from "/choices.json";

const MyForm = ({ handleChange }) => {
  const choices = jsonData.ACCOUNT_TYPES_CATEGORY_CHOICES;
  return (
    <div className="d-flex flex-column align-items-center">
      <h2>Account Type</h2>
      
      <Form.Group className="w-75 mt-4">
        <Form.Control
          placeholder="Account type"
          as="select"
          onChange={handleChange("account_type")}
          name="account_type"
        >
          {choices.map((c) => (
            <option key={c.value} value={c.value}>
              {c.display}
            </option>
          ))}
        </Form.Control>
      </Form.Group>
    </div>
  );
};

export default MyForm;
Related