FrameWork/Django

App Models

mansoorrr 2024. 7. 12. 09:12

Application(app)의 models.py에 작성한다. app에서 관리할 데이터를 정의하는 곳으로 database와 소통한다.

결국 데이터베이스에서 사용할 table을 만드는 곳이다. 쿼리문을 적을필요 없이 클래스로 만들면 db의 테이블로 만들어진다. 필드명, 필드타입, 유니크, nullable 등을 세팅한다.

 

  • 모델생성(클래스) > 모델적용(makemigrations > migrate) 순으로 진행

 

[model 생성]

  • app의 model.py에 들어가면 django에서 미리 임포트 해놨다(from django.db import models)
  • import한 model을 상속받아 클래스를 만듬
  • 필드타입을 디테일하게 설명할 수록  장고와 데이터베이스가 잘 소통하게 됨
  • 모델을 만들때 관행적으로 모델에 대한 설명을 적음
class House(models.Model):

    ''' 모델에 대한 설명   '''

    name = models.CharField(max_length=140) # 집의 이름
    price = models.PositiveIntegerField() # 일박 가격
    description =  models.TextField() # 집의 설명
    address = models.CharField(max_length=140) #집의 주소
번호 필드명 사용하는 이유 비고
1 CharFiled 길이가 있는 텍스트 max_length=
2 IntegerField 정수  
3 PositiveIntegerField 양수인 정수  
4 TextField 길이가 긴 텍스트  

 

 

[모델적용]

  • 모델을 만들고 저장을 한 후 db를 살펴보면 생성한 모델이 보이지 않음

  • 데이터베이스에 적용하기 위해 migration이 필요
  • cmd에 아래 명령어를 순서대로 입력
    • python manage.py makemigrations 
      • model이 수정되었음을 알림
      • makemigrations할때마다 파일이 생성됨
    • python manage.py migrate
      • db에 적용

1: makemigrations / 2: migrate / 3: migrate 적용된 db모습

 

 

[**상속과 커스텀**]

  • 모델은 상속받아서 만들수도 있고 커스텀 할수도 있다.
  • 만약 Django의 기본 모델을 상속받아서 커스텀 하고 싶다면 기본모델은 건들면 안됨
  • 대신 필드를 덮어쓰는 방식으로 커스텀을 진행한다.
  • 예시: Django에서 기본적으로 제공하는 AbstractUser를 상속받은 User라는 모델이 있다. User모델을 다음과 같이 커스텀 하고자 한다.
    • first_name, last_name 필드는 사용하지 않으려고 한다.
    • name(이름)이라는 필드를 새로 만들고자 한다.
    • is_host(호스트여부)라는 필드를 새로 만들고자 한다.
class AbstractUser(AbstractBaseUser, PermissionsMixin):
    username_validator = UnicodeUsernameValidator(...)
    username = models.CharField(...)
    first_name = models.CharField(_("first name"), max_length=150, blank=True)
    last_name = models.CharField(_("last name"), max_length=150, blank=True)
    email = models.EmailField(_("email address"), blank=True)
    is_staff = models.BooleanField(...)
    is_active = models.BooleanField(...)
    date_joined = models.DateTimeField(_("date joined"), default=timezone.now)
    objects = UserManager(...)
    EMAIL_FIELD = "email"
    USERNAME_FIELD = "username"
    REQUIRED_FIELDS = ["email"]
    
 
 class User(AbstratUser):
  	#사용안함으로 커스텀(editable=False)
	first_name = models.CharField(max_length=150, editable=False)
	last_name = models.CharField(max_length=150, editable=False)
    
    #새롭게 사용할 필드
	name = models.CharField(max_length=150, default="")
	is_host = models.BooleanField(default=False)

 

  • db를 수정, 커스텀 하면 makemigrations로 마이그레이션을 생성하고 migrate로 db에 적용한다.
  • 만약 db에 데이터가 들어있는 상황인데 필드를 추가하게 되면 default를 설정해줘야 한다. default값을 설정 해주면 makemigraions > migrate가 정상 실행 됨
    • non-nullable fileld의 경우(models.BooleanField): default=True or False
    • nullable field의 경우: defualt="", 다른것들
  • 기존의 데이터는 새로운 필드가 추가된 부분에 어떤게 채워져야 할지 모르기 때문이다.

