DEV Community

Andrés Álvarez Iglesias
Andrés Álvarez Iglesias

Posted on • Updated on

Django 6 - Using the Django ORM

NOTE: This article was initially posted on my Substack, at https://andresalvareziglesias.substack.com/

Hi everyone!

Our multiplayer Tic Tac Toe is growing, and we have learned a lot about Django in this way: how to create a basic Django App, how to structure our app with subsites, how to separate UI and logic with views... Now, is the turn of a very, very, VERY important part of the development: managing pur application data.

Django comes with a great integrated ORM, so... let's learn how to use it!

Articles in this series

Image description

Writing Data Models

In chapter 4 of the series, we added a TimescaleDB (PostgreSQL) instance to our cluster. Now is the time to use it.

The Django migration process also automates the DB schema creation and management. To do that, Django must know the structure of our tables. To define them, we need to write Data Models.

A Data Model is a class that describes our table. For example, let' write a couple of Data Model for our Tic Tac Toe games, inside the game/models.py file:

class Game(models.Model):
   user_o = models.ForeignKey(
       User, 
       related_name="GameUserO", 
       on_delete=models.DO_NOTHING
   )

   user_x = models.ForeignKey(
       User, 
       related_name="GameUserX", 
       on_delete=models.DO_NOTHING, 
       null=True
   )

   board = models.CharField(max_length=9)
   creation = models.DateTimeField(auto_now_add=True)
   last_move = models.DateTimeField(auto_now=True)
   winner = models.CharField(max_length=1)
Enter fullscreen mode Exit fullscreen mode
class GameMovement(models.Model):
   user = models.ForeignKey(
       User, 
       related_name="GameMovement", 
       on_delete=models.DO_NOTHING
   )

   game = models.ForeignKey(
       Game, 
       related_name="GameMovement", 
       on_delete=models.DO_NOTHING
   )

   symbol = models.CharField(max_length=1)
   movement = models.IntegerField()
   date = models.DateTimeField(auto_now_add=True)
Enter fullscreen mode Exit fullscreen mode

These two Data Models define two tables:

  • A game table, linked to an Users table, with the current board and several info fields
  • A game movements table, to store every movement of a game, linked to Users and Game tables

Once the Data Models are created, execute the cluster again. The migration process will do its magic, and the databases will be automatically created. To check them, we can enter inside the DB container with:

sudo docker exec -it db psql ticmagicalline
Enter fullscreen mode Exit fullscreen mode

Once inside the PostgreSQL CLI get tables with \dt command:

                  List of relations
 Schema |            Name            | Type  | Owner 
--------+----------------------------+-------+-------
 public | auth_group                 | table | tic
 public | auth_group_permissions     | table | tic
 public | auth_permission            | table | tic
 public | auth_user                  | table | tic
 public | auth_user_groups           | table | tic
 public | auth_user_user_permissions | table | tic
 public | django_admin_log           | table | tic
 public | django_content_type        | table | tic
 public | django_migrations          | table | tic
 public | django_session             | table | tic
 public | game_game                  | table | tic
 public | game_gamemovement          | table | tic
(12 rows)
Enter fullscreen mode Exit fullscreen mode

And voilá! We now have our two game tables among Django inner tables.

Using Data Models

Once the tables are defined and mapped as objects, now we can use the Django ORM to do a lot of operations from our views, like data retrieval:

myGames = Game.objects.filter(Q(user_o=user), Q(winner='')).order_by("-creation")
paginator = Paginator(myGames, numStartPageGames)
context['myGames'] = paginator.get_page(1)
context['myGamesCount'] = paginator.count
Enter fullscreen mode Exit fullscreen mode

In this example, we added a filter to our query (user is our logged user) and we are sorting the resultset by the creation field.

In the same way, we can create a new game:

game = Game.objects.create(
    user_o=user, 
    user_x=None, 
    board="EEEEEEEEE", 
    winner="", 
    creation=datetime.now()
)
Enter fullscreen mode Exit fullscreen mode

Or modify and save and existing one:

game.last_move = datetime.now()
game.save()
Enter fullscreen mode Exit fullscreen mode

As you can see, the Django ORM simplifies the data management of our app. Now, we have all tools to develop the full logic of our shiny Tic Tac Toe:

  • The user must log into the app with its credentials (using standar Django users)
  • The user must be able to see its created games, or create a new one
  • The user must be able to make movements in it game

The real fun starts now!

Image description

About the list

Among the Python and Docker posts, I will also write about other related topics (always tech and programming topics, I promise... with the fingers crossed), like:

  • Software architecture
  • Programming environments
  • Linux operating system
  • Etc.

If you found some interesting technology, programming language or whatever, please, let me know! I'm always open to learning something new!

About the author

I'm Andrés, a full-stack software developer based in Palma, on a personal journey to improve my coding skills. I'm also a self-published fantasy writer with four published novels to my name. Feel free to ask me anything!

Top comments (0)