직렬화

모든 프로그래밍 언어의 통신에서 데이터는 필히 문자열로 표현되야 합니다.

송신자 : 객체를 문자열로 변환하여 전송 -> 직렬화
수신자 : 수신한 문자열을 다시 객체로 변환하여, 활용 -> 비직렬화

 

각 언어에서 모두 지원하는 직렬화 포맷(JSON, XML 등) 과

특정언어에서만 지원하는 직렬화 포맷(Python의 Pickle) 이 있습니다.

요즘의 API서버에서는 대개 JSON 인코딩된 요청/응답 사용을 합니다.


 

1. JSON 포맷

- 표준 라이브러리 json 제공

- 다른 언어/ 플랫폼과 통신할 때 주로 사용

 

- pickle에 비해 직렬화를 지원하는 데이터 타입 수가 적지만, 커스텀 Rule 지원도 가능합니다.

import jsonpost_list=[{'message': 'hello'},]#직렬화
json_string = json.dumps(post_list)
print(json_string)      # [{'message': 'hello'},]#비직렬화
print(json.loads(json_string))

2. Pickle 포맷

- 파이썬 전용 포맷으로써 파이썬 시스템 끼리만 통신할 때 사용 가능합니다.

- 표준 라이브러리 pickle 제공.

import picklepost_list=[{'message': 'hello'},]pickle_bytes = pickle.dumps(post_list)
print(pickle_bytes) # b'\x80\0x3]q\x00........print(pickle.loads(pickle_bytes))

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 타입의 응답을 해야만 함.

  1. 직접 json.dumps를 통해 문자열을 획득, HttpResponse를 통해 응답
  2. 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에 다양한 속성이 지정됩니다.


2. DRF 에서의 활용예제

from rest_framework import genericsclass PostListAPIView(generics.ListAPIView):
   queryset = Post.objects.all()
   serializer_class = PostModelSerializerpost_list = PostListAPIView.as_view()

ListAPIView는 리스트 기능만 지원해줍니다!

(5가지 다 사용하고 싶을 땐 ViewSet사용을..)


3. 포스팅 조회 응답에서 글쓴이 이름을 조회하고 싶을 때

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__'
 

