[summary]
- 모델 관련 자료 진도 다감
- Melon artist form 이용해서 데이터 받는 것 연습
- 다음 시간에는 sql과 쿼리셋 진도 나감
질문
pby = Person.objects.create('박보영')
이 경우 오류로 `TypeError: create() takes 1 positional argument but 2 were given`
이런 메시지가 뜨더라구요. 저는 하나의 인자를 넘겨줬는데 왜 2개를 받았다고 하는건가요?
항상 첫번째 위치인자로 self가 넘어가기 때문 create 메서드는 create(** kwargs) 이런식으로 키워드 인자들만 받도록 되어있는데 이 앞에 create(self, ** kwargs) 이런 식으로 self 위치인자가 기본적으로 넘어가서 실제로 create 메서드에 self 라는 인자를 아무값이나 넘겨보면 여러 개의 값이 self 로 넘어왔다고 에러
django_extensions
<!-- 우분투의 경우, graphviz 외에 두개 더 설치 -->
sudo apt-get install graphviz libgraphviz-dev pkg-config
pip install pygraphviz
pip install pydot
<!-- 선택한 테이블 만 출력 -->
./manage.py graph_models multi_table -o erd.png
<!-- 전체 그룹 테이블 출력 -->
./manage.py graph_models -a -g -o erd.png
<!-- 특정 그룹 테이블 출력 -->
./manage.py graph_models -g multi_table abstract_base_classes -o erd.png
해당 파일에 가서 확인 하면, ER다이어그램을 볼 수 있다.
Multi-table inheritance
- abstract를 하는 경우, 부모 클래스가 테이블이 만들어지지 않는다. 그러나 이 모델의 경우 부모 클래스도 테이블이 생긴다.
- 다중 테이브르 상속은 one_to_one 필드를 사용하여, 하위와 상위를 연결하기 때문에, 상위에서 하위로 이동이 가능 (Place -> Restaurant)
<!-- ERD 이미지로 바꾸는 것 -->
(fc-django-document) django git:(master*)./manage.py graph_models multi_table -o erd.png
from django.db import models
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
def __str__(self):
return f'Place {self.name} | {self.address}'
class Restaurant(Place):
# one_to_one field가 되기 때문에, place에 id를 참조
# 무언가를 꺼낼때, 속도가 느리다.
# 최대 2단계만 속도가 느려지기 때문에
# 장점 : Place.name 으로 접근 할 수 있음
serves_hot_dogs = models.BooleanField(default=False)
serves_pizza = models.BooleanField(default=False)
# related_query_name이 같은 경우가 생기기 때문에, 항상 이렇게 설정
nearby_places = models.ManyToManyField(
Place,
related_query_name = 'near_restaurant'
)
def __str__(self):
return f'Restaurant {self.name} | {self.address}'
- 역참조의 경우,
소문자class명_set
이렇게 사용했는데, one_to_one 필드의 경우,소문자class명_속성
이런식으로 접근이 가능
# related_name과 related_query_name이 같다
# related_name
p2.restaurant
# related_query_name
Place.objects.filter(restaurant__address = '신사역')
Proxy models
- multi-table 상속을 하는 경우, 각각 자식 클래스들 마다 테이블이 생성된다.
그러나 부모 모델의 메소드만 재정의하던가 새로 추가하고 싶을 때
Proxy
를 사용한다. 즉, 테이블을 가지는 모델을 상송박되, 자식모델은 테이블을 만들 필요가 없는 경우 사용 - 추상 클래스에 메소드만 있을 경우, 이는 사용할 수 있다.
from django.db import models
class User(models.Model):
name = models.CharField(max_length=50)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_block = models.BooleanField(default=False)
def __str__(self):
return self.name
class Admin(User):
class Meta:
proxy = True
def __str__(self):
return f'{self.name} (관리자)'
def drop(self, user):
user.delete()
class Staff(User):
class Meta:
proxy = True
def __str__(self):
return f'{self.name} (스태프)'
def block(self, user):
user.is_block = True
user.save()
- Staff와 Admin 테이블이 없고, User테이블과
proxy inheritance
로 연결된 것을 볼 수 있다.
from django.db import models
from django.db.models.manager import Manager
class User(models.Model):
name = models.CharField(max_length=50)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_block = models.BooleanField(default=False)
def __str__(self):
return self.name
# 커스텀 매니저
class AdminManager(Manager):
# 기본적으로 가져오는 queryset을 변경할 때 사용
# super().get_queryset() = 클래스의 전체 데이터 가져
def get_queryset(self):
return super().get_queryset().filter(is_admin=True)
class Admin(User):
# Admin.objects.all()하면 기본 쿼리셋으로 지정한 데이터셋 출
objects = AdminManager()
class Meta:
proxy = True
def __str__(self):
return f'{self.name} (관리자)'
def drop(self, user):
user.delete()
class StaffManager(Manager):
def get_queryset(self):
return super().get_queryset().filter(is_staff=True)
class Staff(User):
objects = StaffManager()
class Meta:
proxy = True
def __str__(self):
return f'{self.name} (스태프)'
def block(self, user):
user.is_block = True
user.save()
- 프록시 모델에 모델 관리자를 지정하지 않으면, 부모클래스로부터 관리자를 상속 받는다.
- 프록시 모델에서 정의를 하면, 부모클래스의 관리자 역시 사용할 수 있음
objects
말고 다른이름으로 관리자를 설정하면objects
는 자동으로 생기지 않는다.
# `objects` 매니저도 사용하고, 커스텀 매니저도 사용하고 싶을 때
class ExtraManagers(model.Model):
secondary = NewManger()
class Meta:
abstract = True
class MyPerson(Person, ExtraManagers):
class Meta:
proxy = True
Mix-in
클래스에 추가적이 속성이나 메소드를 제공하는 것을 말함 자체적으로는 실행하지 않는다. Django는 특정 속성이 있을 수도 있다. 필드를 추가 할 수도 있어서.. ps_ptr 을 피하기 위해서.
hiding
추상 클래스의 경우, 테이블이 없기 때문에 상속을 받아서 사용했을 때 속성의 이름을 바꿀 수 있다.
기타
- 캡슐화 추상 기본 클래스에서는 objects를 사용해서 접근 할 이유가 없다.
<!-- 특정 파일 제외 시킬 때 -->
git reset HEAD inheritance/proxy