728x90

새로운 개발 장비가 생기면 이전에 사용하던 장비의 환경과 동일하게 준비하는 것이 은근 번거롭습니다. 한동안 손대지 않고 있던 파이썬 Python 장고 Django 프레임웍으로 개발된 코드를 새 장비에서 다루려다보니 역시나 의존성 문제들이 여러번 발생하고 있습니다.

그 중에서도 최초 환경 설치시에도 겪었던 mysqlclient 패키지 설치 이슈가 있어서 간략하게 정리해봅니다. 한줄 요약을 먼저하자면 Mac OS 환경에서는 homebrew 를 이용해 mysql 을 설치하는 것이 가장 쉽고 빠른 해결 방법입니다. 


개발중인 과제는 requirements.txt 에 필요한 의존성 패키지들이 잘 정리되어 있습니다. virtualenv 를 사용할 수 있는 환경을 만들고 pip install -r requirements.txt 명령을 이용해 패키지를 잘 설치하던 와중에... 떡하니 mysqlclient 패키지 설치가 문제가 발생했습니다.

폴백 fallback 로직에 따라 하위 버전까지 내려가면서 설치 시도를 하느라 실제 터미널 화면에는 휘황찬란한 붉은색의 에러메세지가 도배되었습니다. 에러를 알려주려는 메세지는 여러줄이었지만 핵심을 찝어내면 mysql_config not found 에러가 문제였습니다. 구글링을 조금 해보면 Mac OS 에서는 mysql 설치로 해결하는 것이 정석인듯 합니다. 

Collecting mysqlclient
  Downloading mysqlclient-2.0.3.tar.gz (88 kB)
     |████████████████████████████████| 88 kB 2.6 MB/s 
    ERROR: Command errored out with exit status 1:
    ...
    ...
    Complete output (15 lines):
    /bin/sh: mysql_config: command not found
    /bin/sh: mariadb_config: command not found
    /bin/sh: mysql_config: command not found
    ...
    ...
    OSError: mysql_config not found
    mysql_config --version
    mariadb_config --version
    mysql_config --libs

 

Homebrew 를 이용하여 mysql 을 설치하는 방법은 간단합니다. 사실 mysql 설치 외에도 다른 방법이 있을 거라 생각되지만 (로컬 환경에서 mysql 인스턴스를 띄울 일도 없어서...) 환경을 만들고 코드를 동작시키는 것이 더 급한 관계로 mysql 을 설치했습니다. 

% brew install mysql
==> Downloading https://ghcr.io/v2/homebrew/core/protobuf/manifests/3.15.8
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/protobuf/blobs/sha256:a1615a95bf6f0bd3d9111fd0afa9260373295eadf147c35aef03e31abdbef6bc
==> Downloading from https://pkg-containers.githubusercontent.com/ghcr1/blobs/sha256:a1615a95bf6f0bd3d9111fd0afa9260373295eadf147c35aef03e31abdbef6bc?se=2021-05-18T03%3A15%3A00Z&sig=fpdRcLV73XovJ%2BjHStE98SY%2B9UBYum6GJxr8QQa
######################################################################## 100.0%
...
...
MySQL is configured to only allow connections from localhost by default

To connect run:
    mysql -uroot

To have launchd start mysql now and restart at login:
  brew services start mysql
Or, if you don't want/need a background service you can just run:
  mysql.server start
%

 

mysql 설치가 완료된 후 다시 pip 로 requirements.txt 에 기술된 항목들을 설치 시도해보니 특별히 문제 없이 mysqlclient 가 설치되는 것을 확인할 수 있었습니다. 똑똑한 pip 는 캐시에 저장된 mysqlclient 바이너리를 활용하여 패캐지 설치를 마쳤답니다 :-)

% pip3 install -r requirements.txt
...
...
Collecting mysqlclient
  Using cached mysqlclient-2.0.3.tar.gz (88 kB)
Collecting netifaces
  Downloading netifaces-0.10.9.tar.gz (28 kB)
Collecting cryptography
...
...

 

(업데이트) 트위터로 포스팅이 공유된 후 "왜 PyMySQL과 mysqlclient를 같이 쓰는가?"에 대한 이야기를 들었습니다. 그러고 보니... 왜 두개가 같이 들어가 있는지 생각도 못하고 있었네요. 다행(?)히도 같이 작업하시던 누군가 PyMySQL과 mysqlclient를 같이 시험하다 최종적으로 mysqlclient를 쓰기로 한 것이었습니다. requirements.txt에서 가볍게 삭제~ 

검색을 해보면 python에서 mysql 액세스를 하기 위해 널리 쓰이는게 PyMySQL과 mysqlclient, 그리고 peewee 정도인 것 같습니다. peewee는 ORM의 성격이 강한 것 같고 (써보진 않았습니다) mysqlclient는 C로 개발되어 속도가 빠르다, PyMySQL은 python 으로 만들어졌다 정도의 특징들이 있는 것 같네요!

