flask의 테스트 코드를 실행할 때 사용되는 툴은 다음과 같다.


$ tox -e flake8,py27



tox는 표준 툴이다.

https://tox.readthedocs.io/en/latest/




pyenv를 사용하고 있다면 다음과 같이 설치후 사용할 수 있다.


pip install -r requirements.txt -i http://proxy.google.com/pypi/simple/ --trusted-host proxy.google.com

~/.pyenv/shims/tox -e flake8,py27


Posted by 김용환 '김용환'


아래와 같이 select의 컬럼과 from의 테이블이 서로 다르다.(사실 이게 되기도 한다)


SELECT distinct kibanaauth_esidx.esidx

FROM kibanaauth_role role



이전 쿼리는 kibanaauth_role와 kibanaauth_esidx가 다르기 때문에 조인을 할 수 없다.


sql_alchemy의 query()를 join()과 함께 쓸 때는 

내부적으로 SQL의 select와 from 뒤에 query() 매개 변수에 포함되는 모델의 테이블을 무조건 적용하게 된다.







그래서 아래와 같이 select와 from을 동일한 테이블이 나오도록 쿼리를 수정한 후,, 


SELECT DISTINCT kibanaauth_esidx.esidx AS kibanaauth_esidx_esidx

FROM kibanaauth_esidx 



아래와 같이 sql_alchemy 문을 만들어서 테스트해보니. 조인이 된다.


aaa = session.query(LogAuthServiceTag.esidx).distinct() \

                    .join(LogAuthRoleServiceTag, LogAuthServiceTag.id == LogAuthRoleServiceTag.esidx_id) \

                    .join(LogAuthRole, LogAuthRole.id == LogAuthRoleServiceTag.role_id) \

                    .join(LogAuthRoleUser, LogAuthRoleUser.role_id == LogAuthRole.id) \

                    .join(LogAuthUser, LogAuthUser.id == LogAuthRoleUser.user_id) \

                    .filter(LogAuthUser.userid == userid)



query() 문에 여러 모델을 넣어도 sql_alchemy가 내부적으로 조합하기 때문에 

상황에 따라서는 from이 이상하게 나올 수 있다. 


복잡하게 sql_alchemy 를 사용할 때는 SQL 문장을 디버깅하면서 확인해야 한다.





다시 얘기하면. 



session.query(Post) \

       .join(User, Post.author_id == User.id)



이 문장은 다음과 같이 변환될 것이다.  query()의 매개 변수는 select, from으로 넘어갔다(항상 그런 것은 아니지만, 대개 그렇다.)


select post

from post 

inner join user 

   on post.author_id == user.id




Posted by 김용환 '김용환'



python의 sql_alchemy에서 3개의 테이블을 조인하고 특정 사람의 권한을 보고 싶은 쿼리가 있다.



select role.role

from 

(user join roleuser on user.id = roleuser.user_id)

left join role role on roleuser.role_id = role.id

where user.userid = 'sma'



python의 sql_alchemy는 다음과 같이 코딩한다.



                instance = session.query(Role.role)\

                    .join(RoleUser, User.id == RoleUser.user_id) \

                    .outerjoin(Role, RoleUser.role_id == Role.id) \

                    .filter(User.userid == userid)



조인된 다른 테이블을 보려면 다음과 같다.


                instance = session.query(Role.role)\

                    .join(RoleUser, User.id == RoleUser.user_id) \

                    .outerjoin(Role, RoleUser.role_id == Role.id) \

                    .filter(User.userid == userid) \

                   .add_entity(RoleUser) \

                   .add_entity(User) \

Posted by 김용환 '김용환'



파이썬의 sql_alchemy에서 SQL을 디버깅하려면 다음과 같이 str을 사용해야 한다..



                instance = session.query(...) \

                    .filter(...) \

                    .outerjoin((..))


                print(str(instance))

                

Posted by 김용환 '김용환'


flask 개발 중에 다음과 같은 에러를 발견했다.


  File "/Users/samuel.kim/.pyenv/versions/2.7.12/lib/python2.7/site-packages/flask/app.py", line 1051, in add_url_rule

    'existing endpoint function: %s' % endpoint)

AssertionError: View function mapping is overwriting an existing endpoint function: xxx




이 이유는 서로 다른 URL에서 동일한 Controller 클래스를 사용하면 발생한다.


즉, 다음과 같은 형태로 호출되는 것을 의미한다.



api.add_resource(AuthServiceController,'/authorization') 


api.add_resource(AuthServiceController,'/authentication') 