[Django Rest Framework] 직렬화(Serializer에 대해서 알아보자

직렬화

donis-note.medium.com

 

 

 
 

git은 오늘날 가장 많이 사용하는 버전 관리 시스템 중 하나입니다.
오늘은 git의 자주 사용하는 명령어에 대해서 살펴보고자 합니다.

먼저 각 명령어에 따른 흐름이 어떻게 변하는지 다음 그림을 통해 알 수 있습니다.


이미지 출처 : https://jrebel.com/rebellabs/git-commands-and-best-practices-cheat-sheet/

1. 생성하기

- 새로운 로컬 저장소를 생성하기

$ git init [project_name]

 

- 저장소 가져오기

$ git clone [url]

 


2. 살펴보기

- 작업 디렉토리에 변경된 파일 보기

$ git status

 

- 변경된 staged 파일 보기

$ git diff

 

- 변경 이력 보기

$ git log


3. 브랜치 작업하기

- 로컬 브랜치 보기

$ git branch

 

- 로컬과 원격 브랜치 보기

$ git branch -av

 

- 브랜치 변경하기

$ git checkout <branch>

 

- 브랜치 생성하기

$ git branch <new-branch>

 

- 브랜치 삭제하기

$ git branch -d <branch>

 

- 원격 브랜치를 추적하는 새로운 브랜치 만들기

$ git checkout --track <remote/branch>

 

- 원격 브랜치 추적하기

$ git branch -u <remote/branch>

 

- 현재 커밋에 태그 달기

$ git tag <tag-name>


4. 변경하기

- 파일의 변경 사항을 다음 커밋에 반영하기

$ git add [file]

 

- 모든 변경 사항을 다음 커밋에 반영하기

$ git add .

 

- 메시지와 함께 커밋하기

$ git commit -m "commit message"

 

- 모든 변경 사항을 반영하면서 커밋하기

$ git commit -a

 

- 마지막 커밋 수정하기(published commit에는 하지 말 것!)

$ git commit --amend

 


5. 취소하기

- 작업 디렉토리에 모든 변경 버리기

$ git reset --hard HEAD

 

- 커밋 되돌아가기

$ git revert <commit>


6. 동기화하기

- 원격 저장소의 변경사항 가져오기

$ git fetch <remote>

 

- 원격 저장소의 변경사항을 가져오고 머지하기

$ git pull <remote> <branch>

 

- 원격 저장소의 변경사항을 가져오고 리베이스하기

$ git pull --rebase

 

- 원격 저장소에 변경사항 발행하기

$ git push

 

- 원격 저장소에 태그 발행하기

$ git push --tags


7. 병합하기와 리베이스하기

- 병합하기

$ git merge <branch>

 

- 리베이스하기

$ git rebase <branch>


8. 변경사항 저장하고 복원하기

- 임시로 변경사항 저장하기

$ git stash

 

- 임시 변경사항 복원하기

$ git stash pop

 

- 임시 변경사항 보기

$ git stash list


출처

https://seamless.tistory.com/43

 

Git 명령어 요약 정리 (Cheat sheet)

git은 오늘날 가장 많이 사용하는 버전 관리 시스템 중 하나입니다. 오늘은 git의 자주 사용하는 명령어에 대해서 살펴보고자 합니다. 먼저 각 명령어에 따른 흐름이 어떻게 변하는지 다음 그림을

seamless.tistory.com

 

git branch명령은 branch 생성및 제거, 확인등의 기능을 하는 명령어로 주요 명령어만 요약하였습니다.
자세한 내용은 git-scm Git-브랜치-브랜치-관리에서 확인하세요.


1. git branch [-l]

로컬 branch 정보를 보여줍니다. (-l 옵션은 생략가능)

$ git branch
* master
  work1

2. git branch -v

로컬 branch의 정보를 마지막 커밋 내역과 함께 보여줍니다.

$ git branch -v
* master   4bbc62f commit message 'm1'
  work1    fe7f049 commit message 'w1'
  work_new 4bbc62f commit message 'work_new1'

3. git branch -r

리모트 저장소의 branch 정보를 보여줍니다.

$ git branch -r
  origin/master
  origin/work1

4. git branch -a

로컬/리모트 저장소의 모든 branch 정보를 보여줍니다.

$ git branch -a
* master
  work1
  remotes/origin/master
  remotes/origin/work1

5. git branch (이름)

로컬에 새로운 branch를 생성합니다.

$ git branch work_new
$ git branch -a
* master
  work1
  work_new
  remotes/origin/master
  remotes/origin/work1

※ 생성과 동시에 해당 branch로 이동하려면 아래 명령어를 사용합니다.

$ git checkout -b work2

※ 원격에 있는 branch를 가져오려면 아래 명령어를 사용합니다.

[특정이름 지정시]
$ git checkout -b work2 origin/work2      
[원격 branch 이름을 그대로 사용할 경우]
$ git checkout -t origin/work2

6. git branch (–merged | –no-merged)

--merged는 이미 merge된 branch를 표시해주고 --no-merged는 아직 merge가 되지 않은 branch만 표시합니다.
--merged에 branch 목록 이미 merge되었기 때문에 *가 표시되지 않은 branch는 삭제 가능합니다.

$ git branch --merged
* master
  work_new
  work_old

$ git branch --no-merged
  work1
  work2

7. git branch -d (branch 이름)

branch를 삭제합니다.

아직 merge하지 않은 커밋을 담고 있는 경우 삭제되지 않습니다.

(강제종료 옵션 -D으로만 삭제 가능)

$ 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).

8. git branch -m (변경할 branch이름) (변경될 branch이름)

A 브랜치를 B 브랜치로 변경합니다.

$ git branch -v
* master   4bbc62f m1
  work2    c728ddc w2
  work_old 4bbc62f m1

$ git branch -m work2 work3

$ git branch -v
* master   4bbc62f m1
  work3    c728ddc w2
  work_old 4bbc62f m1

