티스토리 뷰

반응형

모델의 정의

DB에 데이터를 저장하거나, 데이터를 불러오는 서비스 처리를 가능하게 한다.

models.py에 작업을 한다. 데이터베이스와 연동해서 작업한다.

 

장고에서는 SQL문이 나오지 않는다.

모델이라는 파이썬 객체를 통해서 직접적으로 DB와 연동해서 작업한다.

이렇게 SQL을 몰라도 메서드를 통해서도 DB를 다룰 수 있는 걸 ORM이라고 한다.

 

데이터 베이스의 환경설정

DB 환경 설정

mysite/settings.py

DATABASES 

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.sqlite3",
        "NAME": BASE_DIR / "db.sqlite3",
    }
}

만약에 sql을 쓸거면 사용하는 mysql db를 먼저 설정을 해야 한다.

 

환경 설정 할 때는 dict로 해준다.

아무것도 안했을 때는 default로 사용한다.

engine - 현재 장고하고 연결할 엔진을 선택한다.

https://github.com/django/django/tree/main/django/db/backends

 

mysql,oracle,ostgresql,sqltile

 

만약에 원하는 엔진이 없다면 다운로드해서 넣어줘야 한다.

바꾼다면 이름을 경로로 바꿔주면 된다.

 

        "ENGINE": "django.db.backends.mysql",
        "NAME": BASE_DIR / "db.sqlite3",
        "HOST" : 데이터베이스_호스트
        "USER": 데이터 베이스 유저 ID,
        "PASSWORD" : 데이터 베이스 암호
        
#환경변수를 통한 DB 설정

'ENGINE':os.erviron.get('DB_ENGINE', django.db.backends.mysql'),
'HOST' : os.environ['DB_HOST'],
'PORT' : os_environ('DB_PORT'],..

등과 같이 환경변수로 해서 넣어준다.

 

만약에 db가 없다면 기본적으로 db.sqlite3라고 하는 파일에서 불러온다.

 

이제 db browser for sqllite setup 파일을 실행한다.

 

실습파일을 다운받아서, db폴더에서

chinook.db를 mysite에 복사해서 넣는다.

 

program files > db sqllite에서 db 브라우저 for sql lite 실행

 

데이터베이스 열기를 해서, chinook.db를 실행한다.

그리고 데이터 보기를 보면, 들어가있는 데이터들을 볼 수 있다.

 

db만 있고, 연관된 모델은 없다.

그렇기에 일단 setting에서 db와 연동해준다.

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.sqlite3",
        "NAME": BASE_DIR / "chinook.db",
    }
}

 

이제 프롬프트 창을 하나 연다.

 

mysite 폴더 안에서, music이라는 앱을 만든다.

dev mysite> python manage.py startapp music
dev mysite> python manage.py inspectdb > music/models.py

그리고 inspectdb를 해서 

아래 커맨드는 반드시 커맨드창에서 해야 한다.

테이블 안에 있는 걸 토대로 model를 만드는 게 inspectdb이다.

 

vscode에서 쓰면 utf 16을 써서 장고에서 못 읽는다.

 

이제 models.py를 열어보자.

 

models.py

class Albums(models.Model):
    albumid = models.AutoField(db_column='AlbumId', primary_key=True)  # Field name made
    title = models.TextField(db_column='Title')  # Field name made lowercase. This field
    artistid = models.ForeignKey('Artists', models.DO_NOTHING, db_column='ArtistId')  # 

    class Meta:
        managed = False
        db_table = 'albums'

 

하나의 모델은 하나의 테이블을 의미한다.

모델 객체를 상속받는다.

하나의 테이블을 처리해주는 게 각 class이다.

~Field라고 되어 있으면, 인스턴스들이다.

 

 

그러면 albumid,title,artistid 각자가 3개의 컬럼이라고 생각하면 된다.

 

모델의 필드

 

class Meta는 그대로 테이블을 이름으로 하지 않으면 클래스 이름으로 들어가는데, 이름을 albums라고 해서 따로 지정해준 것이다.

managed =false라고 하면 다른 곳(DB sql) 같은 곳에서 수정을 못하게 해놓은 것이다.

 

해당 필드라는 조건은 3가지를 내포한다.

1.컬럼 조건 (컬럼의 데이터 타입은 뭐여야 하고, 조건은 뭐여야 하고 등등)

2. form 조건

