TIL - 0208

[0208 일지]

  • 지난시간에 작성했던 Melon 모델 작성
  • Django document - Meta option 부터 시작

null과 빈 문자열

  • CharField 되도록 null 설정은 피하자 -> blank = True 설정
  • 닉네임과 같이 중복되는 데이터가 있으면 안되는 경우, unique = True, blank = True 설정하면 안된다.
    왜냐하면 빈문자열도 unique로 인식하기 때문에 문제가 된다. -> 이럴땐 null = True로 설정해서, null값이 들어가게 설정!

many to many 삭제

  • ForeignKey처럼 CASCADE 이런 설정이 없음.
  • many to many 의 경우, 속성을 삭제하면 관련된 요소가 함께 삭제된다.
  • 하나가 삭제되면 관계에 있어서 별 의미가 없음

Model attributes

objects

  • 장고는 디폴드로 objects 라는 Manager 객체를 자동으로 추가한다.
  • Manager 을 통해 쿼리작업을 진행 할 수 있다.
  • 클래스에서만 접근이 가능하다!
  • 주요 메소드 참고자료
    • all() :테이블 데이터 전부 가져온다
    • get() :하나의 row만 가져온다
    • filter(): 특정 조건에 맞는 row를 가져온다
    • distinct(): 중복된 값은 하라노만 표시하기 위해서 사용. SQL SELECT DISTINCT와 같은 효과
    • frist()/last(): 데이터의 첫번째 row 출력 / 마지막 row 출력

Overridden model methods on bluck operations

  • 많은 데이터를 한번에 create / update / dleate 실행시키면, 사용자가 재정의한 함수는 동작하지 않는다. 왜냐하면 데이터베이스 차원에서 데이터를 처리하기 따로 재정의한 동작은 일어나지 않는다.
  • 사용자 정의 함수의 경우, pre_delete / post_delete delete동작에는 시그널 쓰는거 권장.

추상 기본 클래스

from django.db import models

# Create your models here.
class CommonInfo(models.Model):
    name = models.CharField(max_length=100)
    age = models.PositiveIntegerField()

    class Meta:
        abstract = True

class Student(CommonInfo):
    home_group = models.CharField(max_length=5)
  • abstract = True 설정
    모델 클래스로 존재는 하지만, 테이블로는 존재하지 않는다.
    자식이 이것을 상속해서 사용

  • 이 경우, CommonInfo는 추상클래스이기 때문에, 인스턴스 생성이 불가능하다. 그러나 CommonInfo를 상속받은 Student를 이용하면 된다.

  • 부모의 Meta 클래스도 상속 받을 수 있다. 또한 abstract 의 속성은 상속에 포함되어 있지 않기 때문에, 하위 클래스에서 상속이 필요하면 다시 Meta클래스에 지정해줘야 한다.

  • 상위 Meta 클래스에 db_table(테이블 이름 설정)을 넣지 말것. 하위 클래스의 모든 이름들이 동일한 오류가 생길 수 있다.

ForeignKey 혹은 ManyToMany 관계의 경우, 역참조를 사용할 때 related_namerelated_query_name 을 지정해줘야 한다.
상속 클래스에서 자주 발생되는 문제로, 같은 상위 클래스를 상속 받는 경우 오류가 생긴다.

from django.db import models

# Create your models here.
class Person(models.Model):
    name = models.CharField(max_length=50)

    def __str__(self):
        return self.name

class Item(models.Model):
    person = models.ForeignKey(
        Person,
        on_delete=models.CASCADE,
        # 같은 이름을 설정해놓은 상황
        related_name='items',
        related_query_name='item',
        )

    class Meta:
        abstract = True

class Fruit(Item):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name

class Food(Item):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name


<!--오류 내용  -->
$django git:(master*)./manage.py makemigrations

SystemCheckError: System check identified some issues:

ERRORS:
rel.Food.person: (fields.E304) Reverse accessor for 'Food.person' clashes with reverse accessor for 'Fruit.person'.
        HINT: Add or change a related_name argument to the definition for 'Food.person' or 'Fruit.person'.
rel.Fruit.person: (fields.E304) Reverse accessor for 'Fruit.person' clashes with reverse accessor for 'Food.person'.
        HINT: Add or change a related_name argument to the definition for 'Fruit.person' or 'Food.person'.


class Item(models.Model):
    person = models.ForeignKey(
        Person,
        on_delete=models.CASCADE,
        # case1
        # 이 경우, 오류는 나지 않지만 query_name을 역참조 했을 경우,
        # 상속을 가장 최근에 받는 클래스하고만 연결 (Food class만 인식)
        # related_name='%(app_label)s_%(class)ss',
        # related_query_name='item',

        # 올바른 표기법
          related_name = '%(app_label)s_%(class)ss'
          related_query_name = '%(app_label)s_%(class)s'
        )

  • %(app_label)s : 각 앱의 이름은 중복이 없어야 하며, 앱 내의 모델 클래스 이름도 중복이 없어야, 이름이 결과적으로 달라진다.
  • %(class)s : 사용되는 하위 클래스의 이름(ex- rel_food__name__)

오류

상대 경로로 저장하기

from foreign.models import car

# 상대 경로로 지정하기!! 이동할때 오류가 안생김
from .models import car