각 URL 마다 서로 다른 Controller를 수정하면 정상적으로 동작된다. 

Posted by 김용환 '김용환'

Play2 Frame에는 괜찮은 인증이 있지만.. 간단하게 구현한 인증 방식(basic authentication)이다.



application.conf


play.http.filters = filters.Filters



Filters.java

package filters

import javax.inject.Inject

import play.api.http.{DefaultHttpFilters, EnabledFilters}

class Filters @Inject() (
defaultFilters: EnabledFilters,
logging: LoggingFilter,
authFilter : AuthFilter,
) extends DefaultHttpFilters (defaultFilters.filters :+ logging :+ authFilter : _*)



AuthFilter.java

package filters

import javax.inject.Inject

import akka.stream.Materializer
import play.api.mvc._
import scala.concurrent.{ExecutionContext, Future}

class AuthFilter @Inject() (implicit val mat: Materializer, ec: ExecutionContext) extends Filter {

def apply(nextFilter: RequestHeader => Future[Result])
(requestHeader: RequestHeader): Future[Result] = {
if (!requestHeader.path.startsWith("/login") && requestHeader.headers.get("X-Auth-User").isEmpty) {
Future(Results.Forbidden)
} else { // AuthService.authenticate(requestHeader.headers.get("X-Auth-User"))
nextFilter(requestHeader).map { result =>
result
}
}
}
}


여기에 X-Auth-User 정보를 읽고 임의의 AuthService라는 클래스를 사용해 매번 호출마다 인증을 해볼 수도 있다. 









Posted by 김용환 '김용환'

WSJ에서 한국의 가계 부채의 심각성을 알렸다. 노르웨이와 한국이 높은 수준의 증가세를 보이고 있다고 한다.



https://www.wsj.com/articles/household-debt-sees-quiet-boom-across-the-globe-1518969601



In all, 10 economies have debts above that threshold and rising fast, with the others including New Zealand, South Korea, Sweden, Thailand, Hong Kong and Finland.

In Switzerland, Australia, New Zealand and Canada, the household debt-to-GDP ratio has risen between five and ten percentage points over the past three years, paces comparable to the U.S. in the run-up to the housing bubble. In Norway and South Korea they’re rising even faster.


(조정은 항상 있게 마련..)



Posted by 김용환 '김용환'

(자바스크립트/웹 초짜의 슬픔)



https://github.com/visionmedia/superagent/issues/1091



set-cookie(response header 값)는 react/javascript에서 핸들링할 수 없다. 


오직 content-type header만 볼 수 있는 것 같다. 그래서 처음 custom 인증(또는 jwt)할 때는 header가 아닌 response로 결과를 받아야 되요.


즉 cookie는 브라우져에서 처리하는 구조라 자바스크립트에서는 request를 자유자재로 핸들링을 못하는 구조였다.



Posted by 김용환 '김용환'



MovieLens의 ratings.csv 파일을 다운로드하는 방법



먼저 파일이 어디 있는지 확인한다.


http://files.grouplens.org/datasets/movielens/ml-20m-README.html


Summary

This dataset (ml-20m) describes 5-star rating and free-text tagging activity from MovieLens, a movie recommendation service. It contains 20000263 ratings and 465564 tag applications across 27278 movies. These data were created by 138493 users between January 09, 1995 and March 31, 2015. This dataset was generated on October 17, 2016.

Users were selected at random for inclusion. All selected users had rated at least 20 movies. No demographic information is included. Each user is represented by an id, and no other information is provided.

The data are contained in six files, genome-scores.csvgenome-tags.csvlinks.csvmovies.csvratings.csv and tags.csv. More details about the contents and use of all these files follows.

This and other GroupLens data sets are publicly available for download at http://grouplens.org/datasets/.



링크를 따라 들어가서 ml-20m.zip를 다운로드한다.



바로 접근하려면 다음 링크로 접속한다. 


https://grouplens.org/datasets/movielens/



저 파일 안에 ratings.csv 파일이 있다.



Posted by 김용환 '김용환'




스칼라 Play 프레임워크의 인증/권한 문서 참조자료이다. 



https://www.playframework.com/documentation/2.6.x/ScalaActionsComposition#Authentication


https://www.playframework.com/documentation/2.6.x/api/scala/index.html#play.api.mvc.Security$$AuthenticatedBuilder$


https://github.com/playframework/playframework/blob/2.6.x/framework/src/play/src/main/scala/play/api/mvc/Security.scala


http://fizzylogic.nl/2016/11/27/authorize-access-to-your-play-application-using-action-builders-and-action-functions/



Posted by 김용환 '김용환'