ORM (Object Relation Mapping)은 객체-관계-맵핑의 약자로, 말 그대로 객체와 관계를 맵핑해주는 도구이다.
코드(객체)를 통해 관계형 데이터베이스를 다룰 수 있게한다.
django에서 사용할 수 있는 라이브러리인 django-extensions
를 통해 관계형 데이터베이스를 객체로 다룰 수 있다.
django shell 사용하기
pip install django-extensions
로 라이브러리 설치- 사용할 프로젝트의 settings.py > INSTALLED_APPS에 django-extensions 추가
- 이제
python manage.py shell_plus
로 django shell 진입 가능
# 모든 사용자 가져오기
User.objects. all()
>> SELECT * FROM user_auth;
# 이메일 주소로 사용자 필터링하기
User.objects. filter(username='admin' )
>> SELECT * FROM user_auth WHERE username='admin';
# 사용자 이름으로 정렬하기
>> SELECT * FROM user_auth ORDER BY username ASC;
QuerySet.__dict__
: 객체를 딕셔너리로 변환{'_state': <django.db.models.base.ModelState at 0x26df4d530a0>,
'id': 1,
'password': 'pbkdf2_sha256$600000$pLjDzijWJbFyVp6Vfi8cdq$26xMiL5jalyIUwYFNNL2J99LGgOCsWWjHvgZ7dZt2eE=',
'last_login': datetime.datetime(2023, 5, 12, 1, 48, 54, 123218, tzinfo=datetime.timezone.utc),
'is_superuser': True,
'username': 'admin',
'first_name': '',
'last_name': '',
'email': '',
'is_staff': True,
'is_active': True,
'date_joined': datetime.datetime(2023, 5, 12, 0, 53, 40, 498738, tzinfo=datetime.timezone.utc)}
# 새로운 사용자 생성하기
new_user = User.objects.create(
username= 'exampleuser' ,
password= 'examplepassword' ,
email= 'example@example.com' )
# 새로운 사용자 생성하기2
new_user = User(
username= 'exampleuser' ,
password= 'examplepassword' ,
email= 'example@example.com')
new_user.save()
생성에는 두 가지 방법이 있다.
1. create()
메서드 이용
2. 데이터 객체를 직접 만든 뒤, save()
메서드를 통해 저장
# 사용자 정보 업데이트하기
user = User.objects.get(username= 'exampleuser' )
user.email = 'newemail@example.com'
user.save()
# 사용자 삭제하기
user = User.objects.get(username= 'exampleuser' )
user.delete()
save()
, delete()
등을 통해 데이터 조작을 확정한다.create()
역시 데이터 조작을 확정하는 것이기 때문에 save()
를 하지 않아도 테이블에 데이터가 추가된다.클래스에 아무런 메서드 없이 데이터만 담아서 사용하는 것
class User:
def __init__(self, id, name, email):
self. id = id
self.name = name
self.email = email
users = [
User(id=1, name='blackdew' , email= 'blackdew7@gmail.com' ),
User(id=2, name='django' , email= 'django@naver.com' ),
User(id=3, name='python' , email= 'python@gmail.com' ),
]
User 클래스로 생성된 인스턴스는 id, name, email 값을 가지는 형식의 일종의 데이터 자료형처럼 사용할 수 있다.
데이터 구조를 명시함으로써 코드를 읽기만해도 데이터 구조를 쉽게 파악할 수 있다는 장점을 갖는다.
데이터를 다루는 함수를 클래스 안에 담아서 사용하는 것
class User:
def __init__(self, id, name, email):
self. id = id
self.name = name
self.email = email
def domain(self):
return self.email.split('@')[-1]
def filter_domain(users, domain):
return [u for u in users if u.domain() == domain]
filtered = filter_domain(users, 'gmail.com' )
for f in filtered:
print(f.name, f.email)
사용자는 데이터의 구조를 몰라도 domain() 메소드의 기능만 알고 있으면 사용할 수 있다.
캡슐화, 다형성, 상속을 이용하여 객체들을 연결 시켜 프로그래밍 하는 것
코드 재사용, 유지 보수를 감소시키는 장점이 있다.
dir()
내장 함수는 객체가 어떤 메소드를 갖고 있는지 출력한다.
class xlist(list):
def map(self, f):
s = map(f, self)
return xlist(s)
→ 이제 리스트를 선언해서 arr.map(function)을 이용하면 리스트를 반환받을 수 있다!
DB와 ORM을 통해 데이터를 주고받을 수 있도록 데이터 구조를 지정한다.
Model을 거쳐 객체화된 데이터는 view에서 파이썬 코드를 통해 다양한 처리가 가능하다.
# models.py
from django.db import models
class Post(models.Model):
title = models.CharField(max_length = 100)
content = models.TextField()
created_at = models.DateField(auto_now_add = True)
published_at = models.DateField(null = True)
django 문법에 의해 모델은 models.Model
을 상속 받아야 한다.
저장할 자료의 Field(자료형)를 선언해야한다.
공식문서 : https://docs.djangoproject.com/en/4.2/ref/models/fields/#model-field-types
커스텀 자료형을 만들어 사용할수도 있다.
이 과정을 거치친 후 migration을 만들어야 한다.
python manage.py makemigrations <app 이름>
: 지정한 앱에 migration을 추가한다.
admin.py
에 추가한 모델을 등록하면 된다.# admin.py
from django.contrib import admin
from . import models
# Register your models here.
admin.site.register(models.Post)
migrate
명령어를 통해 쉽게 돌아갈 수 있다.python manage.py migrate blog 0001
: blog앱에서 선언했던 0001버전으로 돌아간다.ForeignKey : 일대다 관계를 형성하는 관계형 필드
OneToOneField : 일대일 관계를 형성하는 관계형 필드
ManyToManyField : 다대다 관계를 형성하는 관계형 필드
연결하려는 모델을 매개변수로 입력
class Student(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
name = models.CharField(max_length=50)
year = models.IntegerField()
User와 Student는 일대일 관계이다 → 한명의 유저는 한명의 학생이다.
user.student.name
식으로 사용 가능student.course_set.all()
→ 모두 가져오기student.course_set.get(id=5)
→ 연결된 데이터중 id 컬럼값이 5인 데이터만 가져오기<테이블명>_set
으로 묶어 사용한다. → 필드가 지정되어있을 경우 필드로 사용하면 된다.shell_plus에서 사용했던 ORM 문법을 사용할 수 있다.
# views.py
def post_list(req, id):
posts = models.Post.objects.all()
post = posts.get(id=id)
return render(req,
'blog/post.html',
{
'title' : post.title,
'content': post.content
})
<!-- post.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h2>{{ title }}</h2>
<p>{{ content }}</p>
</body>
</html>
blog/post/2/
도메인으로 이동하면 해당 id의 데이터를 받아올 수 있다.# title에 This가 포함된 post 추출
Post.objects.all().filter(title__contains='This')
# title에 This가 포함된 post 제외
Post.objects.all().exclude(title__contains='This')
# 여러 조건으로 조회: 아래와 같이 여러 조건을 걸어 데이터를 조회할 수 있다.
Post.objects.filter(title__contains='this', title__endswith='title')
Post.objects.filter(title__contains='this').filter(title__endswith='title')
# or and 연산자 사용
from django.db.models import Q
Post.objects.filter(Q(title__contains='this') | Q(title__endswith='title'))
Post.objects.filter(Q(title__contains='this') & Q(title__endswith='title'))
# title에 대소문자 구분 없이 this가 포함된 post 추출
Post.objects.filter(title__icontains=’this’)
# title이 this로 시작하는/끝나는 post 추출
Post.objects.filter(title__startswith=’This’)
Post.objects.filter(title__endswith=’title’)
# id가 1, 2, 3인 post 추출
Post.objects.filter(id__in=[ 1, 2, 3])
# id가 1~9인 post 추출
Post.objects.filter(id__range=( 1,10))
# 날짜 관련
Post.objects.filter(published_at__lt=timezone.now())
Post.objects.filter(published_at__gte=timezone.now())
Post.objects.filter(created_at__year=’ 2019’)
Post.objects.filter(created_at__month=’ 5’)
Post.objects.filter(created_at__day=’ 21’)
Post.objects.filter(published_at__isnull= True)