티스토리 뷰

반응형

🚀  들어가며...

  • Django ORM의 CRUD(Create, Read, Update, Delete)는 어떻게 사용해야 하는지 SQL문과 비교하여 정리해보았습니다.

 

📑 내용

실제 쿼리문 날리기


from django.db import connection

cursor = connection.cursor()
cursor.execute("select relname from pg_class where relkind='r' and relname !~ '^(pg_|sql_)';")
print(cursor.fetchall())

execute() 괄호 안에 실제 쿼리문을 스트링 타입으로 작성하여 넣으면 실행됩니다.

 

multiple databases


get object 
>> >  # This will run on the 'default' database.
>> > Author.objects.all()

>> >  # So will this.
>> > Author.objects.using('default').all()

>> >  # This will run on the 'other' database.
>> > Author.objects.using('other').all()

database를 여러개 사용할 때, 오브젝트에 접근하는 방법입니다.

using('__da key__') 안에 사용되는 값은 settings.py의 database를 작성해줄 때 사용한 key값 입니다.

 
save object 
>>> my_object.save(using='legacy_users')

저장 및 업데이트 시 사용되는 save 함수에도 using을 사용하여 데이터베이스에 접근할 수 있습니다.

 

1. SELECT


1_1. SELECT ...

  • in SQL
SELECT * from table_name
 
  • in Django
# import models.py
# sunrise프로젝트에 있는 models.py에서 Member라는 클래스를 임포트 함.
from sunrise.models import Member

# 모든 데이터 가져오기. json형식으로 받아진다.
m = Member.objects.all()
 

1_2. SELECT .... WHERE

  • models.py

다음과 같은 models.py가 있다고 가정해봅시다.

from django.db import models


class Publisher(models.Model):
    name = models.CharField(max_length=30)
    address = models.CharField(max_length=50)
    city = models.CharField(max_length=60)
    state_province = models.CharField(max_length=30)
    country = models.CharField(max_length=50)
    website = models.URLField()

    def __unicode__(self):
        return self.name


class Author(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=40)
    email = models.EmailField()

    def __unicode__(self):
        return u'%s %s' % (self.first_name, self.last_name)


class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField(Author)
    publisher = models.ForeignKey(Publisher)
    publication_date = models.DateField()

    def __unicode__(self):
        return self.title 
 
  • in SQL

SQL에서는 select로 값을 가져올 때, where로 조건문을 줘서 해당하는 값만 조회하는게 가능합니다.

SELECT * from table_name WHERE 조건
 
  • in Django

database로 부터 모든것을 선택(select)하는 경우는 매우 드문 일입니다. 대부분 data의 일부를 다루길 원할 것입니다. django에서 filter() method를 이용하여 data를 필터할 수 있습니다.

1. filter()는 SQL의 WHERE clause에 해당된다. 위의 예는 아래와 같이 번역될 수 있습니다.

>>>Publisher.objects.filter(name='Apress')
[<Publisher: Apress>]​
SELECT id, name, address, city, state_province, country, website 
FROM books_publisher 
WHERE name = 'Apress';

2. filter()에 전달된 여러개의 argument는 SQL의 AND clause로 번역됩니다. 이는 다음과 같습니다.

>>> Publisher.objects.filter(country="U.S.A.", state_province="CA")
[<Publisher: Apress>]
SELECT id, name, address, city, state_province, country, website 
FROM books_publisher 
WHERE country = 'U.S.A.' 
AND state_province = 'CA';

3. values() 추가

위의 filter()함수를 사용할 경우 WHERE과 같은 행위를 하지만 결과값이 [<Publisher: Apress>]와 같은 오브젝트 값으로 넘어옵니다.

memberData = Member.objects.filter(id='hyuna').values()
print(memberData)
결과값 : [{'name': '이현아', 'password': '1234', 'no': 1, 'id': 'hyuna'}]     

Member 오브젝트에서 id가 'hyuna'인 것의 .values()를 가져옵니다.

-> list로 된 제이슨 포맷의 결과값을 얻을 수 있습니다.

 

🤚잠깐!!! 여기서 filter vs exclude 차이를 간단히 설명하겠습니다.

 

Exclude

Posts.objects.exclude(date__month=3)
 
조건에 속하지 않은 값을 조회합니다. (IS NOT, NOT IN)

 

Filter

Posts.objects.filter(date__month__in=[1,2,4,5,6,7,8,9,10,11,12])
 
조건에 속하는 값을 조회합니다. (IS, IN)

 

1_3. auth_user 에서 id 가져오기

from django.contrib.auth.models import User

User.objects.get(username=the_username).pk
 

1_4. LIMIT

For example, this returns the first 5 objects (LIMIT 5):
 
>>> Entry.objects.all()[:5]
SELECT LIMIT 예시
// SELECT resource_no FROM t_service_db_resource WHERE used_key=null LIMIT 1
resource_obj = ServiceDbResource.objects.filter(used_key=None).values_list('resource_no', flat=True)[:1]
 

2. INSERT


2_1. INSERT

  • in sql
INSERT INTO Author values ('hyuna', 'lee', 'dlgusdk419@duzon.com');
 
  • in Django
