본문 바로가기
TIL/Python | Django

2021.7.23 TIL : [Django] ORM의 select_related/prefetch_related, forms.py에서 지정한 form을 css로 디자인하기, 외부 DB 연동하기

by yeon_zoo 2021. 7. 23.

며칠동안 하나의 주제를 깊이 파기 보다는 장고로 기본 블로그를 만들고 이것 저것 많이 시도해봤다. 아직 배울 것도 너무 많고 다 새로운 내용이라 깊이 있게 나가지 못했지만, 배운 내용을 정리 안 해두면 금방 까먹을 것 같아 여러 주제를 통합해 올리기로 했다. 주제는 다음과 같다.

1. ORM의 select_related와 prefetch_related

2. forms.py 를 만들어서 하나의 폼을 어디에나 쓸 수 있도록 간편하게 만들어 둔 것을 css로 디자인 수정하는 방법 (특히 django에서 기본적으로 주는 툴인 UserCreationForm을 바꾸는 방법)

3. Mysql이나 mariadb 같은 외부 DB와 연동하는 법

 

1. ORM의 select_related와 prefetch_related

개인적으로 이 문제를 일주일동안 고민했는데, 생각보다 쉽게 풀리는 문제였다. (내가 실수로 값을 저장하지 않고서 계속 참조를 하고 있었다.) 우선 나는 다음과 같은 문제를 해결하고 싶었다. 

위와 같은 user 모델과 blog 모델이 있을 때, 현재 로그인한 사용자와 같은 학교에 다니는 사람들이 작성한 블로그들을 보여주는 페이지를 만드는 것이다. 우선 위 모델들을 관계형 데이터베이스로 표현해 보면 다음과 같다. 

우리가 궁극적으로 불러올 것은 Blog 객체이고 이 때 참조하고 싶은 것은 Blog 내의 FK인 User이다. 이런 경우를 정참조로 보고 select_related를 사용하면 된다. 

def search_univ(request):
    univUser = request.user
    blogs = Blog.objects.select_related('writer').filter(writer__university = univUser.university)
    return render(request, 'searchUniv.html', {'blogs':blogs})

위 코드는 views.py에서 사용한 함수인데, 이렇게 사용하면 writer에 연결된 user 테이블에 가서 university가 동일한 user들을 찾고, 이들이 작성한 블로그들을 불러올 수 있다. 

반면 prefetch_related()는 역참조 관계나 다대다 관계에서 사용할 수 있다. 역참조란, 위의 예에서 user 테이블에서 blog를 참조할 때를 의미한다. user 테이블에서 직접적으로 blog의 pk를 fk로 갖는다던지와 같이 어떤 관계를 맺고 있는 것은 없지만 찾아볼 수 있도록 역참조하게 해두는 것이다. select_related와 prefetch_related를 이용하면 쿼리가 깔끔해 질 뿐만 아니라 쿼리 실행 횟수도 줄일 수 있다. 

 

2. forms.py에서 지정한 form에 css로 디자인하기 

django에서 기본적으로 제공한 UserCreationForm 디자인이 너무 안 예쁘고 helptext 가 너무 많아서 수정하고 싶었는데, 구글링해도 검색 결과가 잘 나오지 않았다. 생각보다는 단순하게 디자인을 다시 할 수 있었는데 forms.py 에서 다음과 같은 코드로 작성하면 된다.

from django import forms
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.db.models import fields
from .models import CustomUser

class SignupForm(UserCreationForm):
    username = forms.CharField(
        label="",
        widget=forms.TextInput(attrs={ 'class': 'signup-inputs',
                                        'placeholder': '아이디를 입력하세요'})
        )
    password1 = forms.CharField(
        label="",
        help_text="문자, 숫자, 기호를 조합하여 8자 이상을 사용하세요",
        widget=forms.PasswordInput(attrs={'class': 'signup-inputs',
                                          'placeholder': '비밀번호를 입력하세요'})
        )
    password2 = forms.CharField(
        label="",
        help_text="",
        widget=forms.PasswordInput(attrs={'class': 'signup-inputs',
                                          'placeholder': '비밀번호 확인'})
        )
    nickname = forms.CharField(
        label="",
        widget=forms.TextInput(attrs={'class': 'signup-inputs',
                                          'placeholder': '닉네임을 입력하세요'})
        )
    university = forms.CharField(
        label="",
        help_text="예 : 한국외국어대학교",
        widget=forms.TextInput(attrs={'class': 'signup-inputs',
                                          'placeholder': '재학 중인 대학교를 입력하세요'})
        )
    location = forms.CharField(
        label="",
        help_text="예 : 서울시 동대문구 이문로 107",
        widget=forms.TextInput(attrs={'class': 'signup-inputs',
                                          'placeholder': '주소를 입력하세요'})
        )
    class Meta:
        model = CustomUser
        fields = ['username', 'password1', 'password2', 'nickname', 'university', 'location']

 