728x90
728x90

지난 포스팅에서 안드로이드 스튜디오를 업데이트하고 플러터 플러그인을 설치해보았습니다. 추가된 플러그인을 통해 샘플 프로젝트를 만들고 실행을 해보았지만 예상대로 문제가 발생했고, 안드로이드 가상 장치에서 시험을 해볼 수 없었습니다. 무슨 문제가 있었던 것일까요?

 

안드로이드 스튜디오에서 플러터 프로젝트를 생성하고 기본 샘플 앱을 가상 안드로이드 기기로 실행했을때 발생한 에러 화면입니다. 뭔가 SDK와 관련된 라이센스가 제대로 적용이 안된 것 같은 에러메세지입니다. 바로 터미널을 실행하여 플러터 닥터 flutter docter 명령을 통해 문제점을 확인해 보았습니다. 명령은 터미널에서 flutter docter 를 입력하여 수행합니다. 

 

초록색 체크표시가 된 것들은 문제가 없는 부분들입니다. 느낌표로 출력된 내용을 보니 비주얼 스튜디오 코드를 위한 플러터 환경 구성 이후 변경된 것들이 좀 있어 보입니다. 가장먼저 Android toolchain 항목에 대한 명령을 통해 첫번째 문제를 해결해 보겠습니다. 

flutter doctor --android-licenses

 

위의 플러터 닥터 명령은 동의해야 하는 약관, 라이센스에 대한 확인을 해주는 명령입니다. 실행후 나오는 내용을 살펴보고 (영어입니다 -_-;) 동의한다는 의미로 y 키를 몇 번 눌러주면 됩니다. 다시 닥터를 실행해서 처리가 잘 되었는지 보겠습니다. 

오호라. 첫번째 Android toolchain 항목도 이제 초록색 체크로 바뀌었습니다. 플러터로 개발된 코드를 iOS 에서 실행할 수 있도록 하기 위해서는 Xcode 환경도 준비가 되어 있어야 합니다. 지난번에도 CocoaPods 설치하느라 고생했는데... 그래도 다시 한 번 해보았습니다. 

#  sudo gem install cocoapods
Password:
Fetching i18n-1.8.9.gem
Fetching tzinfo-1.2.9.gem
Fetching activesupport-5.2.4.5.gem
Fetching nap-1.1.0.gem
Fetching fuzzy_match-2.0.4.gem
Fetching concurrent-ruby-1.1.8.gem
...
...
Parsing documentation for gh_inspector-1.1.3
Installing ri documentation for gh_inspector-1.1.3
Parsing documentation for ruby-macho-1.4.0
Installing ri documentation for ruby-macho-1.4.0
Parsing documentation for cocoapods-1.10.1
Installing ri documentation for cocoapods-1.10.1
Done installing documentation for concurrent-ruby, i18n, thread_safe, tzinfo, activesupport, nap, fuzzy_match, httpclient, algoliasearch, ffi, ethon, typhoeus, netrc, public_suffix, addressable, cocoapods-core, claide, cocoapods-deintegrate, cocoapods-downloader, cocoapods-plugins, cocoapods-search, cocoapods-trunk, cocoapods-try, molinillo, atomos, CFPropertyList, colored2, nanaimo, xcodeproj, escape, fourflusher, gh_inspector, ruby-macho, cocoapods after 25 seconds
34 gems installed

 

자, 코코아포드 관련한 패키지들의 추가도 끝났으니 다시 flutter docter 를 실행해 봐야겠죠?

 

에러 메세지가 확~ 사라졌습니다. 이제 마지막으로 남은 것은 안드로이드 스튜디오에서 플러그인을 설치하는 일입니다. 에..? 플러그인? 분명히 설치했다고 생각했는데... 무슨 문제일까요? 일단 에러 메세지를 무시하고 코드를 안드로이드 에뮬레이터에서 실행해 보겠습니다. 희안하게도 문제 없이 실행이 됩니다. 

 

어렵지 않죠? 네, 저는 어렵습니다 ㅎㅎ. 일단 동작이 잘 되는 것을 확인했으니, 본격적으로 뭔가를 만들어 봐야겠습니다!

728x90
728x90

개발을 하던 다른 트러블 슈팅을 하던 기기의 패킷을 추출해야 하는 경우들이 많습니다. Mac 을 사용하는 경우 rvi (Remote Virtual Interface) 를 이용해서 기기를 연결해서 쉽게 와이어샤크 Wireshark 같은 물건으로 패킷을 캡쳐할 수 있습니다. 말 그대로 가상 네트워크 인터페이스로 iOS 기기를 설정하기 때문이죠.

