Django models describe database tables using Python classes. This guide creates a Person model with two CharField fields, applies its migration, and verifies that records can be saved, read, updated and deleted. Define the class in your application’s models.py file; use the Django shell afterward to work with its records.

Prerequisites and a clean project

The commands below were tested with Python 3.12.15, Django 5.2.18 and SQLite in an isolated Linux container. You need Python 3.12 with pip and venv available, a terminal and internet access. Run these Bash commands as your normal user in a directory where django-models-lab does not already exist. This is a new learning project, not a command sequence to paste over an existing application.

mkdir django-models-lab
cd django-models-lab
python3 -m venv .venv
. .venv/bin/activate
python -m pip install 'Django==5.2.18'
python -m django --version
django-admin startproject config .
python manage.py startapp people

Create and register the Person model

Register the people application in INSTALLED_APPS. Then save the class in people/models.py. Each CharField has a maximum length of 50 characters. The __str__ method supplies a readable representation. The following file writes are intended for the new project just created; when using an existing project, edit its settings and models without replacing unrelated code.

cat >> config/settings.py <<'PY'

INSTALLED_APPS += ['people.apps.PeopleConfig']
PY
cat > people/models.py <<'PY'
from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)

    def __str__(self):
        return f'{self.first_name} {self.last_name}'
PY

Create and apply the database migration

makemigrations records the schema change in a migration file. migrate applies it to the SQLite database configured by startproject. showmigrations should list people.0001_initial with an [X] after it has been applied. The built-in Django applications also have migrations, so several tables will be created.

python manage.py check
python manage.py makemigrations people
python manage.py migrate
python manage.py showmigrations people

Save, read, update and delete a record

The shell imports the model from the registered application. full_clean validates the field values; save does not call full_clean automatically. Saving assigns a primary key. The example then reads that record back, updates its surname and deletes only the record it created. A successful run prints John Smith and Create, read, update and delete passed. The final migration check should report No changes detected.

python manage.py shell <<'PY'
from people.models import Person
person = Person(first_name='John', last_name='Doe')
person.full_clean()
person.save()
assert person.pk is not None
saved = Person.objects.get(pk=person.pk)
assert saved.first_name == 'John'
saved.last_name = 'Smith'
saved.full_clean()
saved.save(update_fields=['last_name'])
saved.refresh_from_db()
assert saved.last_name == 'Smith'
print(saved)
pk = saved.pk
saved.delete()
assert not Person.objects.filter(pk=pk).exists()
print('Create, read, update and delete passed')
PY
python manage.py makemigrations --check --dry-run

Troubleshooting

If the people table is missing, run the migration step from the directory containing manage.py. If the app cannot be imported, confirm the virtual environment is active and PeopleConfig is registered. After changing model fields, create and apply a new migration before relying on the new schema. Keep migration files with your application source.

Reference: Django’s model and database tutorial.