※ -M 옵션을 사용할 경우 기존에 동일한 이름의 branch가 있더라도 덮어씁니다.


출처

https://jistol.github.io/vcs/2017/01/27/git-branch/

 

Git branch 주요 명령어 정리

 

jistol.github.io

 

메타 데이터는 다른 데이터에 대한 정보를 제공하는 특정 데이터 집합을 나타냅니다.

Django에서는 Django 모델을 사용하여 데이터베이스의 테이블과 해당 필드를 설계합니다.

 

모델 자체에 대한 데이터를 추가해야하는 경우Meta클래스를 사용합니다.

이 기사에서 Django 모델의Meta클래스에 대해 자세히 알아보십시오.


Django의 Meta클래스

Meta클래스는 inner 클래스입니다.

즉, 다음과 같이 모델 내부에 정의됩니다.

from django.db import models

class MyModel(models.Model):
    ...
    class Meta:
        ...

Meta클래스는 권한, 데이터베이스 이름, 단 복수 이름, 추상화, 순서 지정 등과 같은

모델에 대한 다양한 사항을 정의하는 데 사용할 수 있습니다.

 

Django 모델에Meta클래스를 추가하는 것은 전적으로 선택 사항입니다.

이 클래스에는 구성 할 수있는 많은 옵션도 제공됩니다.

다음은 일반적으로 사용되는 몇 가지 메타 옵션입니다. 여기에서 모든 메타 옵션을 탐색 할 수 있습니다.


1. Django 메타 옵션 - Abstract

이 옵션은 모델이 추상적인지 여부를 정의하는 데 사용됩니다. 추상 클래스와 동일하게 작동합니다.

 

추상 클래스는 인스턴스화 할 수없고 확장 또는 상속 만 가능한 클래스입니다.

추상으로 설정된 모델은 상속만 가능합니다.

공통 필드가있는 여러 모델이있는 경우이 옵션을 사용할 수 있습니다.

from django.db import models

class Human(models.Model):
    genders = (
        ("M", "Male"),
        ("F", "Female"),
        ("NB", "Non-binary"),
        ("T", "Transgender"),
        ("I", "Intersex"),
        ("O", "Other"),
        ("PNTS", "Prefer not to say")
    )

    name = models.CharField(max_length = 200)
    age = models.IntegerField(default = 0)
    gender = models.CharField(max_length = 50, choices = genders)

    class Meta:
        abstract = True # Important

class Teacher(Human):
    subject = models.CharField(max_length = 200)
    

class Student(Human):
    grade = models.IntegerField(default = 0)
    

여기에서 선생님 및 학생 모델은 Human 모델 내부에 모든 필드가 있습니다.

데이터베이스 내에는Teacher 및 Student 모델 만 생성됩니다.


2. Django 메타 옵션 - db_table

이 옵션은 데이터베이스 내에서

테이블을 식별하는 데 사용해야하는 이름을 설정하는 데 사용됩니다.

예를 들어 다음과 같은 작업을 수행하면 데이터베이스에서 모델 이름이 job이됩니다.

from django.db import models

class JobPosting(models.Model):
    
    
    class Meta:
        db_table = "job"

 


3. Django 메타 옵션 - Ordering

이 옵션은 모델 필드 인 문자열 값 목록을 사용합니다. 모델 객체의 순서를 정의하는 데 사용됩니다.

이 모델의 개체가 검색되면이 순서대로 표시됩니다.

from django.db import models

class JobPosting(models.Model):
    dateTimeOfPosting = models.DateTimeField(auto_now_add = True)
    
    
    class Meta:
        ordering = ["-dateTimeOfPosting"]

위의 예에서 검색된 개체는dateTimeOfPosting필드를 기준으로 내림차순으로 정렬됩니다.

(-접두사는 내림차순을 정의하는 데 사용됩니다.)


4. Django 메타 옵션 - verbose_name

이 옵션은 사람이 읽을 수있는 모델의 단일 이름을 정의하는 데 사용되며

Django의 기본 명명 규칙을 덮어 씁니다.