3. 유효성 검사

 

모델 필드 레퍼런스를 읽어보면 된다.

https://docs.djangoproject.com/ko/4.2/ref/models/fields/#model-field-types

 

AutoFild

bigAutoField 등등 숫자와 관련된 것들.

 

Emailfield같은 건 데이터 타입이 스트링이 되고, 값의 유효성도 체크할 수 있다.(이메일인지 아닌지)

 

albumid = models.AutoField(db_column='AlbumId', primary_key=True)  # Field name made
title = models.TextField(db_column='Title')  # Field name made lowercase. This field
artistid = models.ForeignKey('Artists', models.DO_NOTHING, db_column='ArtistId')  #

 

textfield에 대해서는 null 값에 대한 허용도 할 수 있다.

각종 옵션 값들이 다 다르다. 유효키도 줄 수 있다.

관계 설정도 가능하다.

 

Manager 

models.py에는 models.Model을 상속받는데, 거기엔 다음과 같은 객체가 있다.

 

objects = models.Manager()

 

SQL 작업을 실행시켜주는 메소드가 Manager 객체이다.

생성해서 사용할 수 있다.

 

변수명 = 모델명.objects.메소드()

 

이 매니저 객체를 통해서 CRUD 작업을 하면 된다.

 

QuerySet

https://docs.djangoproject.com/en/4.2/ref/models/querysets/

 

매니저라는 객체는 크게 두 가지로 나뉜다.

쿼리셋을 리턴하는 메소드와, 리턴하지 않는 메소드로 나뉜다.

 

필터를 쓰면 쿼리셋을 리턴한다.

그러면 쿼리셋을 계산으로 다시 또 CRUD 작업이 가능하다.

쿼리셋과 매니저가 가진 객체가 동일하나, 쿼리셋은 매니저의 결과로 한 번 나와서 재활용하는 결과값이다.

 

데이터 조회

 

python manage.py shell

->manage.py를 이용해 shell을 연다.

 

from music.models import *

Customers.objects.all()

하면, Customers 테이블의 모든 데이터를 다 출력해준다.

In [1]: from music.models import *

In [2]: Customers.objects.all()
Out[2]: <QuerySet [<Customers: Customers object (1)>, <Customers: Customers object (2)>, <Customers: Customers object (3)>, <Customers: Customers object (4)>, <Customers: Customers object (5)>, <Customers: Customers object (6)>, <Customers: Customers object (7)>, <Customers: Customers object (8)>, <Customers: Customers object (9)>, <Customers: Customers object (10)>, <Customers: Customers object (11)>, <Customers: Customers object (12)>, <Customers: Customers object (13)>, <Customers: Customers object (14)>, <Customers: Customers object (15)>, <Customers: Customers object (16)>, <Customers: Customers object (17)>, <Customers: Customers object (18)>, <Customers: Customers object (19)>, <Customers: Customers object (20)>, '...(remaining elements truncated)...']>

하나하나가 Customers 인스턴스가 출력된다.

모델 인스턴스는 하나의 레코드를 의미한다.

즉, 한개의 줄이 된다.

해당 customers object 1에서는 행의 1번째 값들이 간다.

그러면 쿼리셋으로 만들려면 result라는 변수에 담는다.

result = Customers.objects.all()

 

이렇게 담은 데이터들을 정렬할 수도 있다.

result.order_by('lastname')
result.order_by(-'lastname')

이러면 해당 행을 기준으로 해서 정렬해준다.

-를 붙이면 내림차순 정렬이다.

 

조건에 맞는 데이터 추출

.all()로 모든 데이터를 받아오는 건 흔하지 않다.

조건에 맞는 데이터들을 골라온다.

 

filter(조건)

필터는 조건에 맞는 걸 가져온다.

모델명.objects.filter(조건)

 

exclude(조건)

exclude는 조건에 맞지 않는 걸 가져온다.

모델명.objects.exclude(조건)

 

select * from employees where 과 같은 것이다.

조건을 어떻게 지정할 것인가?

 

조건은 필드명_lookup 명 = 값으로 지정한다.

age > 20 => age__lookup(각 연산자마다 조건을 표시하는 연산자가 따로 있다) = 20

 

exact는 그냥 지정한 거를 가져온다.

id__exact=4 / id=4  -- SELECT..WHERE ID=4;

id__exact=None / id =None  -- SELECT WHERE id IS NULL;

