2010년 6월 7일 월요일

03 - 2) Insert, Update, Delete

자료의 입출력 (DML : INSERT, UPDATE, DELETE, SELECT)

 

본 절의 예는 웹에서 볼수도 있지만 작성의 편의를 위해

$ python manage.py shell

을 통해 python 입력창으로 들어가 확인하는 것으로 합니다.

위의 명령으로 python 입력창에 들어간 후 다음의 명령을 통해 위에서 작성한 model을 module을 python이 읽을 수 있도록 합니다. (Application명은 itemBank 이라 가정)

>>> from itemBank.models import Department, Student, Subject

준비가 되었으면 자료의 입출력에 대해 알아보도록 하겠습니다.

 

 

자 료구조(Table)에 자료 입력

 

django 문서등 을 보면 두가지 방법을 통해 자료를 입력할 수 있습니다.

 

첫번째로는 Class Instance 생성을 통한 자료의 입력입니다.

앞서 작성한 models.py를 보시면 각 Table은 Class의 형태로 정의되어 있으이 Class의 Instance 생성과 유사하게 저장할 수 있습니다.

단, Class의 Instance 를 생성하는 것처럼 생성할 때는 메모리 상에 저장할 데이터의 Instance가 존재하고 실제 Table에 저장되지는 않습니다.

메 모리상에만 존재하는 Instance를 실제 Table에 저장하기 위해서는 별도의 메소드인 .save()를 사용합니다.

다 음의 예를 살펴보겠습니다.

 

학과(Department)에 새로운 학과명을 입력합니다.

>>> dept1 = Department(dName = 'Statistics')

>>> dept1

<Department: Department object>

현재 dept1이라는 이름의 새로운 Instance를 생성하였습니다.

위 의 결과에서 <Department: Department object> 이 표시된 것은 django에서는 Class의 Instance 즉, object의 형태로 저장되었기 때문입니다.

여기서 Department Class의 멤버변수인 dName을 출력하기 위해서는 일반적인 . 연산자를 사용하여 다음과 같이 입력하면 됩니다.

>>> dept1.dName

 'Statistics'

하지만 위에서 말씀드린 대로 아직 table에 해당 내용이 저장된 것은 아닙니다.

그래서 이를 테이블에 저장하기 위해서는 다음과 같이 현재 instance에 대해 .save() 메소드를 적용합니다.

>>> dept1.save()

그리고 기본 상태에서는 .save() 메소드를 적용하고 나면 id 라는 django가 생성한 PK 필드에 값이 적용됩니다.

다음을 dept1.save()를 적용하기 전과 적용한 후에 각각 입력해 보면 save() 를 한 후에 값이 생성되는 것을 알 수 있습니다.

>>> dept1.id

 

자료를 입력하는 두번째 방법으로는 objects.create() 메소를 사용하는 방법입니다.

이 방법은 .save() 메소드가 필요없이 바로 테이블에 저장이 됩니다.

 

>>> dept2 = Department.objects.create(dName='Computer Science')

>>> dept2.id

2

 

.id를 입력해 보시면 알시겠지만 바로 자료가 저장됩니다.

objects.create() 메소드가 더 편하게 여겨집니다만...

본 페이지에서는 조금 불편하더라도 절차에 대해 조금 더 생각하게 해주는 .save() 를 이용하여 자료를 저장하도록 하겠습니다.

 

 

다 음은 Foreign Key가 적용된 자료의 입력입니다.

저장 방법은 앞선 두가지중에 편한대로 하셔도 됩니다.

그 럼 위에서 만든 Student Table에 자료를 입력하는 예를 보시겠습니다.

 

>>> st1 = Student(sID='20100101', sName='Dooly', sDept=dept1)

>>> st1.save()

 

앞서 dept1에 학과명이 'Statictics'인 학과를 생성하였습니다.