이 이름은 관리자 패널 (/admin/)에도 반영됩니다.

from django.db import models

class JobPosting(models.Model):
    
    
    class Meta:
        verbose_name = "Job Posting"

 

5. Django 메타 옵션 - Verbose name plural

이 옵션은 모델에 대해 사람이 읽을 수있는 복수형 이름을 정의하는 데 사용되며

다시 Django의 기본 명명 규칙을 덮어 씁니다. 이 이름은 관리자 패널 (/admin/)에도 반영됩니다.

from django.db import models

class JobPosting(models.Model):
    
    
    class Meta:
        verbose_name_plural = "Job Postings"

 


출처

https://www.delftstack.com/howto/django/class-meta-in-django/

 

ForeignKeyManyToManyField 그리고 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. 외래키 모델들

아직 살펴보지는 않았지만, ForeignKeyManyToManyField 그리고 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 은 키워드 인자로 넣어줌​

 

위의 예시에서는, 단지 ForeignKeyManyToManyField 그리고 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을 찾아보자.

user1 = User.objects.get(id = 1)
user1.job.name
>>> 'Developer'

 

그러나 Occupation 객체는 User 객체를 역참조 하고 있으므로 바로 접근이 불가능하다. 

developer 이라는 Occupation을 가지고 있는 유저를 모두 찾아보자.

job1   = Occupation.objects.get(name = 'developer')
people = job1.user.all() # 이게 될까?

 

❌ 안 됨 ❌

Traceback (most recent call last):
  File "<console>", line 1, in <module>
AttributeError: 'Occupation' object has no attribute 'user'

 

그렇다고 절대로 사용하지 못하는 것은 절대 아니니 걱정하지말자.

역참조 관계에 있을 때는 [classname]_set 이라는 속성을 사용하여 접근해야한다.

job1   = Occupation.objects.get(id = 1)
people = job1.user_set.all()
>>> <QuerySet[<Object User Object(1)>, <Object User Object(2)>]>

이 때, user_set 대신 사용할 수 있는 것이 related_name이다. 역참조 대상인 user 객체를 부를 이름.

 

즉, User 클래스를 정의할 때,

정참조 하고 있는 Occupation 클래스의 인스턴스에서 어떤 명칭으로 거꾸로 호출당할 지 정해주는 이름인 것이다.


2. What related names do

앞의 예시를 다시 보자.

아무래도 Occupation의 입장에서는 입사 지원자들을 appliers라고 부르는 것이 더 직관적이고 편할 것 같다.

class User(models.Model):
    name = models.CharField(max_length = 50)
    job	 = models.ForeignKey( 
            'Occupation',
            on_delete    = models.CASCADE,
            related_name = 'appliers' ------------------------- [Key Point !]
        )
    created_at	= models.DateTimeField(auto_now_add = True)
    	
class Occupation(models.Model):
    name = models.CharField(max_length = 50)

 

[Key Point] 를 눈여겨 보자.
User객체를 정의할 때, job이라는 속성에 Occupation객체가 연결되어 정참조하고 있다.

 

Occupation객체의 인스턴스와 연결되어 있는 User 객체를 거꾸로 불러올 때, 

appliers 라는 이름으로 부르기 위해 job 속성에 related_names = 'appliers'를 함께 지정해주었다.

job1   = Occupation.objects.get(id = 1)
people = job1.appliers.all()
>>> <QuerySet[<Object User Object(1)>, <Object User Object(2)>]>

 

잘 동작하는 것을 알 수 있다.

모든 Foreign Key에 related_name을 붙여줄 필요는 없다.

때에 따라, 참조하고 있는 객체 이름에 _set을 붙이는 것이 더 직관적인 경우가 굉장히 많기 때문이다.


3. Related name이 필수인 경우가 있다.

바로 한 클래스에서 서로 다른 두 컬럼(속성)이 같은 테이블(클래스)를 참조하는 경우이다.
앞서 설명한 상황에서, 지원자가 필수로 신청한 occupation외에, 2지망인 occupation도 받는다고 가정해보자.

