json/pickle 모두 파이썬 기본 라이브러리이며 장고의 Model, QuerySet 등에 대해서는 직렬화 Rule이 없기때문에 그대로 dumps()에 넣으면 에러가 발생합니다. (TypeError: Object of type QuerySet is not JSON serializable)
(1) rest_framework.renderer.JSONRender
rest_framework/utils/encoders.py 의 JSONEncoder를 통한 직렬화 지원
__getitem__ 속성 지원시 dict(obj) 변환
__iter__ 속성 지원시 tuple 변환
QuerySet 타입일 시 tuple 변환
.tolist 속성 지원 시 obj.tolist()
Model 타입은 미지원 -> ModelSerializer를 통해 변환이 가능합니다.
(2) rest_framework.renderers.JSONRenderer
json.dumps에 대한 래핑 클래스 -> 보다 편리한 직렬화를 지원
from rest_framework.renderers import JSONRendererdata = Post.objects.all()
JSONRenderer().render(data)# 하지만 Model에 대한 변환 Rule은 아직 없음.
(3) ModelSerializer를 통한 JSON 직렬화
Serializer/ModelSerializer는 Form/ModelForm과 유사합니다. => 역할 면에서 Serializer는 POST 요청만 처리하는 Form임.
장고 기본 View에서의 HttpResponse JSON 응답
모든 View는 HttpResponse 타입의 응답을 해야만 함.
직접 json.dumps를 통해 문자열을 획득, HttpResponse를 통해 응답
1번을 정리하여 jsonResponse 지원 -> 내부적 json.dumps를 사용하며 DjangoJSONEncoder가 디폴트 지정됨.
DRF에서의 JSON 응답
1. DRF를 통한 HttpResponse JSON 응답
qs = Post.objects.all()
serializer = PostModelSerializer(qs, many=True)from rest_framework.response import Response
response = Response(serializer.data) # text/html 기본값# Response에서는 JSON 직렬화가 Lazy하게 동작
# 실제 응답 생성시 .rendered_content 속성에 접근하며 이때 변환 이뤄짐
DRF의 모든 뷰는 APIView를 상속받습니다. APIView를 통해 Response에 다양한 속성이 지정됩니다.
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) 필드가 있을 때,
serializers.py 에서 fields = ‘__all__’ 로 사용시
author : 1
이런식으로 알아보기 쉽지 않게 author의 pk로 뜨게 됩니다. 하지만 serializers.py에서 serializer.ReadOnlyField를 통해 FK의 필드값을 읽어와서
class PostSerializer(serializers.ModelSerializer):
username = serializers.ReadOnlyField(source='author.username')
# fk인 author의 username을 가져와서
class Meta:
model = Post
fields = ['pk', 'username', 'message', 'created_at', 'updated_at']
이런식으로 읽어온 값을 fields에 지정해주면 author : 1 이 아닌 username : ‘홍길동’ 이런 식으로 응답을 받을 수 있겠죠!
# 아니면 이 방법으로도 가능합니다!( 중첩된 Serializer 사용 )
class AuthorSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
fields = ['username', 'email']class PostSerializer(serializers.ModelSerializer):
author = AuthorSerializer() class Meta:
model = Post
fields = '__all__'
$ git branch -d work3
error: The branch 'work3' is not fully merged.
If you are sure you want to delete it, run 'git branch -D work3'.
$ git branch -d work_new
Deleted branch work_new (was 4bbc62f).
ForeignKey, ManyToManyField 그리고 OneToOneField 들을 제외한,
각 필드 타입은 선택적으로 첫번째 위치인자로, verbose name 을 받습니다.
verbose name 이 주어지지 않았을때는,
Django 는 자동으로 field 의 속성명의 언더스코어를 공백으로 전환하여 verbose name 을 생성합니다.
verbose name 은
사용자가 사용하는 자세한 이름을 의미합니다
verbose name 을 지정하지 않으면,
어드민에 표시되는 이름이 이상하다는것을 느낄수 있을겁니다.
아래 예시에서, verbose name 은 “person’s first name” 입니다
first_name = models.CharField("person's first name", max_length=30)
아래 예시에서는, verbose name 이 “first_name” 입니다.
필드 타입의 첫번째 인자로, verbose name 이 명시되지 않았기 때문에,
필드명 first_name 에서, 언더스코어를 공백으로 전환하여 verbose name 을 표시합니다.
first_name = models.CharField(max_length=30)
verbose_name 을 정의한 모델의 예시입니다.
class Members(models.Model):
name = models.CharField(max_length=50, verbose_name='이름')
nick_name = models.CharField(max_length=50, verbose_name="닉네임")
birth_date = models.DateField(verbose_name="생년월일", null=True)
위 Members 모델에서는, name, nick_name, birth_date 이
각각 한글로 표시된 verbose_name 들을 어드민에 표시할것입니다.
1. 외래키 모델들
아직 살펴보지는 않았지만, ForeignKey, ManyToManyField 그리고 OneToOneField 들은
첫번째 인자로 모델 클래스가 옵니다.
따라서,verbose_name을 키워드 인자로 사용해줍니다.
poll = models.ForeignKey(Poll, on_delete=models.CASCADE, verbose_name="the related poll")
# poll 은 ForeignKey (외래키) 로 Poll 이라는 클래스를 첫번째 인자로 받음
# verbose_name 은 키워드 인자로 넣어줌
sites = models.ManyToManyField(Site, verbose_name="list of sites")
# sites 는 ManyToManyField 로 Site 라는 클래스를 첫번째 인자로 받음
# verbose_name 은 키워드 인자로 넣어줌
place = models.OneToOneField(Place, on_delete=models.CASCADE, verbose_name='related place')
# place 는 OneToOneField 로 Place 라는 클래스를 첫번째 인자로 받음
# verbose_name 은 키워드 인자로 넣어줌
위의 예시에서는, 단지 ForeignKey, ManyToManyField 그리고 OneToOneField 를 사용할때에,
verbose_name 이 어떻게 키워드 인자로 들어가는지에 대한 코딩 스타일만 보여주고 있습니다.
관례적으로,
verbose_name 의 첫번째 글자는 대문자로 써주지 않습니다.
Django 가 필요할때 자동으로 첫번째 글자를 대문자화 해줍니다.
2. 마치며..
verbose_name 에 대해서 알아보았습니다. verbose_name 을 사용하면, 어떤것이 달라지는지 완벽한 예시가 있으면 좋았을텐데,
현재까지는, verbose_name 을 사용할경우,
해당 필드가 어드민에 표시되는 바가 달라지게 된다는점을 알고 넘어가면 될것 같습니다.
지난 포스팅에서 Runner 모델을 작성했었는데,
아래와 같이, name 필드에 verbose_name 을 추가해주었습니다. “러너 이름”
class Runner(models.Model):
MedalType = models.TextChoices('MedalType', 'GOLD SILVER BRONZE')
name = models.CharField("러너이름", max_length=60)
medal = models.CharField(blank=True, choices=MedalType.choices, max_length=10)
def __str__(self):
return self.name + " " + self.medal
위와같이 verbose_name 을 모델 필드에 추가하면,
아래처럼 어드민에 “러너이름” 이라고 표시가 됩니다.
1. 정참조와 역참조 객체 서로 호출하기
데이터베이스에서 두 테이블이 참조 관계에 있는 경우를 생각해보자.
예를 들어, User 테이블과 사용자의 직업인 Occupation 테이블이 있다.
두 테이블은 N:1 관계에 있으며, User 객체가 Occupation 객체를 참조하고 있다.
User 가 Occupation 을 선택하여 입사 원서를 작성한다고 가정해보자.
class User(models.Model):
name = models.CharField(max_length = 50)
job = models.ForeignKey('Occupation', on_delete = models.CASCADE)
created_at = models.DateTimeField(auto_now_add = True)
class Occupation(models.Model):
name = models.CharField(max_length = 50)
User 객체는 Occupation 객체를 정참조 하고 있으므로,
속성 이름으로 바로 접근 할 수 있다. User1을 선택하여, 그 사람의 job을 찾아보자.