개인 기기로 아이폰을 쓰다보니 안드로이드는 샤오미 홍미4 이후 오랫동안 쓴적이 없었습니다. 그나마도 딸래미 학교 들어가면서 비상연락용 겸 슬랙 서적 집필할 때 화면 캡쳐용으로 산거라 진심을 다해서 써보지도 않았습니다. 허나, 현실에서는 안드로이드 환경의 패킷을 확인해야 하는 일이 종종 생기더군요.


ADB, 안드로이드 디버그 브릿지

이유는 잘 기억나지 않지만 제 Mac 에도 안드로이드 스튜디오 Android Studio 가 이미 설치되어 있었습니다 -_-;; ADB 는 Android SDK 개별 설치 혹은 Android Studio 설치시 SDK 에 딸려서 설치되는 디버그 툴인 것 같습니다. 패킷을 뜨기 위해 기기를 연결할 필요가 있었는데요 (사실은 NOX 로 기기 에뮬레이션해서...) ADB 가 그냥 실행이 되지는 않더군요.

Android Studio 가 정상적으로 동작하고 있다면 ADB 는 어딘가에 잘 설치가 되어 있는 상태입니다. 제 경우에는 아래의 Path 에서 해당 내용을 확인할 수 있었습니다. 아마 대부분 비슷한 경로에 설치가 되어 있을거라 생각합니다. 

% pwd
/Users/nopd/Library/Android/sdk/platform-tools

 

Path 로 경로 잡아주기

보통 SDK 가 설치되면 자동으로 Path 를 설정해 주는 경우가 많은데 Android SDK 는 그러지 않나 봅니다. (혹은 제가 영어로 나온 메세지를 놓친 것일지도... 속닥속닥...) 제 경우 필요한 터미널 환경 설정을 .bash_profile 에 하고 있어서 아래와 같이 Android SDK 의 Platform tools 경로를 추가해 주었습니다. 이렇게 해주고나니 어디서든 adb 를 실행할 수 있게 되었습니다 ㅎㅎ 

# Setting PATH for Android Platform Tools (esp for ADB)
export PATH="${PATH}:/Users/nopd/Library/Android/sdk/platform-tools"

그럼! 즐거운 디버깅 되시길 기원합니다. 이제 저는 NOX 와 씨름하러...

728x90
728x90

이제 본격적으로 프로젝트의 내용물을 채워보도록 하겠습니다. 별도의 외부 데이터베이스를 사용하지 않고 기본적으로 제공되는 파일 기반의 데이터베이스인 Sqlite 를 그대로 사용하도록 하겠습니다. 데이터베이스를 쓰기 위해서 먼저 기본 테이블을 생성해야 하는데요, Django 는 데이터베이스를 이용하는 것을 전제로 사용자와 사용자 권한 그룹 테이블을 알아서 만들어 주도록 되어있습니다. 

 

기본 테이블의 생성

기본 테이블을 생성하거나 프로젝트에 필요한 테이블을 생성하는 것 모두 manage.py 가 제공하는 명령어를 이용할 수 있습니다. 기본 테이블의 구조는 미리 정의가 되어 있기 때문에 모델을 만드는 작업을 하지 않고 사용이 가능합니다. 프로젝트의 루트 경로에서 manage.py migrate 명령을 사용하여 기본 테이블인 admin, auth, contenttypes, sessions 의 4개 테이블을 생성할 수 있습니다. 

% python3 manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying sessions.0001_initial... OK

migrate 명령이 수행되고 나면 settings.py 에 지정된 기본 데이터베이스 정보에 따라 Sqlite 용 파일이 프로젝트 루트 경로에 생성된 것을 보실 수 있습니다. 추후 Django 에 익숙해져 외부 데이터베이스를 사용하는 경우에는, 해당 데이터베이스 인스턴스에 4가지 테이블이 생성된다고 보시면 되겠습니다. 

 

프로젝트용 테이블의 생성 

기본 테이블은 Django 를 이용한 과제의 공통 테이블의 성격입니다. 수퍼 유저의 정보와 같은 것들이 이곳에 저장되는 것이지요. 실제 프로젝트에서 사용할 테이블을 정의하고 생성해야 하겠죠? 지난 포스팅 이후 뭘 만들어 볼까 고민하다가... 인터넷 서핑을 하면서 마음에 드는 이미지를 모아두는 서비스를 만들어 보면 어떨까 생각을 해보았습니다. (그닥 재미있어 보이진 않는군요...)

이미지의 이름 (Title) 과 이미지의 경로 (URL) 이고, 추후 검색 기능등을 넣기 위해 태그 (Tags) 정보를 입력받아 저장해보겠습니다. 지난 시간에 추가한 어플리케이션인 myfirstapp 폴더에 생성된 여러 파일들 중 models.py 를 열겠습니다. 이 파일에는 어플리케이션이 사용할 데이터, 테이블의 구조가 기술되며 이를 기반으로 manage.py 가 데이터베이스에 테이블 생성 작업을 대행해주기도 합니다. 