region__exact='Asia' / region='Asia'

 

그러나 그냥 조건에 지정해줘도 상관 없다.

Customers.objects.filter(country='France')
Customers.objects.filter(country__exact='France')
Customers.objects.filter(country='france')
Customers.objects.filter(country__iexact='france')


In [4]: Customers.objects.filter(country='France')
Out[4]: <QuerySet [<Customers: Customers object (39)>, <Customers: Customers object (40)>, <Customers: Customers object (41)>, <Customers: Customers object (42)>, <Customers: Customers object (43)>]>

In [5]: Customers.objects.filter(country__exact='France')
Out[5]: <QuerySet [<Customers: Customers object (39)>, <Customers: Customers object (40)>, <Customers: Customers object (41)>, <Customers: Customers object (42)>, <Customers: Customers object (43)>]>

 

iexact는 비슷하지 않아도 뽑아내 준다.

 

 

>>> Customers.objects.filter(phone=None)

none도 뽑아내 준다.

 

contatins는 지정한 글자가 포함되어 있는 걸 찾아준다.

Customers.objects.filter(address__contains='Broadway')

 

in은 해당 컬럼의 값이 리스트 안에 있는 단어들에 포함되어 있는 지를 찾아준다.

Customers.objects.filter(country__in=['Italy','Spain'])

gt,gte,lt,lte는 각각 >, >=, <, <=이다.

>>> Tracks.objects.order_by('milliseconds')
>>> Tracks.objects.filter(milliseconds__gte=3000000)

milliseoconds가 >= 3000000인걸 찾는다.

 

startswith, endwith

해당 단어로 시작하거나 끝나는 걸 찾는다.

Employees.objects.filter(title__startswith='IT')
Employees.objects.filter(title__endswith='Manager')

range

해당 범위 안에 있는걸 찾는다. 여리서 range는 end의 해당 값도 포함한다.

from datetime import date
start_date = date(2002,1,1)
end_date=date(2002,6,30)
Employees.objects.filter(hiredate__range=(start_date, end_date))

end_date는 2002,6,30도 포함한다.

 

year,month,day

날짜에 관련해서도 최대 최소를 지정해서 할 수 있다.

Employees.objects.filter(hiredate__year__gt = 2003)
Employees.objects.filter(hiredate__month=5)
Employees.objects.filter(hiredate__month__gte=6)
Employees.objects.filter(hiredate__day=1)

 

조건이 여러개라면 and, or,xor 연산자로 하면 된다.

Post.objects.filter(region='Asia') & Post.objecs.filter(body__contains='발리')

혹은 그냥 인자로 지정하면 된다.

Post.objects.filter(region='Asia',body__contatins='발리') 아시아이면서 발리

 

또는 Q 메소드를 사용할 수 있다.

from django.db.models import Q
Employees.objects.filter(Q(title='IT Staff') & Q(country='Canada'))

 

 

and는 이렇게 하면 되나, or는 다르다.

or는 웬만하면 Q 메소드를 쓴다.

>>> Employees.objects.filter(Q(title='IT Staff') | Q(country='Canada'))

 

조회

get()

모델명.objects.get(조건)

primary key로 사용하는 필드에 사용한다.

 

primary key가 있는 녀석이라면 조건을 썼을 때 결과값이 하나가 나온다는 걸 전제로 한다.

반드시 하나의 인스터스가 리턴되어야 한다.

결과값이 없는 경우 DoesNotExist라는 오류가 리턴된다.

결과값이 1개보다 많은 경우 MultipleObjectsReturned 오류가 리턴된다.

Employees.objects.get(employeeid=1)
# OK

Employees.objects.get(employeeid=10)
# music.models.Employees.DoesNotExist

Employees.objects.get(country='Canada’)
# music.models.Employees.MultipleObjectsReturned

 

first() / last()

모델명.objects. first() / 모델명.objects.
QuerySet
QuerySet객체명. first() / QuerySet QuerySet객체명.

Employees.objects.order_by('birthdate').first()
Employees.objects.order_by('birthdate').last()

리턴되는 건 인스턴스다.

 

count()

Employees.objects.count()
Employees.objects.filter(title='IT Manager').count()

exists()

위의 exist와 다르게 존재하는지 안하는지를 bool 타입으로 리턴해준다.

Customers.objects.filter(country='korea').exists()
# False
반응형