Django 핵심기능 Model

김용녀·2022년 7월 28일
0

Django 정의

Model이란 테이블을 정의하는 장고의 클래스다.

우리는 이 model을 기본적으로 models.py에 저장한다.
우리가 DB에 데이터를 저장하려면 sql문법을 사용해야한다. 하지만 장고에서는 ORM방식에 기반해 클래스로 정의해서 테이블을 구성할수있다.

테이블은 컬럼(속성)과 값으로 이루어져있다.
장고의 models.py에 클래스내에 변수를 가지는것이 테이블 내에 하나의 컬럼을 가지는것과 같다. 게다가, 장고에서는 그 테이블에 관련된 메소드들을 모델클래스에 함수로서 정의할수있다.

다음 사진을 보면 더 이해하기 쉬울것이다.

모델 속성

( 모델속성에 명시안하면 디폴트 속성으로 objects = models.Manager()을 갖는다.)

  • 모델 속성=테이블의 컬럼
  • 모델 메소드 = 테이블의 데이터들을 다루는 함수

그리고 각 속성에는 적절한 타입(ex.CharField)을 지정해줘야한다. 이때 max_length와 같은 필수 인자가 있을수있다. 이러한 타입을 Field추상클래스라 하는데, 장고에서 약 30개를 지원한다. 만약 개발자가 필요로 한다면 커스텀 필드를 작성할 수 있다.

모델 메소드

  • 테이블에는 메소드가 없지만 모델 클래스에선 메소드를 정의할수있다.

  • 모델 메소드에서 구분해야할것은 클래스 메소드와 객체 메소드이다.
    둘의 차이는 테이블레벨과 레코드 레벨에서 다룬다는것이다.

  • 장고에서는 객체 메소드만 이용한다. 이때 이 객체 메소드들은 모두 self인자를 가지며 호출시 항상 레코드 단위로 움직인다.

객체 메소드란?

__str__(self.(속성)) 
__unicode__ ()
 객체의 속성을 문자열 표현으로 return한다.
객체는 기본적으로 포맷돼있어 우리가 알아보기 어렵기때문에 이런것들을 사용한다.
get_absolute_url() 
자신이 정의된 객체를 지칭하는 url을 반환한다. 
보통 DetailView(제네릭뷰) 사용시 객체에대한 상세정보를 보여주기 위함인데, 
get_absolute_url()을 사용해 url을 구해 해당 뷰와 매핑할수있다.
또한 템플릿에서도 url을 구하는과정에서 자주 등장한다.
get_next_by_필드명(**kwargs),(+previous 버젼도있다.)
필드 기준으로 다음 객체를 반환한다. 없을경우 익셉션
get_필드_display()
choice인자를 갖는 Foo필드가 있으면 FOo필드의 설명 문자열을 반환

Meta 내부 클래스

  • 모델에 대한 메타 데이터를 정의한다.
  • 모델클래스의 필드는 아니지만 모델클래스에 필요한 항목을 Meta내부 클래스에 정의한다.
- ordering
객체의 리스트 출력시 정렬. DB저장순X DB에서 가져올때 순서O
-db_table
db에 저장되는 테이블명을 지정한다. 명시X면, 앱명_클래스명으로 테이블명을 저장한다.   
db_table = 'tb_post'
-verbose_name 
사용자가 이해하기 쉬운 모델 객체의 별칭
-verbose_name_plural
별칭에 대해 s를 붙여 복수 명칭을 지정

Manager속성

  • 모든 모델은 manager속성을 가져야한다. 이 속성은 클래스의 컬럼이랑은 별개로 독자적으로 가져야만 하는것인데, 모델클래스를 통해서만 접근가능하다.(테이블레벨)
  • 테이블 레벨에서의 동작은 Manager클래스의 메소드를 통해 이뤄진다.
  • manager속성이 명시X경우, 이름은 object로 저장된다
    EX) Album.objejcts.all(),filter(),exclude(),get(),count()
    여기서 all()은 manager클래스의 메소드다. QuerySet객체를 반환한다.
    manager속성 여러개 정의 가능하다.

모델 간 관계

  • 1:N 관계
    User : Album 은 사용자 한명이 여러 앨범을 가질수 있으므로 1:N관계다.
    이 점을 이용해서 한 사용자가 여러 앨범을 가질수있도록 해보려한다.
유저목록
>>> User.objects.all()
<QuerySet [<User: shkim>]>

앨범목록
>>> Album.objects.all()
<QuerySet [<Album: 1>, <Album: 2>, <Album: 새로운앨범이라구욧>]>
>>> a2 = Album.objects.all()[2]
>>> a2
<Album: 새로운앨범이라구욧>
앨범의 오너
>>> a2.owner
<User: shkim>

newa1 앨범 생성
>>> newa1 = Album(name='TestAlbum1')
>>> newa1
<Album: TestAlbum1>
>>> newa1.save()

u1가 newa1앨범 소유하기
>>> u1.album_set.add(newa1)
>>> u1.album_set.all()
<QuerySet [<Album: TestAlbum1>, <Album: 새로운앨범이라구욧>]>

앨범을 새로 만듬과 동시에 u2에게 소유권 지정
>>> newa2 = u2.album_set.create(name='TestAlbum2')

필터를 통해 조건부 검색 가능
>>> u2.album_set.filter(name__startswith='Test')
<QuerySet [<Album: TestAlbum1>, <Album: TestAlbum2>, <Album: TestAlbum22>]>
>>> Album.objects.filter(owner=u1,name__startswith='Test')
<QuerySet [<Album: TestAlbum1>, <Album: TestAlbum2>, <Album: TestAlbum22>]>