default값을 설정하지 않고 makemigrations했을때 나타나는 에

 

 

[**relationship**]

  • relationship은 RDBMS에서 테이블간 관계를 맺는 것을 의미한다.
  • 관계 형성에는 몇가지가 있다.
    • PK(Primary Key): Django에서는 테이블에 자동으로 id가 생기고 이 컬럼을  pk로 지정한다.
    • FK(Foreign Key): 다른 테이블의 무슨 컬럼을 참조할 것인지 정한다.
      • on_delete: 참조한 테이블의 데이터가 변경되거나 삭제되면 어떻게 할것인지를 정한다
        • CASCADE: 참조한 테이블의 데이터가 삭제되면 본 테이블의 데이터도 삭제한다
        • SET_NULL: 참조한 데이터가 삭제되면 본 테이블의 해당 컬럼은 NULL처리 한다
  • ForeignKey지정
# users app의 User모델을 참조(자동으로 id를 참조하게 됨)
# on_delete=CASCADE 이므로 User모델에서 특정 id가 삭제되면 House모델의 ownser_id가 id인 데이터는 함께 삭제됨

class House(models.Model):
	<생략...>
	owner_id = models.ForeignKey('users.User', on_delete=models.CASCADE)

 

  • ManyToMany
    • Foriegn Key의 경우: 
      • User 1명 --- Room 여러개
      • Room 1개 --- User 1명
    • ManyToMany의 경우
      • Room 1개 --- Amenity 여러개
      • Amenity 1개 --- Room 여러개
    • db에 새로운 테이블이 하나 생성됨
    • related_name을 이용해 거꾸로 검색 가능
# ManyToMany 연결

'''
방 1개 --- 속성 여러개
속성 1개 --- 방 여러개
=> 방여러개 ---- 속성 여러개
'''

class Room(CommonModel):
    name = models.CharField(max_length=100,)    
    owner = models.ForeignKey('users.User', on_delete=models.CASCADE,)
    amenities = models.ManyToManyField('rooms.Amenity', related_name='rooms',) #Amenity.rooms로 Amenity별 room정보를 알 수 있음(backref)

    
class Amenity(CommonModel):
    name = models.CharField(max_length=150,)
    description = models.CharField(max_length=150, null=True, blank=True,)

room_amenities라는 테이블이 생성됨(ManyToMany)

[**choices**]

  • 모델에서 필드를 설정할때 choices를 설정할 수 있다.
  • choices는 필드가 몇가지의 선택지를 가질때 설정한다
    • gender: 남자, 여자
    • language: 한국어, 영어, 일본어, 중국어
    • currency: 원, 달러, 엔
    • grade: 초등학교, 중학교, 고등학교, 대학교
  • 모델안에 클래스를 만들어 적용한다.
  • 이후 admin.py에 적용해주면 됨
class User(AbstractUser):
	
    #choice class
    class GenderChoice(models.TextChoice):
    	'''
        변수 = (db에 저장될 데이터, 관리자패널에서 보여질 데이터)
        이렇게 세팅함
        '''    
    	MALE = ('male', 'Male')
        FEMALE = ('female', 'Female')
        
    
    #새로운 필드 정의
    gender = models.CharField(max_length=10, choices=GenderChoice.choices) #choices 설정(클래스명.choices)

choice설정이 admin패널에서 이렇게 나타남

 

[**Meta**]

  • 모델의 메타정의를 만들때 사용함
  • 여러 parameter를 사용해 모델 조작 가능
    • abstract: 추상클래스로만 사용, 해당 모델을 db에는 저장하지 않음
    • verbose_name_plural: 관리자패널에서 보일 모델의 이름을 정의
class CommonModel(models.Model):
	created_at = models.DateTimeField(auto_now_add=True,) #auto_no_add: 생성된 시간만 자동입력
    modified_at = models.DateTimeField(auto_now=True,) #auto_now: 수정될때마다 수정시간 자동입력
    
    #Meta정의
    class Meta:
    	absrtract = True #추상클래스로만 사용, db에 저장안함