Student table 에서는 sDept가 외부 테이블의 PK 혹은 Unique 를 참조하는 Foreign Key로 지정하였으며 참조의 대상이 Department Table입니다.

위의 예는 sID가 20100101, sName이 Dooly 인 학생의 학과를 dept1이 저장하고 있는 학과로 저장하라는 것입니다.

여러분들이 생각하시기에 Foreign Key가 조금 어려울 수 있으나 자료들 간의 구조를 생각해 보시면 그리 어렵지 않습니다.

Foreign Key가 있어서 오히려 직접 Statictics라고 입력하는 것보다 더 정확하게 입력될 수 있습니다.

 

마지막으로 ManyToManyField(MTM field) 자료의 입력입니다.

MTM 자료는 각 Table 간의 연결(DB 모델링에서는 관계라는 용어를 사용합니다)에서 서로 대응되는 수를 말합니다.

위의 예에서 한 학생은 여러과목을 수강할 수 있고, 한  과목은 여러학생에 의해 선택되어 질 수 있으므로 MTM 연결이 됩니다.

DB 모델링에서는 MTM이 성능에 지대한 영향을 미치므로 MTM table 구조를 1:M, N:1 으로 분해하여 다시  작성하는데 django에서는 ManyToManyField로 적용하면 MTM 구조를 분해하여 줍니다.