1:N이기때문에 User가 삭제되면 CASCADE로 Album도 삭제된다.
>>> u3 =  User.objects.create(username='guest3')
>>> u3.album_set.create(name='TestAlbum3')
<Album: TestAlbum3>
>>> u3.album_set.all()
<QuerySet [<Album: TestAlbum3>]>
>>> u3.delete()
(2, {'auth.User': 1, 'photo.Album': 1})
>>> Album.objects.all() #삭제된것을 볼수있다.
<QuerySet [<Album: 1>, <Album: 2>, <Album: TestAlbum1>, <Album: TestAlbum2>, <Album: TestAlbum22>, <Album: 새로운앨범이라구욧>]>
  • N:N 관계
    테이블관 N:N관계는 필드 정의할때 ManyToMany를 이용하면 된다. (한쪽에만 정의해야한다)
    N:N관계를 예시로 보여주기위해 Album과 Publication (출판사)를 만들었다.
각 클래스의 객체들을 만들고, publication객체에 album객체를 연결하려한다.
>>> Publication.objects.all()
<QuerySet [<Publication: Publication object (1)>, <Publication: Publication object (2)>, <Publication: Publication object (3)>]>
>>> Album.objects.all()
<QuerySet [<Album: 1>, <Album: 2>, <Album: TestAlbum1>, <Album: TestAlbum2>, <Album: TestAlbum22>, <Album: 새로운앨범이라구욧>]>
>>> a1 = Album.objects.get(name='1')
>>> p1.albums.add(a1)
>>> p1.albums.all()
<QuerySet [<Album: 1>]> #p1객체에 앨범 연결하기 성공!

반대로 a1에도 p1이 연결되어있다.
>>> a1.publication_set.all()
<QuerySet [<Publication: Publication object (1)>]>

filter뿐만 아니라 exclude도 가능
>>> Publication.objects.exclude(albums=1)
<QuerySet [<Publication: Publication object (2)>, <Publication: Publication object (3)>]>

****N:N관계에선 CASCADE 필드가 필수가 아니라서 따로 걸지 않는 이상 한쪽이 삭제된다고 
연쇄 삭제가 발생하지 않는다.****
  • 1:1 관계

1:1 관계는 OneToOneField 필드 타입을 사용하면 된다.
그리고 특이점은 Foreign키와 동일하게 on_delete 인자또한 필수다.
우선 기존 챕터에서 1:1관계를 이룰만한 테이블이 없기에
Place와 Restraunt라는 모델에 새로 생성한후 migrate했다.

r(restraunt)은 place쪽으로 access 가능. 반대방향도 가능.
>>> p1 = Place(name='TestPlcae1',address='Seoul')
>>> p1.save()
>>> p2 = Place(name = 'TestPlace2', address = 'Jeju')
>>> p2.save()
>>> r = Restraunt.objects.create(place=p1,name='TestRestraunt')
>>> r
<Restraunt: Restraunt-TestRestraunt>

서로 연결된 필드에 접근 가능.
>>> r.place
<Place: Place-TestPlcae1>
>>> p1.restraunt
<Restraunt: Restraunt-TestRestraunt>


식당의 장소를 p2로 변경. 1:1관계에선 add 사용X. 그냥 바로 대입한다.
>>> r.place = p2
>>> r.save()
>>> r.place
<Place: Place-TestPlace2>
>>> p2.restraunt
<Restraunt: Restraunt-TestRestraunt>

하지만 메모리에는 예전 내용이 남아있다.(p1과 끊겼음에도 남음..)
>>> p1.restraunt
<Restraunt: Restraunt-TestRestraunt>

- 관계 매니저

관계매니저를 사용하는 경우
- 1:N

User과 Album상황에서, 1에서 N으로 액세스 하는경우.
user1.album_set #album_set이 관계 매니저 클래스의 객체다.

N에서 1로 액세스할땐, 1개로 가니 album1.owner 해주면된다. 
owner는 ForeignKey 타입의 필드명이다.



-N:N
Album과 Publication을 예로 들면, 
album1.publication_set 접근하는 경우 **_set은 관계 매니저클래스의 객체다.
publication1.albums.   #albums는 ManyToMany타입의 필드명이면서 관계 매니저의 객체다
  • 관계 매니저 메소드
add(객체) -인자로 주어진 객체들을 관계 객체의 집합에 추가한다.즉 두 모델 객체간 관계를 맺어줌 (이후 save필요)
ex) b.entry_set.add(e) #entry e 객체를 blog b객체에 연결

create() - 인자 값을 저장하면 새로운 객체를 생성과 동시에 반환해준다. 
이후 save()호출하지 않아도 자동으로 저장된다.

remove() - 인자로 지정된 모델 객체들을 관계 객체집합에서 삭제. 즉 두 모델 객체간의 관계를 해제하는 역할을 한다.
ex) b.entry_set.remove(e) blog b 객체에서 entry e와 관계를 끊음

clear() - 관계 객체 집합에 있는 모든 객체를 삭제한다. 다른 객체들과의 관계를 모두 제거.
ex) b.entry_set.clear() 

***remove와 clear는 관계 객체 자체를 삭제하는게 아니라 관계!를 끊는거임!

set() - 메소드는 내부에서 add,remove,clear가 적절히 실행된다. 
profile
어서오세요

0개의 댓글