본문 바로가기
Programming/Django

[Python Django] The Practical Guide - Data & Models

by Mandy's 2025. 7. 22.

재시작 될 때 마다 모든 데이터가 날아간다. 

data query functionality가 없다. 현실적이지 않다. 

영원히 저장되는 데이터가 필요하다 ! database

- What is "Data" and a "Database" ?

- Exploring SQL & Models

- Django, Models. & Database Queries

 

Different Kinds of Data

- Temporary Data: User Input, Selected Blog Post

  • Data is used immediately and lost thereafter
  • Store in Memory (Variables)

- Semi-Persistent Data: User authentication status

  • Data is stored for a longer time byt may be lost (can be re-created)
  • Store in Browser, Temporary Files

- Persistent Data: Blog Posts, Orders, ...

  • Data is stored forever and must not be lost
  • Store in a Database

 

 

Understanding Database Options

- SQL

  • Table-based
  • MySQL, PostgreSQL, SQLite

- NoSQL

  • Document-based
  • MongoDB, Cassandra

 

Understanding SQL

-> db.sqlite3

이미 내장되어 있는 파일, 없으면 만들면 됨...

  • Create table & set table schema (Only done once, when DB is initialized)
  • Insert data into table
  • Get data from tale (possible with condition)

 

 

Migration

__init__.py

instruction on how to update databases

❯ python manage.py makemigrations
Migrations for 'book_outlet':
  book_outlet/migrations/0001_initial.py
    + Create model Book

# Generated by Django 5.2.4 on 2025-07-22 03:09

from django.db import migrations, models


class Migration(migrations.Migration):

    initial = True

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='Book',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('title', models.CharField(max_length=50)),
                ('rating', models.IntegerField()),
            ],
        ),
    ]
 

-> 0001_initial.py


❯ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, book_outlet, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying book_outlet.0001_initial... OK
  Applying sessions.0001_initial... OK

Q. Migration이란?

 

validators?

function that takes a value

0002_book_auth_...

# Generated by Django 5.2.4 on 2025-07-22 04:47

import django.core.validators
from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        ('book_outlet', '0001_initial'),
    ]

    operations = [
        migrations.AddField(
            model_name='book',
            name='author',
            field=models.CharField(max_length=100, null=True),
        ),
        migrations.AddField(
            model_name='book',
            name='is_bestselling',
            field=models.BooleanField(default=False),
        ),
        migrations.AlterField(
            model_name='book',
            name='rating',
            field=models.IntegerField(validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(5)]),
        ),
    ]

 

Blank vs Null

blank = True

  • When providing a calue for this model field (via a form), this field may be blank (empty)

null = True

  • When no value is received for that field, the special NULL value should be stored in the database

-> If null=False is set, you have to ensure that some default value is set in case if blank values

-> Exception: CharFields (and related types) -> The default value here is an enpty string and null=True therefore typically shoud be avoided

blank=True 입력값이 비어 있어도 됨 폼(Form) 수준 사용자로부터 입력 받지 않아도 됨 (검증 제외)
null=True DB에 NULL 저장 허용 데이터베이스 수준 값이 없으면 DB에 NULL로 저장됨

 

  • 문자열 필드는 빈 문자열 ""NULL 을 혼동할 수 있기 때문에,
  • Django 공식 문서는 일반적으로 문자열 필드에서는 null=True를 피하고 blank=True만 사용할 것을 권장합니다.

❗ 만약 null=False인데 blank=True인 경우?

  • 사용자가 입력을 안 했는데 DB에 저장할 수 없음 → 에러 발생
  • 이럴 땐 default 값을 꼭 지정해줘야 함

 

 

Updating Data

 

harry_potter = Book.objects.all()[0]

In [9]: harry_potter.title
Out[9]: "Harry Potter 1 - The Philosopher's Stone"

In [10]: lotr = Book.objects.all()[1]

In [11]: lotr.title
Out[11]: 'Lord of the Rings'
harry_potter.author = "J.K. Rowling"

In [13]: harry_potter.is_bestselling = True

In [14]: harry_potter.save()

Book.objects.all()[0].author
Out[17]: 'J.K. Rowling'
lotr.author = "J.R.R Tolkien"

In [19]: lotr.is_bestselling = True

In [20]: lotr.save()

In [21]: Book.objects.all()[1].author
Out[21]: 'J.R.R Tolkien'

