재시작 될 때 마다 모든 데이터가 날아간다.
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
'Programming > Django' 카테고리의 다른 글
| [Python Django] The Practical Guide - Data & Models (3) (3) | 2025.07.22 |
|---|---|
| [Python Django] The Practical Guide - Data & Models (2) (2) | 2025.07.22 |
| [Python Django - The Practical Guide] 장고로 블로그 만들기 프로젝트 (기초) (7) | 2025.07.21 |
| [Django] 2. URLs & Views 핵심 요약 (0) | 2025.07.20 |
| [Django] 1. 폴더 구조, App 생성, runserver 실행까지 (1) | 2025.07.20 |