나는 mongodb의 List 타입을 $in 으로 검색하려고 하는데..이게 지원안된다.


태그 같은건 ["한국", "여행"] 이런식으로 list 타입으로 관리되고, 해쉬태그처럼 사용하는거라 $in 검색을 하고 싶은데 

(=성능상 contains 하면 데이터 많으면 힘들다)


관계형 데이터베이스에서는 이런 N개의 데이터는 없었기 때문일까? 기본적으로는 지원안된다.


column_searchable_list = ('tags', )  # Document 를 ListField(StringField()) 필드로 구성했다고 했을때...


이걸 하려면 ModelView를 고쳐서 쓰면 된다.

참고로 기존 코드만 배끼고 저 파란부분만 추가해서 오버라이딩 한거다.

이 모델뷰를 이용해 구성하면 list<stringField> 구성에 대해서는 $in 검색을 한다.


# -*- coding: utf-8 -*-
import sys

import mongoengine
from flask_admin.contrib.mongoengine.tools import parse_like_term


reload(sys)
sys.setdefaultencoding('utf-8')
from flask_admin.contrib.mongoengine import ModelView
from flask_admin._compat import string_types
from mongoengine import ListField

class CustomModelView(ModelView):
    """
        list 타입 검사 안되는 문제를 해결
    """
    def init_search(self):
        if self.column_searchable_list:
            for p in self.column_searchable_list:
                if isinstance(p, string_types):
                    p = self.model._fields.get(p)  # convert type

                if p is None:
                    raise Exception('Invalid search field')

                # list type (my code)
                if isinstance(p, ListField):
                    p_sub = p.field
                    if type(p_sub) in self.allowed_search_types:
                        self._search_fields.append(p)
                        continue

                field_type = type(p)
                if (field_type not in self.allowed_search_types):
                        raise Exception('Can only search on text columns. ' +
                                        'Failed to setup search for "%s"' % p)
                self._search_fields.append(p)
        return bool(self._search_fields)


    def _search(self, query, search_term):
        op, term = parse_like_term(search_term)
        criteria = None

        for field in self._search_fields:
            if isinstance(field, ListField):
                flt = {'%s__%s' % (field.name, 'in'): (term,)}
            else:
                flt = {'%s__%s' % (field.name, op): term}


            q = mongoengine.Q(**flt)

            if criteria is None:
                criteria = q
            else:
                criteria |= q
 

            return query.filter(criteria)


flask-admin을 사용하면 쉽게 admin페이지를 만들수 있다.

그런데 데이터를 볼때 일부 필드 데이터는 다른방식으로 표현하고 싶다.


예를 들면,


  * 주소는 <A> 태그를 써거 링크를 건다거나

  * 이미지는 <IMG> 태그를 써서 이미지를 관리페이지에서 본다거나..


나는 스토리지를 몽고엔진을 썻으므로 이걸 예로 들겠다.


img 필드에는 이미지 url

link 에는 링크 url 이 있다고 치자


그럼 ModelView를 구성할때

column_formatters 를 이용해 다음과 같이 구성하면 원하는대로 볼수 있다.


from flask_admin.contrib.mongoengine import ModelView

from markupsafe import Markup


class SampleView(ModelView):

    ...

column_list = ('title', 'img', 'body', 'link') column_formatters = dict(img=lambda v, c, m, p: Markup('<img style="width:100px;height:100px"" src="'+m.img+'"/>'), link=lambda v, c, m, p: Markup('<a href="'+m.link+'" target="_blink"/>이동</a>'), )



귀찮아서 캡쳐는 생략한다.

스프링부트의 기본 로깅은 로그백인가 뭐시긴가여서 pom.xml 에서 이걸 해줘야 log4j를 쓴다.

 <!--logging for Log4j-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j</artifactId>
</dependency>


그리고 로컬파일에 있는 log4j 설정을 로딩하려고 하는데 잘안된다.

인터넷 뒤져보면 가이드된게 이런식인데 안된다.


java ... -Dlog4j.configuration=file:/test/conf/log4j.properties ...


스프링부트에서 외부 log4j 설정이 먹은 성공한 방법은 --logging.config 옵션을 쓴것이다.

물론 이건 스프링부트 한정이고, 일반적인 상황은 위에 적은 방법이 맞는것 같다.



java ... --logging.config=file:/test/conf/log4j.properties


끝.

+ Recent posts