In [22]: Book.objects.all()[1].is_bestselling
Out[22]: True

 

Deleting Data
In [23]: harry_potter = Book.objects.all()[0]

In [24]: harry_potter.delete()
Out[24]: (1, {'book_outlet.Book': 1})

In [25]: Book.objects.all()
Out[25]: <QuerySet [<Book: Lord of the Rings (4)>]>

 

Create Instead of Save
In [26]: Book.objects.create(title="Harry Potter 1", rating=5, author="J.K. Rowling", is_bestselling=True)
Out[26]: <Book: Harry Potter 1 (5)>

In [27]: Book.objects.all()
Out[27]: <QuerySet [<Book: Lord of the Rings (4)>, <Book: Harry Potter 1 (5)>]>

In [28]: Book.objects.create(title="My Story", rating=2, author="Minjoo", is_bestselling=False)
Out[28]: <Book: My Story (2)>

In [29]: Book.objects.create(title="Some random book", rating=1, author="Random Dude", is_bestselling=False)
Out[29]: <Book: Some random book (1)>

In [30]: Book.objects.all()
Out[30]: <QuerySet [<Book: Lord of the Rings (4)>, <Book: Harry Potter 1 (5)>, <Book: My Story (2)>, <Book: Some random book (1)>]>

 

Quering & Filtering Data
In [32]: Book.objects.get(id=3)
Out[32]: <Book: Harry Potter 1 (5)>

In [33]: Book.objects.get(id=2)
Out[33]: <Book: Lord of the Rings (4)>

In [34]: Book.objects.get(id=1)
---------------------------------------------------------------------------
DoesNotExist                              Traceback (most recent call last)
Cell In[34], line 1
----> 1 Book.objects.get(id=1)

File ~/.asdf/installs/python/3.13.5t/lib/python3.13t/site-packages/django/db/models/manager.py:87, in BaseManager._get_queryset_methods.<locals>.create_method.<locals>.manager_method(self, *args, **kwargs)
     85 @wraps(method)
     86 def manager_method(self, *args, **kwargs):
---> 87     return getattr(self.get_queryset(), name)(*args, **kwargs)

File ~/.asdf/installs/python/3.13.5t/lib/python3.13t/site-packages/django/db/models/query.py:633, in QuerySet.get(self, *args, **kwargs)
    631     return clone._result_cache[0]
    632 if not num:
--> 633     raise self.model.DoesNotExist(
    634         "%s matching query does not exist." % self.model._meta.object_name
    635     )
    636 raise self.model.MultipleObjectsReturned(
    637     "get() returned more than one %s -- it returned %s!"
    638     % (
   (...)    641     )
    642 )

DoesNotExist: Book matching query does not exist.

In [35]: Book.objects.get(title="My Story")
Out[35]: <Book: My Story (2)>

In [36]: Book.objects.get(rating=5)
Out[36]: <Book: Harry Potter 1 (5)>

# 여러개가 있어도 하나만 나온다..

In [37]: Book.objects.get(is_bestselling=True)
---------------------------------------------------------------------------
MultipleObjectsReturned                   Traceback (most recent call last)
Cell In[37], line 1
----> 1 Book.objects.get(is_bestselling=True)

File ~/.asdf/installs/python/3.13.5t/lib/python3.13t/site-packages/django/db/models/manager.py:87, in BaseManager._get_queryset_methods.<locals>.create_method.<locals>.manager_method(self, *args, **kwargs)
     85 @wraps(method)
     86 def manager_method(self, *args, **kwargs):
---> 87     return getattr(self.get_queryset(), name)(*args, **kwargs)

File ~/.asdf/installs/python/3.13.5t/lib/python3.13t/site-packages/django/db/models/query.py:636, in QuerySet.get(self, *args, **kwargs)
    632 if not num:
    633     raise self.model.DoesNotExist(
    634         "%s matching query does not exist." % self.model._meta.object_name
    635     )
--> 636 raise self.model.MultipleObjectsReturned(
    637     "get() returned more than one %s -- it returned %s!"
    638     % (
    639         self.model._meta.object_name,
    640         num if not limit or num < limit else "more than %s" % (limit - 1),
    641     )
    642 )

MultipleObjectsReturned: get() returned more than one Book -- it returned 2!

# 에러 출력 ..

get()은 하나의 데이터만 출력할 때 사용한다.