물론 별도로 데이터베이스를 수정하고 내용을 models.py 에 반영하는 것도 가능하지만 models.py 를 먼저 수정하고 manage.py 를 이용해서 데이터베이스 작업을 하는 것이 초보자에게는 좋다고 생각합니다. 사실 회사에서 과제를 진행하면서 migrate 과정에 대한 의문이 좀 많았는데 원격지의 리얼 데이터베이스를 쓰는 경우에는 migrate 을 잘 활용하는 것이 DBA 의 눈도 피할 수 있어서 좋을 것 같군? 하는 생각도 좀 들긴 합니다. 

 

이번 포스팅에서는 테이블 구조를 기술할 때 사용하는 django.db.models.Model 클래스를 자세히 살펴보지는 않겠습니다. 아직 공부를 못한 것도 있고 (퍽퍽...) 일단은 과제 하나를 잘 수행해 보는 것이 좋다고 생각하기 때문입니다 (후훗). 눈으로 보더라도 최대 길이라던가 빈 값의 허용, null 도 허용할 것인가와 같은 우리가 데이터베이스에서 테이블을 만들때 입력하는 정보들이 대부분 기술된다고 보시면 되겠습니다. 

Admin 사이트에 생성한 테이블 반영

admin.py 를 수정하면 생성한 테이블 정보를 django 가 제공하는 기본 어드민 페이지 (0.0.0.0:8000/admin) 에서 관리하거나 간단한 데이터 입출력 작업을 할 수 있게 됩니다. 지난 포스팅에서 이야기 했는지 기억이 잘 안납니다만 php 에서 쓰는 phpmyadmin 과 같은 역할이라고 생각하시면 편합니다. 우리가 생성한 어플리케이션인 myfirstapp 폴더 하위의 admin.py 를 열어서 아래와 같이 수정해 보겠습니다. 

 

테이블을 Sqlite 데이터베이스에 반영하려면 manage.py 가 제공하는 makemigrations 와 migrate 명령을 사용하게 됩니다. makemigrations 는 migrate 명령이 이해할 수 있도록 models.py 에 기술된 내용을 확인하고 현재의 데이터베이스와 비교하여 변경이 필요한 부분을 추출, python 코드로 만드는 역할을 수행합니다. migrate 은 이렇게 정리된 내용을 실제로 데이터베이스에 반영하는 역할을 하는 것이겠죠?

명령을 수행하기전에 어플리케이션 폴더인 myfirstapp 하위의 migrations 폴더를 살펴보면 __init__.py 파일만 존재하고 아무런 내용이 없는 것을 확인할 수 있습니다. makemigrations 명령을 수행한 후에 해당 폴더의 내용들이 어떻게 바뀌는지 살펴보도록 하겠습니다. 

 

명령을 수행하고 나면 myfirstapp/migrations 폴더에 0001_initial.py 라는 파일이 생성된 것을 볼 수 있습니다. 느낌은 첫번째 마이그레이션 작업이라는 느낌이죠? 이 파일을 열고 내용을 살펴보면 데이터베이스 작업에 필요한 파일로 조금전에 models.py 에 업데이트 했던 내용들이 들어가 있는 것을 확인할 수 있습니다. 

% python3 manage.py makemigrations
Migrations for 'myfirstapp':
  myfirstapp/migrations/0001_initial.py
    - Create model ImageCollector

 

이제 manage.py 의 migrate 명령으로 생성된 마이그레이션 작업 파일을 수행하여 데이터베이스에 반영되도록 하겠습니다. 기본 테이블로 생성한 admin, auth, contenttypes, sessions 에 대해서도 변경 사항이 있는지 점검하는 것을 볼 수 있습니다. ImageCollector 모델을 만들면서 지정한 max_length 지정 값은 auth 테이블에도 업데이트가 필요한 모양입니다. 알아서 잘 챙겨주니 참 고맙습니다. :-)

% python3 manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, myfirstapp, sessions
Running migrations:
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying myfirstapp.0001_initial... OK

 

이렇게 이번 포스팅에서는 기본 테이블을 생성하고 프로젝트에서 사용할 테이블을 생성해 보았습니다. 이렇게 만든 테이블을 확인하는 쉬운 방법은 장고가 제공하는 Admin 사이트를 이용하는 것입니다. 다음 포스팅에서는 Admin 사이트 접근을 위한 수퍼유저 계정의 생성을 해보고 생성된 ImageCollector 테이블에 간단한 샘플 데이터를 넣어보도록 하겠습니다. 

728x90

+ Recent posts