내 잡다한 노트

Relation과 Join 본문

Web/Django

Relation과 Join

peanutwalnut 2022. 4. 18. 00:16

#Relation

모델과 모델간의 종속 관계를 정의한다.

1. Many-to-Many : 출판사와 저작물의 관계라고 생각하자

하나의 저작물을 여러 출판사에서 낼 수도 있고 반대로 하나의 출판사가 여러 저작물을 낸다.

2. Many-to-One : 게시물과 댓글의 관계

3. One-to-One : 여권과 사람의 관계

 

#Foreign-Key

외래키란 테이블의 필드 중에서 다른 테이블의 행과 식별할 수 있는 키를 의미한다.

외래키가 포함된 테이블을 자식 테이블이라 하며, 외래키 값을 갖고 있는 테이블은 부모 테이블이라

합니다.

즉, 테이블과 테이블을 연결하기 위해 사용되는 키.

 

필수적으로 포함되어야 할 매개변수는 참조할 테이블, 개체 관계에 사용할 이름, 개체 삭제시

수행할 동작 입니다.

 

 

 # 식당 모델과의 릴레이션 정의,

    # on_delete CASCADE로 지정하면 식당이 삭제되면 같이 삭제된다.

    restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE)

 

Many-to-One 관계에서 Many는 Review, One은 Restaurant 모델이 된다.

이때는 종속되는 모델인 Review에 ForeignKey로 상위 모델을 정의해 릴레이션을 구현한다.

on_delete로 식당 레코드가 삭제될때 그 식당정보에 등록된 리뷰들을 어떻게  처리할 건지에

대해 결정할 수 있다.

CASECADE로 지정하면 모든 댓글이 삭제되고 SET_NULL을 사용하면 restaurant 속성이 Null

데이터로 채워지게 된다.

이렇게 릴레이션을 정의하게 되면 실제 db에는 Restaurant의 primary key인 id 값을

저장하는 컬럼이 review에 추가된다.

 

path('restaurant/<int:id>/', views.detail, name='restaurant-detail'),  # detail 의 주소를 재정의

 

def detail(request, id):  # restaurant의 id (pk)를 직접 url path parameter을 통해 전달 받습니다.

    if id is not None:

        item = get_object_or_404(Restaurant, pk=id)

        return render(request, 'third/detail.html', {'item': item})

    return HttpResponseRedirect('/third/list/')  # 리스트 화면으로 이동합니다.

 

<a href="{% url 'restaurant-detail' id=item.id %}" class="card-link">자세히 보기</a>

이전 글에서 나중에 장고식으로 바꾸게 된 다고 한 부분이 여기이다.

쿼리 파라미터를 이용했는데 바뀌었다.

 

 widgets = {

            'restaurant': forms.HiddenInput(),  # 리뷰를 달 식당 정보는 사용자에게 보여지지 않도록 합니다.

            'point': forms.Select(choices=REVIEW_POINT_CHOICES)  # 선택지를 인자로 전달합니다.

 

widgets로 다양한 forms 들을 사용할 수 있다.

 

#Join

Join또는 결합 구문은 한 db내의 여러 테이블의 레코드를 조합하여 하나의 열로 표현한 것이다.

따라서 조인은 테이블로서 저장되거나, 그 자체로 이용할 수 있는 결과 셋을 만들어 낸다.

JOIN은 2개의 테이블에서 각각의 공통값을 이용함으로써 필드를 조합하는 수단이 된다.

 

만약 우리가 리뷰 목록만 모아보는 화면을 만든다고 생각해봅시다. 이 때 일단 리뷰를 조회하는

코드를 수행하고 각 리뷰마다 어떤 음식점을 평가한 것인지 찾아내야 하는데요. 10개의 리뷰가

있다면, 각각에 대해 

 

Restaurant.objects.get(pk= … )

 

코드를 10번 수행해서 각각의 음식점들을 조회해야 합니다. 

하지만 애초에 원하는 결과를 가져오려면 음식점 목록을 가져올 때 위 조건을 만족하는 리뷰 글을

동시에 조회할 수 있으면 됩니다. 이 때 사용되는게 Join이라는 방법입니다.

쟝고에서는 ORM에서 Join을 지원하기 때문에 Relation 관계가 정의된 모델 간에는 쉽게 사용할

수 있습니다

 

# Review 조회 시에 바로 join을 사용해서 restaurant을 같이 가져오기

방법은 간단합니다. Django orm에서 데이터를 조회할 때 아래의 메소드를 추가로 호출하면 됩니다.

 

.select_related() 을 사용하자!

 

 reviews = Review.objects.all().select_related()

 

#

  • 리스트 화면에서 리뷰개수 불러오기

그 외에도 각 음식점의 리뷰 수를 구하거나 평점을 음식점 목록 화면에서 바로 표시할 수 있도록

해주는 방법이 있습니다. django의 공식 문서의 aggregation 파트(https://docs.djangoproject.com/en/2.1/topics/db/aggregation/)를 보시면 된다.

 

# annotate

 

이건 조회되는 각 레코드들에 대해서 계산을 수행해서 데이터를 뽑아낼 대 사용한다.

.annotate(  counts            =              Count                (‘review’)
      {연산 결과를 저장할 속성명}  {ORM 연산 메소드}   {relation 이름}

만약 Many-to-One관계에서 부모 레코드에서 자식 레코드의 정보를 연산할 때에는 relation 이름에 다음과 같이 작성합니다.

 

.annotate(  avgs            =              Avg                (‘review__point’)
      {연산 결과를 저장할 속성명}  {ORM 연산}  {‘relation 이름’ +’ __’ + ‘연산 대상 속성명’}

 

이렇게 하면 template에서 {{ item.reviews_count }}로 model에 속성이 없어도

꺼내서 쓸 수 있다.

 

'Web > Django' 카테고리의 다른 글

Django에 이미지 업로드 후 출력하기  (0) 2022.06.06
putty가 connection timed out 오류가 계속 떠서...  (0) 2022.05.04
CRUD  (0) 2022.04.17
ORM  (0) 2022.04.11
Form  (0) 2022.04.11