from models import Author
a = Author(first_name='hyuna', last_name-'lee', email='dlgusdk419@duzon.com')
a.save()
 

2_2. INSERT with Foreign key

Django에서 foreign key를 가진 테이블에 값을 넣을 때 foreign key는 위와 같은 방식으로 하는것이 아니라 _id라는 값에 추가로 넣어줘야 합니다.

위의 모델 예제에서 Book을 보면 publisher가 foreignkey 입니다. 그러면 title, authors, publication_date는 위와 같은 방식으로 insert하고 publisher는 _id에 추가로 넣어줍니다.

from models import Book
b = Book(title='title_name', authors='authors_name', publication_date='date')
b.publisher_id = 4  #publisher 테이블의 id
b.save()   
 

 아래와 같은 방법도 있다고 하니 참고하시길.

employee = Employee.objects.create(first_name='first', last_name='last', type_id=4)
 

 

3. DELETE


3_1. DELETE

Entry model(entry table)에서 blog=b인 row를 찾아서, delete 합니다.

Entry.objects.filter(blog=b).delete()
 

 

4. UPDATE


4_1. UPDATE

Entry model(entry table)에서 pub_date__year = 2010인 row를 찾아서, comments_on에 False를 headline에 This is old를 update 합니다.

Entry.objects.filter(pub_date__year=2010).update(comments_on=False, headline='This is old')
 

4_2. with LIMIT

LIMIT으로 가져온 오브젝트를 업데이트시키는 방법 및 예시입니다.

~~.filter(컬럼명__in=list(select한 오브젝트)).update(업데이트할 컬럼=값)

// SELECT resource_no FROM t_service_db_resource WHERE used_key=null LIMIT 1
resource_obj = ServiceDbResource.objects.filter(used_key=None).values_list('resource_no', flat=True)[:1]

// UPDATE t_service_db_resource SET used_key=company_no WHERE resource_no in (1)
ServiceDbResource.objects.filter(resource_no__in=list(resource_obj)).update(used_key=company_no)
 

5. Between A and B


__range 이용
# SELECT ... WHERE pub_date BETWEEN '2005-01-01' and '2005-03-31';
import datetime

start_date = datetime.date(2005, 1, 1)
end_date = datetime.date(2005, 3, 31)
Entry.objects.filter(pub_date__range=(start_date, end_date))
 
__lte, __gte 이용
# SELECT * FROM appname_dataset WHERE i_begin_int <= 170 AND i_end_int >= 170

Dataset.objects.filter(i_begin_int__lte=170, i_end_int__gte=170)
 

 

6. values and values_list


6_1. values()

object의 원하는 컬럼만 가져오기 위해서는 values를 사용할 수 있습니다. values를 사용하면 해당 컬럼의 key, value의 쌍의 리스트를 얻을 수 있습니다.

>>> Entry.objects.values()
[{'blog_id': 1, 'headline': 'First Entry', ...}, ...]

>>> Entry.objects.values('blog')
[{'blog': 1}, ...]

>>> Entry.objects.values('blog_id')
[{'blog_id': 1}, ...]
 

6_2. values_list()

values_list()를 사용하면 key,value 형태가 아닌 tuples 형태의 리스트로 가져올 수 있습니다.

>>> Entry.objects.values_list('id', 'headline')
[(1, 'First entry'), ...]
 

6_3. flat

flat을 사용하면 tuples 형태가 아닌 값의 리스트의 형태로 가져올 수 있습니다.

>>> Entry.objects.values_list('id').order_by('id')
[(1,), (2,), (3,), ...]

>>> Entry.objects.values_list('id', flat=True).order_by('id')
[1, 2, 3, ...]
 

 

7. transaction


from django.db import transaction

@transaction.atomic
def viewfunc(request):
    # This code executes inside a transaction.
    do_stuff()
 

 

8. auth_user 


8_1. 비밀번호 비교

>>> from django.contrib.auth.models import User

>>> my_user = User.objects.create_user('ea87', 'ea@gmail.com', '666monkeysAndDogs777')

>>> my_user.save()
>>> my_user.password
'pbkdf2_sha256$20000$L7uq6goI1HIl$RYqywMgPywhhku/YqIxWKbpxODBeczfLm5zthHjNSSk='
>>> my_user.username
'ea87'

>>> from django.contrib.auth import authenticate

>>> authenticate(username='ea87', password='666monkeysAndDogs777')
<User: ea87>

>>> print(authenticate(username='ea87', password='wrong password'))
None

>>> from django.contrib.auth.hashers import check_password

>>> check_password('666monkeysAndDogs777', my_user.password)
True

>>> exit()
 

 

🙋🏻‍♂️ 후기

여러가지 예시를 통해 Django ORM에 익숙해져보는 시간이었습니다. 사용해보니 뚜렷한 장점도 보였고, 역시 500줄이 넘어가는 굉장히 복잡한 쿼리에서는 기존 SQL문을 ORM 으로 바꾸는데에만 수시간이 걸릴것 같다는 단점도 보였습니다.

개인 프로젝트에서는 Django ORM을 이용하여 간단한 웹사이트를 만들 예정입니다. 확실히 ORM이 객체로 접근하니 사용하기 편한점이 좋은것 같습니다.

 

반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함