오늘 코드를 구현하고 뭔가 굉장히 마음에 들지 않아 정한이형과 같이 리펙토링을 했다!
우선
worry_list = []
for cate_get in range(1, 7):
worry_gets = WorryBoardModel.objects.filter(category=cate_get).order_by(
"-create_date"
)[:3]
for worry_get in worry_gets:
cate = {
"worry_id": worry_get,
"category": worry_get.category,
"content": worry_get.content,
}
worry_list.append(cate)
위와 같은 코드이다.
이번 프로젝트 메인페이지에서는 카테고리별(총6개) 에서 게시글을 3개씩 가져와야 하는데 이 쿼리셋을 합치는
코드를 짜는데 2중 for문을 쓰는것도 그렇고 너무 비효율적이고, 맘에 들지 않는 코드다.
worry_list = WorryBoardModel.objects.none()
for cate_get in WorryCategory.objects.all():
worry_list = worry_list.union(WorryBoardModel.objects.filter(category=cate_get).order_by("-create_date")[:3])
저코드를 3줄로 줄였다.
굳이 2중for 문을 돌릴필요 없이 빈쿼리셋을 선언하고, 거기에 union 으로 합쳐주면 된다
qs1 = Toy.objects.filter(price__lte=10000) // 만원 이하인 장난감들
qs2 = Toy.objects.filter(price__gt=20000) // 2만원이 넘는 장난감들
// 방법1
result_set = qs1 | qs2 // qs1과 qs2를 합친 결과
// 방법2
result_set2 = qs1.union(qs2)
이 쿼리셋을 합치기 위해 필요한 조건은 합치려고 하는 두 쿼리셋이 같은 필드를 갖고 있어야 한다는 점이다. 사실 쿼리셋을 합치기 위해선 같은 모델의 쿼리셋이라고 설명하는 블로그들이 많은데 엄밀히 말하면 같은 모델이라도 필드명과 타입이 똑같으면 쿼리셋을 합칠 수 있다는 것이다.
물론 필드가 다르더라도 ORM 작성시 annotate를 통해 필요한 컬럼을 붙여 최종적으로 queryset에 담겨있는 모델의 스키마가 같게 해주면 합쳐질 수 있다.
class Toy(models.Model):
name = models.CharField(max_length=50, help_text='이름')
price = models.IntegerField(help_text='가격')
company = models.CharField(max_length=50, help_text='판매사')
class Toy2(models.Model):
name = models.CharField(max_length=50, help_text='이름')
price = models.IntegerField(help_text='가격')
위의 Toy와 Toy2 모델은 다른 모델이지만 다음과 같이 company 컬럼을 추가해 주어 쿼리셋을 만들어 주면 Toy 쿼리셋과 합칠 수 있다는 것이다.
Toy2.objects.annotate(company=Value('company2', output_field=CharField())
letter_author = request.user
title = request.data["title"]
content = request.data["content"]
worry_board_get = request.data["worry_board_id"]
category = WorryBoardModel.objects.get(id=worry_board_get).category.id
post_datas = {
"category": category,
"letter_author": letter_author.id,
"title": title,
"content": content,
"worryboard": worry_board_get,
}
letterserialzier = LetterSerilaizer(data=post_datas)
letterserialzier.is_valid(raise_exception=True)
letterserialzier.save()
이렇게 하면, serialzier를 굳이 쓰는 이유도 없고, 쓸데 없는 코드도 너무 많다.
worry_board_get = request.data['worry_board_id']
request.data['letter_author'] = request.user.id
request.data['category'] = WorryBoardModel.objects.get(id=worry_board_get).category.id
letterserialzier = LetterSerilaizer(data=request.data)
letterserialzier.is_valid(raise_exception=True)
letterserialzier.save(worryboard=WorryBoardModel.objects.get(id=worry_board_get))
이렇게 간단하게 리펙토링 할 수 있다.
코드를 짤때 항상 간결하게, 누구나 보기 쉽게, 그리고 효율적으로 짜기.