Building a Todo application using Django, Django Rest Framework, GraphQL, and PostgreSQL
Published: 2023-08-21 03:24:12


Today, we are building a Todo application using Django, Django Rest Framework, GraphQL, and PostgreSQL. This is a powerful tech stack that can help you create a robust and scalable application. Let's break down the steps to achieve this:

**Setting Up Django Project**
   Start by creating a new Django project or using an existing one. You can use the following command to create a new project:
   ```
   django-admin startproject projectname
   ```

**Setting Up PostgreSQL Database**
   Install the PostgreSQL database and configure it in your Django project's settings. Update the `DATABASES` configuration in your `settings.py` file with your PostgreSQL database credentials.

3. **Setting Up Django Rest Framework**
   Install Django Rest Framework using pip:
   ```
   pip install djangorestframework
   ```
4. **Add `'rest_framework'` to the `INSTALLED_APPS` list in your `settings.py` file**
	Your `INSTALLED_APPS` might look something like this after adding DRF:

   ```python
   INSTALLED_APPS = [
       # ... other apps ...
       'rest_framework',
       # ... more apps ...
   ]
   ```

5. **Creating a Todo Model**
   Define a Todo model in one of your Django app's `models.py` file. For example:
   ```python
   from django.db import models

   class Todo(models.Model):
       title = models.CharField(max_length=200)
       completed = models.BooleanField(default=False)
       created_at = models.DateTimeField(auto_now_add=True)
   ```

5. **Migrating the Database**
   Run the migrations to create the necessary database tables:
   ```
   python manage.py makemigrations
   python manage.py migrate
   ```

6. **Creating Django Rest Framework API**
   Create a serializer for the Todo model, views using Django Rest Framework's class-based views, and wire up the URLs for API endpoints.

------------


**Setting Up GraphQL**
   Install the `graphene-django` package to integrate GraphQL into your Django project:
   ```
   pip install graphene-django
   ```
   Create GraphQL schema and types for your Todo model.


**Defining GraphQL Queries and Mutations**
   Defining GraphQL queries and mutations involves creating a schema that outlines the available operations and their input/output types. In your case, for a Todo application, you'll want to define queries to fetch Todo items and mutations to create, update, and delete them. Here's how you can do that using the `graphene-django` package in a Django project:


   **Create GraphQL Schema**
   In one of your Django app files, typically `schema.py`, define your GraphQL schema and types. Here's an example for a Todo app:

   ```python
   import graphene
   from graphene_django.types import DjangoObjectType
   from .models import Todo

   class TodoType(DjangoObjectType):
       class Meta:
           model = Todo

   class Query(graphene.ObjectType):
       todos = graphene.List(TodoType)

       def resolve_todos(self, info):
           return Todo.objects.all()

   class CreateTodo(graphene.Mutation):
       class Arguments:
           title = graphene.String()

       todo = graphene.Field(TodoType)

       def mutate(self, info, title):
           todo = Todo(title=title)
           todo.save()
           return CreateTodo(todo=todo)

   class Mutation(graphene.ObjectType):
       create_todo = CreateTodo.Field()

   schema = graphene.Schema(query=Query, mutation=Mutation)
   ```

   In this example, the `TodoType` is a GraphQL type that maps to your `Todo` model. The `Query` class defines the `todos` query to fetch all Todo items. The `Mutation` class defines the `create_todo` mutation to create a new Todo.

3. **Wire Up URLs**:
   In your project's `urls.py` file, you need to create a GraphQL endpoint and connect it to the schema:

   ```python
   from django.urls import path
   from graphene_django.views import GraphQLView

   urlpatterns = [
       # ... other URL patterns ...
       path('graphql/', GraphQLView.as_view(graphiql=True, schema=schema)),
   ]
   ```

   This sets up the `/graphql/` endpoint for your GraphQL API. The `graphiql=True` argument enables the interactive GraphiQL interface for testing your queries and mutations.


After setting up your schema and URLs, you can use the GraphiQL interface to test your queries and mutations by accessing `http://localhost:8000/graphql/` (assuming your development server is running on the default port).

**Integrating Django Rest Framework (DRF) with GraphQL**

------------
Integrating Django Rest Framework (DRF) with GraphQL can be achieved by using the `graphene-django` library for GraphQL and leveraging DRF's serializers and views. This way, you can keep your existing DRF infrastructure for certain operations while using GraphQL for others. Here's how you can integrate the two:

**Install `graphene-django`**:
   If you haven't done so already, install the `graphene-django` package using the following command:
   ```
   pip install graphene-django
   ```

**Define GraphQL Types**:
   In your app's `schema.py`, define GraphQL types for the models you want to expose through GraphQL. Since you're using DRF, you can use DRF serializers to facilitate the conversion between Django models and GraphQL types.

   ```python
   import graphene
   from graphene_django.types import DjangoObjectType
   from .models import Todo
   from .serializers import TodoSerializer  # Your DRF serializer

   class TodoType(DjangoObjectType):
       class Meta:
           model = Todo

   class Query(graphene.ObjectType):
       todos = graphene.List(TodoType)

       def resolve_todos(self, info):
           queryset = Todo.objects.all()
           return queryset

   schema = graphene.Schema(query=Query)
   ```

**Use DRF Serializers in Mutations**:
   You can continue using DRF serializers in your GraphQL mutations to handle data input. Define GraphQL mutations that use DRF serializers to create, update, or delete objects.

   ```python
   class CreateTodo(graphene.Mutation):
       class Arguments:
           title = graphene.String()

       todo = graphene.Field(TodoType)

       def mutate(self, info, title):
           serializer = TodoSerializer(data={'title': title})
           if serializer.is_valid():
               todo = serializer.save()
               return CreateTodo(todo=todo)
           return CreateTodo(todo=None)

   class Mutation(graphene.ObjectType):
       create_todo = CreateTodo.Field()

   schema = graphene.Schema(query=Query, mutation=Mutation)
   ```

**Wire Up URLs**:
   In your project's `urls.py`, create a GraphQL endpoint that uses the `GraphQLView` from `graphene-django` and set up DRF views for your other API operations:

   ```python
   from django.urls import path
   from graphene_django.views import GraphQLView
   from rest_framework.routers import DefaultRouter
   from .views import TodoViewSet  # Your DRF viewset

   router = DefaultRouter()
   router.register(r'todos', TodoViewSet)

   urlpatterns = [
       path('graphql/', GraphQLView.as_view(graphiql=True, schema=schema)),
       path('api/', include(router.urls)),
   ]
   ```

   In this example, you're creating a DRF router for the `TodoViewSet` and a GraphQL endpoint at `/graphql/`.

This integration allows you to use both GraphQL and DRF in parallel, using the strengths of each for different parts of your application. Be sure to adjust the code to match your project's structure, models, serializers, and views.

**Testing and Running:**
    Test your API endpoints and GraphQL queries/mutations using tools like Postman or Insomnia. Run your Django development server:
    ```
    python manage.py runserver
    ```

Each step involves more detailed configuration and coding. Be sure to refer to the documentation for each technology (Django, Django Rest Framework, GraphQL, and PostgreSQL) to get the most accurate and up-to-date instructions.