중요한 점은 class Meta: 전에 해당 내용들이 들어가야 한다. widget을 이용해서 fields 밑에다가 적어도 css의 class를 지정할 수는 있지만, label이나 help_text는 저 위치에서만 수정이 된다. 더 예쁘게 꾸미고 싶었지만, 아무래도 css적 지식도 부족하고 더 수정할 수 있는 방법을 잘 몰라서 다음 사진처럼 회원가입 페이지를 만들 수 있었다. 

3. Mysql이나 mariaDB와 같은 외부 DB 연동하기

이 부분은 아직 로컬에서만 연동해봐서 프로젝트 배포때는 어떻게 해야 하는지는 아직 잘 모른다. 다만 로컬에서 연동하는 법은 다음과 같다. (그리고 DB 연동은 윈도우가 맥보다 쉬워보였다) 

mariaDB 다운로드 받기🔽

https://mariadb.com/resources/blog/installing-mariadb-10-1-16-on-mac-os-x-with-homebrew/

 

Installing MariaDB Server on Mac OS X with Homebrew | MariaDB

Developing on your Mac? Get the latest stable MariaDB version on OS X easily with Homebrew. See this step by step guide on installing MariaDB 10.4.13.

mariadb.com

mysql 다운로드 받기🔽

https://flaviocopes.com/mysql-how-to-install/

 

How to install MySQL on macOS

Step by step instructions to install MySQL on macOS using Homebrew

flaviocopes.com

mysql 다운로드 받는 방법은 중간 정도에 다음 코드가 나오는 정도까지만 하면 된다.

$ mysql -u root -p

그러면 이런 문구를 볼 수 있을 것이다.

mysql을 다운로드 받은 후에는 이 데이터베이스를 사용할 수 있도록 시각적으로 더 잘 보여주는 툴을 다운로드 받는 것이 좋다. 이 때 자주 추천되는 툴은 Sequel Pro 인 것 같다. 나도 처음엔 Sequel Pro로 했는데, mysql 8.x 버전과 Sequel Pro를 같이 사용하니까 에러가 났다. 그래서 검색해보니 많은 사람들이 같은 오류를 겪고 있더라. 이 때 할 수 있는 방법은 mysql 다운그레이드 혹은 다른 툴을 찾는 것이었다. https://webruden.tistory.com/732 에 따라서 쉽게 다른 툴을 사용할 수 있었다. Sequel Ace를 이용하니까 UI는 비슷하고, 오히려 쉬운 느낌을 받아서 쉽게 뚝딱 오픈할 수 있었다.

이제 장고에서 DB를 연결해 주면 된다. settings.py에 들어가보면

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

이런 코드로 DB가 sqlite로 사용되고 있는 것을 확인해 볼 수 있다. 이것을 다음과 같이 바꿔주면 DB연결 끝이다.

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'mysql',
        'USER': 'root',
        'PASSWORD': '비밀번호 입력',
        'HOST' : '127.0.0.1',
        'PORT' : '3306',
    }

이렇게 하면 기존에 있던 데이터들은 전부 삭제되니 유의해야 한다! (아예 삭제 되는 것은 아니고 sqlite에 남아있다. 다시 sqlite를 연결하면 데이터를 확인할 수 있다) Sequel Ace에서 위의 DATABASES와 동일하게 USER, HOST, PORT를 입력하면 데이터베이스에 접근할 수 있다. 그리고 mysql 데이터베이스를 선택하면 다음과 같이 데이터가 쌓이는 것을 확인할 수 있다.

참고로 DB의 비밀번호는 깃헙과 같은 곳에 올라가면 안되기 때문에(특히 실제 서비스의 경우, 사용자 정보가 노출될 수 있으니까) my_settings.py 를 만들어서 myDATABASES = {} 와 같은 식으로 저장하고 settings.py 에는 DB란을 적지 않는다. 그리고 settings.py 에는 from . my_settings.py import myDATABASES 를 해서 연결해 주면된다. 이렇게 하고 나서는 깃헙에는 .gitignore을 이용해서 my_settings.py는 올리지 않아야 한다!

(같은 방식으로 SECRET_KEY도 올리면 안된다!) 나는 첫 프로젝트 두 개 정도를 모르고 secret_key를 공개해 올렸는데, 그러면 파일을 올린지 얼마 되지 않아서 깃헙으로부터 메일이 온다ㅎㅎ 그걸 다 감지하는게 신기하기도 하고, 아무도 안 보면서 쓸모도 없는 그런 프로젝트라서 다행인 기분이 든다! 

댓글