In [39]: Book.objects.filter()
Out[39]: <QuerySet [<Book: Lord of the Rings (4)>, <Book: Harry Potter 1 (5)>, <Book: My Story (2)>, <Book: Some random book (1)>]>

In [40]: Book.objects.filter(is_bestselling=True)
Out[40]: <QuerySet [<Book: Lord of the Rings (4)>, <Book: Harry Potter 1 (5)>]>

filter()를 사용해서 여러 개를 출력한다.

In [41]: Book.objects.filter(rating<3)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[41], line 1
----> 1 Book.objects.filter(rating<3)

NameError: name 'rating' is not defined

In [42]: Book.objects.filter(rating__lte=3)
Out[42]: <QuerySet [<Book: My Story (2)>, <Book: Some random book (1)>]>

In [43]: Book.objects.filter(rating__lt=3)
Out[43]: <QuerySet [<Book: My Story (2)>, <Book: Some random book (1)>]>

lt ; less tham

lte; less than equal

In [44]: Book.objects.filter(rating__lt=3, title__contains="story")
Out[44]: <QuerySet [<Book: My Story (2)>]>

In [45]: Book.objects.filter(rating__lt=3, title__icontains="story")
Out[45]: <QuerySet [<Book: My Story (2)>]>

icontains 는 대소문자 구분 안함

 

"or" Conditions
In [48]: from django.db.models import Q
In [50]: Book.objects.filter(Q(rating__lt=3) | Q(is_bestselling=True))
Out[50]: <QuerySet [<Book: Lord of the Rings (4)>, <Book: Harry Potter 1 (5)>, <Book: My Story (2)>, <Book: Some random book (1)>]>

In [53]: Book.objects.filter(Q(rating__lt=3) | Q(is_bestselling=True), Q(author="J.K. Rowling"))
Out[53]: <QuerySet [<Book: Harry Potter 1 (5)>]>

In [54]: Book.objects.filter(Q(rating__lt=3) | Q(is_bestselling=True), author="J.K. Rowling")
Out[54]: <QuerySet [<Book: Harry Potter 1 (5)>]>

 

Q 로 감싸줘야 함.

마지막에 Q를 감싸주지 않아도 동작함 .. 

In [55]: Book.objects.filter(author="J.K. Rowling", Q(rating__lt=3) | Q(is_bestselling=True))
  Cell In[55], line 1
    Book.objects.filter(author="J.K. Rowling", Q(rating__lt=3) | Q(is_bestselling=True))
                                                                                       ^
SyntaxError: positional argument follows keyword argument

파이썬에서는 위치 인자(positional arguments)는 키워드 인자(keyword arguments)보다 앞에 와야 합니다.
그렇지 않으면 SyntaxError: positional argument follows keyword argument 에러가 발생합니다.

 

Query Performance

저장하지 않으면 데이터베이스는 터치 되지 않음.

In [57]: bestsellers = Book.objects.filter(is_bestselling=True)

In [58]: amazing_bestsellers = bestsellers.filter(rating__gt=4)

In [59]: print(bestsellers)
<QuerySet [<Book: Lord of the Rings (4)>, <Book: Harry Potter 1 (5)>]>

In [60]: print(amazing_bestsellers)
<QuerySet [<Book: Harry Potter 1 (5)>]>
cashing ?

하나의 데이터베이스.. 두개는 아니고 세개도 아니고..

In [63]: print(Book.objects.filter(rating__gt=3))
<QuerySet [<Book: Lord of the Rings (4)>, <Book: Harry Potter 1 (5)>]>

In [64]: good_books = Book.objects.filter(rating__gt=3)

In [65]: print(good_books)
<QuerySet [<Book: Lord of the Rings (4)>, <Book: Harry Potter 1 (5)>]>

참고자료

https://docs.djangoproject.com/en/3.1/topics/db/queries/#deleting-objects

 

Making queries | Django documentation

The web framework for perfectionists with deadlines.

docs.djangoproject.com

https://docs.djangoproject.com/en/3.0/ref/models/querysets/#bulk-update

 

QuerySet API reference | Django documentation

The web framework for perfectionists with deadlines.

docs.djangoproject.com

https://docs.djangoproject.com/en/3.0/ref/models/querysets/#bulk-create

 

QuerySet API reference | Django documentation

The web framework for perfectionists with deadlines.

docs.djangoproject.com