Posted on Leave a comment

Building a City Lookup Tool

React, React Query, and Django

Introduction:

In this tutorial, we’ll walk through creating a form that lets users select a state, county, and town using React, React Query, and Django as a backend. React will be used for building the frontend user interface, React Query for fetching and managing server-side data, and Django to create the backend API.

Prerequisites:

  • Basic understanding of React, React Query, and Django
  • Node.js and npm/yarn installed on your system
  • Python and Django installed on your system
  • Django Rest Framework ( install with pip )

Step 1: Setting up the Django Backend

1.1. Create a new Django project and app:

$ django-admin startproject myproject
$ cd myproject
$ python manage.py startapp myapp

1.2. In myapp/models.py, create the State, County, and Town models:

from django.db import models

class State(models.Model):
    name = models.CharField(max_length=100)

class County(models.Model):
    name = models.CharField(max_length=100)
    state = models.ForeignKey(State, on_delete=models.CASCADE)

class Town(models.Model):
    name = models.CharField(max_length=100)
    county = models.ForeignKey(County, on_delete=models.CASCADE)

1.3. Add ‘myapp’ to the INSTALLED_APPS in myproject/settings.py.

1.4. Run migrations to create the database schema:

$ python manage.py makemigrations
$ python manage.py migrate

1.5. Create serializers for the models in myapp/serializers.py:

from rest_framework import serializers
from .models import State, County, Town

class StateSerializer(serializers.ModelSerializer):
    class Meta:
        model = State
        fields = '__all__'

class CountySerializer(serializers.ModelSerializer):
    class Meta:
        model = County
        fields = '__all__'

class TownSerializer(serializers.ModelSerializer):
    class Meta:
        model = Town
        fields = '__all__'

1.6. Create views in myapp/views.py:

from rest_framework import generics
from .models import State, County, Town
from .serializers import StateSerializer, CountySerializer, TownSerializer

class StateList(generics.ListAPIView):
    queryset = State.objects.all()
    serializer_class = StateSerializer

class CountyList(generics.ListAPIView):
    serializer_class = CountySerializer

    def get_queryset(self):
        state_id = self.kwargs['state_id']
        return County.objects.filter(state_id=state_id)

class TownList(generics.ListAPIView):
    serializer_class = TownSerializer

    def get_queryset(self):
        county_id = self.kwargs['county_id']
        return Town.objects.filter(county_id=county_id)

1.7. Configure the API URLs in myapp/urls.py:

from django.urls import path
from . import views

urlpatterns = [
    path('states/', views.StateList.as_view(), name='state_list'),
    path('states/<int:state_id>/counties/', views.CountyList.as_view(), name='county_list'),
    path('counties/<int:county_id>/towns/', views.TownList.as_view(), name='town_list'),
]

1.8. Include the app URLs in the project’s urls.py:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('myapp.urls')),
]

Step 2: Setting up the React Frontend

2.1. Create a new React project using Create React App:

$ npx create-react-app myapp-frontend
$ cd myapp-frontend

2.2. Install the necessary dependencies:

$ npm install axios react-query

2.3. Replace the contents of src/App.js with the following:

import React, { useState } from "react";
import { useQuery } from "react-query";
import axios from "axios";

const fetchStates = async () => {
  const { data } = await axios.get("/api/states/");
  return data;
};

const fetchCounties = async (stateId) => {
  const { data } = await axios.get(`/api/states/${stateId}/counties/`);
  return data;
};

const fetchTowns = async (countyId) => {
  const { data } = await axios.get(`/api/counties/${countyId}/towns/`);
  return data;
};

function App() {
  const [selectedState, setSelectedState] = useState(null);
  const [selectedCounty, setSelectedCounty] = useState(null);

  const { data: states } = useQuery("states", fetchStates);

  const { data: counties } = useQuery(
    ["counties", selectedState],
    () => fetchCounties(selectedState),
    { enabled: !!selectedState }
  );

  const { data: towns } = useQuery(
    ["towns", selectedCounty],
    () => fetchTowns(selectedCounty),
    { enabled: !!selectedCounty }
  );

  return (
    <div className="App">
      <h1>Location Selector</h1>
      <select
        value={selectedState}
        onChange={(e) => {
          setSelectedState(e.target.value);
          setSelectedCounty(null);
        }}
      >
        <option value="">Select State</option>
        {states?.map((state) => (
          <option key={state.id} value={state.id}>
            {state.name}
          </option>
        ))}
      </select>

      {selectedState && (
        <select
          value={selectedCounty}
          onChange={(e) => setSelectedCounty(e.target.value)}
        >
          <option value="">Select County</option>
          {counties?.map((county) => (
            <option key={county.id} value={county.id}>
              {county.name}
            </option>
          ))}
        </select>
      )}

      {selectedCounty && (
        <select>
          <option value="">Select Town</option>
          {towns?.map((town) => (
            <option key={town.id} value={town.id}>
              {town.name}
            </option>
          ))}
        </select>
      )}
    </div>
  );
}

export default App;

In the code above, we create the App component, import the necessary dependencies, and define three functions to fetch states, counties, and towns from the API. We then use React Query’s useQuery hook to fetch the data and store it in the component’s state. Based on the user’s selection of state and county, we conditionally render the county and town dropdown menus.

Step 3: Configure Proxy for the Development Server

To avoid CORS issues while making API requests from the frontend, add a proxy to the development server. In myapp-frontend/package.json, add the following line:

"proxy": "http://localhost:8000",

This will proxy requests made by the development server to the Django back-end running on port

Step 4: Run the Application

There is some additional code if you are running bot the Django Server and the React Server ( as below )

Make sure you have react-query installed

npm install react-query

Modify your index.js

Add an import at the beginning of your index.js

import { QueryClient } from 'react-query';

Add a new instance below the imports ( in the index.js file )

const queryClient = new QueryClient();

Wrap your ‘App’ in the QueryClient ( in the index.js file )

  <QueryClientProvider client={queryClient}>
    <App />
  </QueryClientProvider>,

You index.js should now look like this:

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { QueryClient, QueryClientProvider } from 'react-query';

const root = ReactDOM.createRoot(document.getElementById('root'));
const queryClient = new QueryClient();

root.render(
  <React.StrictMode>
    <QueryClientProvider client={queryClient}>
      <App />
    </QueryClientProvider>,
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

4.1. Start the Django development server:

In the myproject directory, run the following command:

$ python manage.py runserver

This will start the Django development server on http://localhost:8000.

4.2. Start the React development server:

In the myapp-frontend directory, run the following command:

$ npm start

This will start the React development server, which will automatically open your default web browser and navigate to http://localhost:3000.

Now you should see the form with the state, county, and town dropdown menus. As you select a state and county, the corresponding counties and towns will be fetched and populated in the respective dropdowns.

Conclusion:

In this tutorial, we have demonstrated how to create a form with state, county, and town dropdowns using React, React Query, and Django. We utilized Django as our backend to serve the API, React to build the user interface, and React Query to manage data fetching and state management. This combination of technologies allows for a seamless and performant user experience while managing complex data dependencies.

Leave a Reply

Your email address will not be published. Required fields are marked *