Lesson 1
Referencing User in Your Models
Introduction

Welcome to the first lesson in our course on implementing an API for a TODO app with Django. In this lesson, we will explore how to reference users in your models — a crucial step toward personalizing and managing user-related data in web applications. By the end of this lesson, you will understand how to use Django's built-in User model, incorporate user references into existing models, and validate these modifications with testing. This foundational knowledge will set the stage for developing user-centric features seamlessly.

Recap of the Existing Models

Before we dive into the new content, let's quickly revisit the Group, Tag, and Todo models that you've previously implemented. This will help us set the foundation for adding user references. Here is a summary code block of these models:

Python
1class Group(models.Model): 2 name = models.CharField(max_length=50) 3 4class Tag(models.Model): 5 description = models.CharField(max_length=20) 6 color = models.CharField(max_length=7) 7 8class Todo(models.Model): 9 task = models.CharField(max_length=255) 10 completed = models.BooleanField(default=False) 11 priority = models.IntegerField() 12 group = models.ForeignKey(Group, on_delete=models.CASCADE, null=True, blank=True)

These models are currently not associated with users. Our task is to modify them by incorporating user references using Django's built-in User model.

Understanding the Django User Model

The Django framework provides a robust User model out of the box, designed to handle user authentication and management. This model includes essential fields like username, password, email, and more. Using Django's User model streamlines the management of user-related data, leveraging tested and secure components.

Utilizing this pre-defined model brings several benefits:

  • Simplicity: Save time by using a pre-built model with necessary authentication fields.
  • Consistency: Using a standard User model ensures your code aligns with industry best practices.
  • Security: Benefit from Django's security features, like password hashing, automatically.

With this understanding, you can now enhance the existing models by linking them with the User model.

Adding User References to Models

Adding user references involves using foreign keys, which establish relationships between your models and users in the database. Let’s start by modifying the Group model to include this reference:

Python
1from django.contrib.auth.models import User 2 3class Group(models.Model): 4 name = models.CharField(max_length=50) 5 user = models.ForeignKey(User, on_delete=models.CASCADE) 6 7 def __str__(self): 8 return self.name
  • We import Django's User model to enable referencing users.
  • The model now includes a user field as a ForeignKey to the User model.
  • We set on_delete=models.CASCADE, ensuring that when a user is deleted, the associated group is also removed.
Updating Other Models

We can update other models similarly:

Python
1class Tag(models.Model): 2 description = models.CharField(max_length=20) 3 color = models.CharField(max_length=7) 4 user = models.ForeignKey(User, on_delete=models.CASCADE) 5 6 def __str__(self): 7 return self.description 8 9 10class Todo(models.Model): 11 task = models.CharField(max_length=255) 12 completed = models.BooleanField(default=False) 13 priority = models.IntegerField() 14 assignee = models.ForeignKey(User, on_delete=models.CASCADE, related_name='assigned_todos', null=True, blank=True) 15 group = models.ForeignKey(Group, on_delete=models.CASCADE, null=True, blank=True) 16 due_date = models.DateTimeField(auto_now_add=True, blank=True, null=True) 17 tags = models.ManyToManyField(Tag, blank=True) 18 user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='todos') 19 20 def __str__(self): 21 return self.task
  • The assignee field is another user reference, allowing specific users to be assigned to a Todo item separately from the owner or creator (user).
  • related_name provides a way to access reverse relationships from the user perspective. For example, related_name='assigned_todos' allows you to query todos assigned to a specific user using user.assigned_todos.all(). Similarly, related_name='todos' allows retrieval of todos owned by the user using user.todos.all().

These associations enable a structured relationship in your database, providing a way to keep all the models user-specific.

Writing Tests to Validate Model Changes: Setup

Testing ensures that the models behave as expected and verifies the correctness of our user references. The setUp method is a part of the Django TestCase where you initialize data before each test. Let's see how to structure this part:

Python
1from django.test import TestCase 2from django.contrib.auth.models import User 3from .models import Group, Todo 4 5class UserGroupTodoTestCase(TestCase): 6 def setUp(self): 7 # Create two users 8 self.user1 = User.objects.create_user(username='user1', password='testpassword1') 9 self.user2 = User.objects.create_user(username='user2', password='testpassword2') 10 11 # Create one group for each user 12 self.group1 = Group.objects.create(name='Group1', user=self.user1) 13 self.group2 = Group.objects.create(name='Group2', user=self.user2) 14 15 # Create one todo item for each user, stored in this group 16 self.todo1 = Todo.objects.create(task='Todo for user1', completed=False, priority=1, user=self.user1, group=self.group1) 17 self.todo2 = Todo.objects.create(task='Todo for user2', completed=False, priority=2, user=self.user2, group=self.group2)
  • Here, setUp is initializing two users and associating a group and a todo item with each user.
  • This setup process runs before each test method to ensure a consistent testing environment.
Writing Tests to Validate Model Changes: Test Method

Now, let's look more closely at writing a test for these associations:

Python
1 def test_todo_creation(self): 2 # Verify two todos exist 3 self.assertEqual(Todo.objects.count(), 2) 4 5 # Verify associations 6 todo1 = Todo.objects.get(task='Todo for user1') 7 self.assertEqual(todo1.user, self.user1) 8 self.assertEqual(todo1.group, self.group1) 9 10 todo2 = Todo.objects.get(task='Todo for user2') 11 self.assertEqual(todo2.user, self.user2) 12 self.assertEqual(todo2.group, self.group2)
  • In the test_todo_creation method, the existence and associations of Todo items are validated.
  • The test checks that the correct user and group are linked to each Todo. This ensures that the foreign key relationships are correctly established and maintained.
Summary and Preparation for Practice

In this lesson, you have learned how to incorporate user references into your models using Django’s User model, enhancing the application’s capacity to manage user-specific data. By reinforcing this understanding with tests, you ensure the reliability of these associations.

As we proceed, get ready to apply these concepts in practical exercises where you will implement user references and test their functionality. Embrace this journey, as it marks your first step toward building a robust, user-focused application architecture.

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.