class User(models.Model):
    name       = models.CharField(max_length = 50)
    job	       = models.ForeignKey('Occupation', on_delete = models.CASCADE)
[*] choice_2nd = models.ForeignKey('Occupation', on_delete = models.CASCADE, null = True)
    created_at = models.DateTimeField(auto_now_add = True)
    	
class Occupation(models.Model):
    name = models.CharField(max_length = 50)

 

참고로 위와 같은 선언은 애초에 마이그레이션이 되지 않는다.

related_name 지정하라는 문구만 뜸.

 

User객체에서 Occupation객체를 정참조 하는 속성이 두 개이다.

다시 말해 developer이라는 Occupations객체의 인스턴스를 1지망으로 선택한 지원자와 2지망으로 선택한 지원자가

따로 구별되어있다는 뜻이 된다. 아래 두 인스턴스를 보자.

user1 = User.objects.create(name = 'Nick', job_id = 1) #developer
user2 = User.objects.create(name = 'Sue', job_id = 2, choice_2nd_id = 1)

user1은 1지망은 job으로 id가 1번인 developer이다.
user2의 1지망은 2번 job이고, 2지망이 developer이다.

job1 = Occupation.objects.get(id = 1)
job1.user_set.all()

의 결과가 생성될 수 있을까?
❌ 안 됨 ❌

 

Occupation객체를 정참조 하고 있는 컬럼이 job과choice_2nd두 개이므로,

그저 user_set이라는 속성만으로는 자신을 바라보고 있는 두 User 객체 가운데

어떤 속성에 접근해야할 지 알 수가 없기 때문이다.

 

즉, developer을

1지망으로 고른 사람들의 목록(Nick)을 가져와야할 지,

2지망으로 고른 사람들의 목록(Sue)을 가져와야할 지 알 수가 없기 때문이다.

class User(models.Model):
    name = models.CharField(max_length = 50)
    job	 = models.ForeignKey( 
            'Occupation',
            on_delete    = models.CASCADE,
            related_name = 'appliers' ------------------------- [Key Point !]
        )
    choice_2nd  = models.ForeignKey(
            'Occupation',
            on_delete    = models.CASCADE,
            null         = True
            related_name = 'second_appliers'
        )
    created_at	= models.DateTimeField(auto_now_add = True)

 

이제는 developer을 1지망으로 지원한 Nick과 2지망으로 지원한 Sue를 구분하여 호출할 수 있다.

job1 = Occupation.objects.get(id = 1)

job1.appliers.all()
>>> <QuerySet[<Object User Object(1)>]> # ---> Nick

job1.second_appliers.all()
>>> <QuerySet[<Object User Object(2)>]> # ---> Sue

ManyToMany 관계에 있을 때에도 related_name은 같은 원리로 동작한다. 헷갈리지 않게 주의하자.

 


4. 마치며

웹의 구조나 서비스가 복잡해질 수록, 클래스 사이의 참조가 많아진다.

일대다는 물론이고, 다대다 관계도 계속 늘어난다.

그럴 때일 수록 related name이 중요하다고 생각한다.

 

어떻게든 migration만 되면 되지. 라는 생각으로 related_name을 마음대로 설정하다 보면,

나중엔 변수 이름을 아무렇게나 정했을 때만큼이나 의미를 알수 없는 코드를 양산하게 되기 때문이다.

오늘도 많이 배웠다.

 


출처

https://djangojeng-e.github.io/2020/08/02/Django-Models-6%ED%8E%B8-Fields-verbose-field-names/

 

Django Models 6편 - Fields (verbose field names)

Models - Fields (verbose field names) ForeignKey, ManyToManyField 그리고 OneToOneField 들을 제외한, 각 필드 타입은 선택적으로 첫번째 위치인자로, verbose name 을 받습니다. verbose name 이 주어지지 않았을때는, Django

djangojeng-e.github.io

https://velog.io/@brighten_the_way/Django%EC%99%80-Reverse-relations%EA%B3%BC-Relatedname

 

Django와 Reverse relations과 Related_name

그래서 결국, 너의 이름은

velog.io

 

+ Recent posts