여기서 $ python manage.py sql myPilot에서 나온 결과를 잠시 살펴보도록 하겠습니다.

  1.  

  2. CREATE TABLE "itemBank_department" (
    ...
    )
    ;
    CREATE TABLE "itemBank_subject_sStudent" (
       "id" integer NOT NULL PRIMARY KEY,
       "subject_id" integer NOT NULL,
       "student_id" integer NOT NULL REFERENCES "myPilot_student" ("id"),
       UNIQUE ("subject_id", "student_id")
    )
    ;

    CREATE TABLE "myPilot_subject" (
    ...

  3.  

 

우 리가 작성한 models.py 에는 subject_sStudent 는 없습니다.

하지만 실제 DB에 작성한 SQL 문을 보면 위와 같은 Table을 만들고 있음을 볼 수 있습니다.

위의 Table은 models.py의

 

class Subject(models.Model):

sName = models.CharField(max_length=50)

sStudent = models.ManyToManyField(Student)

 

에 의해 django 가 자동으로 생성한 Table입니다.

이 Table은 Student Table 과  Subject Table 사이에서 둘 사이를 연결해 주어 두 Table간의 MTM 연결을 해제하고 이 Table과 Subject가 n:1, 이 Table과 Student가 M:1로 연결되는 다리 역할을 합니다.

위의 SQL 문을 보시면 새로 생성된 subject_sStudent Table은 두 개의 FK를 가지고 있으며 각각 Subject Table과 Student Table을 참조하고 있음을 알 수 있습니다.

 

그럼 MTM Field에 자료를 입력하는 방법에 대해 알아보겠습니다.

입력방법은 위의 ForeignKey Field와 약간 다르게 .add() 메소드를 사용합니다.

위 의 예에서 st1에 학생 정보가 있고, Subject에 MTM Field가 존재하는 것을 확인하시고 다음 예를 보도록 하겠습니다.

 

먼저 학생 st1이 있습니다.

이 학생은 과목 Introduction to Statistics를 듣고 싶어 합니다.

그렇다면 학생과 과목이 모두 존재하여야 겠죠?

그래서 먼저 Subject에 저장될 자료 하나를 MTM Field로 저장된 sStudent는 제외하고 생성합니다.

 

>>> subj1 = Subject(sName='Introduction to Statistics')
>>> subj1.save()

 

 그 다음 학생의 존재를 확인합니다.(위에서 만들었으니 당연히 있겠....)

>>> st1

<Student: Student object>

 

그 다음 학생 st1이 위의 과목을 수강한다고 하면 다음과 같이 입력합니다.

 

>>> subj1.sStudent.add(st1)

 

이제 학생 st1은 과목 subj1을 수강하게 되었습니다.

그리고, 이 과정은 MTM Field에 새로운 값을 입력하는 과정이 됩니다.

 

일 반적으로 DB에서는 위와 같이 MTM을 해제하고 django에서 생성한 새로운 Table과 같이 새로운 Table을 생성하여 직접 해당 Table에 입력합니다만 django에서는 위와 같은 절차를 통해 자료를 입력합니다.

여기서 기억할 것은 여러분들이 MTM Field는 이렇게 자료를 저장하는 것이야 하고 외우는 것 보다 절차를 생각하여 보게 되면 더 쉽다는 점입니다.

제 가 제목으로는 MTM Field에 저장하기하고 하였지만 실제 예에서는 상황을 들어 설명한 것 같이 MTM Field는 이렇게 보다 상황을 먼저 이해해 주시기 바랍니다.

 

자료의 수정

 

입력한 자료의 수정에 앞서 간단한 SELECT 기능에 대해 알아보겠습니다.

SELECT 기능에 대한 자세한 설명은 다음에 설명을 드리겠고 간략히 전체 혹은 일부를 가져오는 방법은 다음과 같습니다.

 

먼 저 저장된 Table의 모든 자료를 가져오는 방법으로 objects.all() 메소드를 사용합니다.

 

(models.py 에서 설정한)Class명(실제 저장은 DB의 Table명).objects.all()

 

우 리의 예에 Department Table의 모든 자료를 가져오라는 명령을 적용해 보면

>>> Department.objects.all()

[<Department: Department object>, <Department: Department object>]

 

.objects.get() 메 소드를 다음과 같이 적용하여 특정자료를 가져올 수 있습니다.

 

(models.py에서 설정한)Class 명(실제 저장은 DB의 Table명).objects.get(가져올 조건)

 

이때 주의할 것이 있는데 django에서는 Table로 부터 가져오는 자료에 대해 QuerySet과 Single Object 두가지를 지원합니다.

위에서 사용한 all() 메소드의 경우 결과를 QuerySet으로 가져오지만 지금 설명드리는 get()메소드는 Sinigle Object로 결과를 가져옵니다.

Single Object로 가져온다는 것은 한 개의 Record 만을 가져올 수 있으며 복수개의 Record를 가져올 경우 MultipleObjectsReturned 예외를 발생시킨다는 것을 의미합니다.

 

예를 들어 보겠습니다.

>>> Department.objects.get(dName='Statistics')

<Department: Department object>

 

위의 예는 Department Table에 저장된 자료중 dName이 'Statistics'인  Record 한개를 가져오라는 의미입니다.

get() 메소드는 한개의 Record 만을 가져오므로 검색의 조건으로 사용될 열은 PK 혹은 UNIQUE 인것이 안전할 것입니다.

 

이 제 UPDATE 하는 방법에 대해 알아보겠습니다.

 

 

기존 자료 한 개의 변경 - UPDATE

 

django에서는 자료의 변경에 대해 변경할 자료가 한행인지 복수행인지에 따라 구현하는 것이 조금 다릅니다.

본 페이지에서는 먼저 한 행의 자료를 변경하는 것에 대해 알아보고 복수개의 행에 대한 변경은 추후에 알아보도록 하겠습니다.

 

위의 dName 이 Statistics인 학과명이 'Infomation and Statistics'로 변경되었다고 해 봅시다.

그렇다면 dName이 Statistics인 학과를 선택하여야 겠지요?

다음과 같이 입력합니다.

>>> mDept = Department.objects.get(dName='Statistics')

>>> mDept.id
1
>>> mDept.dName
u'Statistics'

 

django에서의 UPDATE는 자료를 저장하는 것과 유사하게 save() 메소드를 이용합니다.

save() 메소드는 해당 Object가 기존 Table에 존재하지 않으면 INSERT 기능을 수행하고 해당 Object가 기존 Table에 존재할 경우 UPDATE 기능을 수행합니다.

save() 메소드를 사용하기 전에 Object의 dName 값을 다음과 같이 변경합니다.

>>> mDept.dName = 'Infomation and Statistics'

 

mDept는 Department Table의 모든 열을 가지고 있고 또한 django 에서 id 열을 생성하여 PK로 지정하였으므로 변경할 자료를 제외하고는 Table내의 다른 자료와 id 값이 같지 않습니다.

이런 경우에 mDept 값을 save() 메소드를 이용하여 저장하면 UPDATE가 이뤄집니다.

>>> mDept.save()

>>> mDept = Department.objects.get(dName='Infomation and Statistics')
>>> mDept.id
1

 

위의 결과를 보시면 아시겠지만 PK 열인 id 값이 1인 기존 학과명이 Statistics인 자료를 성공적으로  학과명이 Infomation and Statistics로 변경하였습니다.

django 에서의 UPDATE 처리 순서를 요약하면 다음과 같습니다.

  1. 변경할 Record를 가져와 Object로 저장한다.(Department.objects.get(dName='Statistics'), 해당 Object의 속성과 속성값으로 Table의 열이름과 해당값을 가지게 됩니다.)
  2. 변경 대상이 되는 열에 변경할 값을 저장합니다.(mDept.dName = 'Infomation and Statistics' : Object.변경할 열이름 = 변경할 값)
  3. 변경된 Object를 .save() 메소드를 이용하여 저장합니다.(mDept.save())

 

이 상으로 단일 행의 UPDATE에 대해 알아보았습니다.

복수개의 행의 UPDATE에 대해서는 SELECT 기능 설명 중간에 다시 하도록 하겠습니다.

 

 

기존 자료의 삭제 - DELETE

 

django 에서의 DELETE는 UPDATE와 유사하게 이뤄집니다만 단일 행이나 복수 행이나 똑같이 delete()메소드를 사용합니다.

예 를 통해 .delete() 메소드의 사용에 대해 알아보겠습니다.

 

먼저 다음과 같이 학생 2명을 새로 추가합니다.

 

>>> dept1 = Department.objects.get(id=1)

>>> st2 =  Student(sID='20100102', sName='Donor', sDept=dept1)

>>> st2.save()

>>> st3 =  Student(sID='20100103', sName='Ddochi', sDept=dept1)

>>> st3.save()

>>> Student.objects.all()

[<Student: Student object>, <Student: Student object>, <Student: Student object>]

 

 

이 중 마지막에 입력한 sID='20100103' 인 학생을 삭제하도록 하겠습니다.

단일 행 UPDATE 와 유사하게 먼저 삭제할 행을 Object에 저장합니다.

>>> delst3 = Student.objects.get(sID='20100103')

 

delst2에 삭제할 학생 정보가 저장되어 있습니다.

이제 이 정보를 참조하여 삭제하는 명령을 입력합니다. 이 부분은 UPDATE와 조금 다릅니다. 예를 잘 보시면 Object명.delete()를 바로 사용하여 삭제합니다.

>>> delst3.delete()

>>> Student.objects.all()

[<Student: Student object>, <Student: Student object>]

 

복수개의 행을 삭제할 경우 다음과 같이 복수개의 행을 선택한 후(결과값이 QuerySet으로 반환되는 SELECT 처리) 뒤에 .delete()를 붙히기만 합니다.

예 에서는 모든 자료를 삭제하는 예입니다.

>>> Student.objects.all().delete()

>>> Student.objects.all()
[]

이상으로 간략하게 django에서의 UPDATE와 DELETE 처리에 대해 알아보았습니다.

본 페이지 도중 심심치 않게 QuerySet이 등장하였는데 이제 SELECT를 통해 본격적으로 QuerySet을 만들도록 하겠습니다.

 

 

이 글은 스프링노트에서 작성되었습니다.

댓글 없음:

댓글 쓰기