RE with FLASK-Searcher 이식하기

들어가기 전에

Cutter와 Finder도 내일 이식하긴 할건데, 내일 이식하는 부분에서 FASTA/Genbank 파일 올리는거랑 결과 저장 기능은 빠진다. 그래서 원본 코드에 있던 with 어쩌고를 일단 작성 없이 서버로 보내서 텍스트 에리어에서 출력하는 걸 일차적으로 진행하고 저장-업로드 순으로 할 예정. FASTA/Genbank는 JS로 파일 받아서 파이썬으로 넘겨서 열 생각인데 그거 관련해서 로직 처리가 좀 필요하고(뼈대를 보면 라디오 버튼이다) 반대로 텍스트 파일은 파이썬에서 만들어서 JS로 넘길 생각이다. 텍스트 파일은 만들어준 거 받아서 버튼 누르면 다운로드 되게 하면 끝임.

본격 대공사 썰 푼다

로직 이식 전단계

일단 이전에 만들었던 뼈대를 먼저 보자.

원본 코드에서는 이거 일일이 타이핑으로 입력 받던건데, 죄다 라디오버튼 때려박았다. 그리고 라디오버튼에는 당연하게도 이에 상응하는 값이 할당되어 있지. 아니 대공사 썰 푼다면서 웬 라디오버튼? 이게 일차적으로 JS가 할 일이다. 라디오버튼에 할당된 값(value=”이거”)이랑 입력값을 app.py(파이썬)으로 넘겨주는 일. 여기서 JS가 넘겨줄 인자는 

  1. 입력창에 있는 문자열과
  2. 저 어마무시한 검색 필터들

크게 이 두 가지다. 그리고 나중에 로직이 다 돌아가고 나면

  1. 결과값을 받아서
  2. 깔쌈하게 뽑는다

이게 JS의 일이다. 그럼 app.py로 값은 어떻게 넘기느냐… 그걸 Ajax가 한다. 즉, jQuery는 저거때문에 있는거고 이 코드에서 Ajax를 뺀 다른 기능들은 다 바닐라JS로 한 것들이다. 심지어 저기 있는 탭조차. 

function searchFilter() {
    const search_method = document.getElementsByName('search_val');
    console.log(search_method)
}

일단 이렇게 하면 값은 나오는데 문제가 뭐냐, 이거 라디오버튼이라서 선택한 값만 넘겨야 한다. 그럼 어캄?

function searchFilter() {
    const search_method = document.getElementsByName('search_val');
    for (let i = 0;i < search_method.length;i++) {
        if (search_method[i].checked == true) {
            console.log(search_method[i].value)
        }
    }
}

이렇게요. 그리고 이 if를 세 개 줘야 한다.

function searchFilter() {
    const search_method = document.getElementsByName('search_val');
    const NEB_filter = document.getElementsByName('option_NEB');
    const cut_filter = document.getElementsByName('option_cut');

    for (let i = 0;i < search_method.length;i++) {
        if (search_method[i].checked == true) {
            console.log(search_method[i].value);
        }
    }
    for (let i = 0;i < NEB_filter.length;i++){
        if (NEB_filter[i].checked == true) {
            console.log(NEB_filter[i].value);
        }
    }
    for (let i = 0;i < cut_filter.length;i++){
        if (cut_filter[i].checked == true) {
            console.log(cut_filter[i].value)
        }
    }
}

짜잔… 그리고 Ajax를 소환해보자.

let search_method_val = '';
let NEB_filter_val = '';
let cut_filter_val = '';
function searchFilter() {
    const search_method = document.getElementsByName('search_val');
    const NEB_filter = document.getElementsByName('option_NEB');
    const cut_filter = document.getElementsByName('option_cut');

    for (let i = 0; i < search_method.length; i++) {
        if (search_method[i].checked == true) {
            search_method_val = search_method[i].value;
        }
    }
    for (let i = 0; i < NEB_filter.length; i++) {
        if (NEB_filter[i].checked == true) {
            NEB_filter_val = NEB_filter[i].value;
        }
    }
    for (let i = 0; i < cut_filter.length; i++) {
        if (cut_filter[i].checked == true) {
            cut_filter_val = cut_filter[i].value
        }
    }
    $.ajax({
    type: "POST",
    url: "/searcher",
    data: {NEB_give: NEB_filter_val, cut_give: cut_filter_val, search_give: search_method_val},
    success: function (response) {
        alert(response['msg'])
    }
})
}

여기다가 변수 하나를 더 얹으면 4개를 넘길 수 있다.

@app.route('/searcher', methods=['POST'])
def searcher():
    NEB_receive = request.form['NEB_give']
    cut_receive = request.form['cut_give']
    search_receive = request.form['search_give']
    message = '{},{},{}'.format(NEB_receive,cut_receive,search_receive)
    return jsonify({'msg': message})

그리고 받아오면 본격적인 이식이 시작된다.

대공사 포인트

위에서 기존 코드로 입력받던 것들을 라디오버튼으로 바꿨다고 했는데, 그거 말고도 변경점이 하나 더 있다. 원래 코드에서는 print문으로 출력해줬지만, 쟤는 app.py에서 다 만들고 나면 결과를 다시 JS에게 넘겨줘야 한다. 그러니까 단순히 print문으로 되어있던 걸 처리하는 과정이 필요하다.

@app.route('/searcher', methods=['POST'])
def searcher():
    enzyme_table = pd.read_csv('/home/koreanraichu/restriction_merge.csv')
    NEB_receive = request.form['NEB_give']
    cut_receive = request.form['cut_give']
    search_receive = request.form['search_give']
    keywd_receive = request.form['keywd_give']

    def SeqtoString(a):
        a = enzyme_table.sequence[(enzyme_table['Enzyme'] == keywd_receive)]
        a = a.to_string(index=False)
        a = str(a).strip()
        return a

    def SitetoString(a):
        a = enzyme_table.restriction_site[(enzyme_table['Enzyme'] == keywd_receive)]
        a = a.to_string(index=False)
        a = str(a).strip()
        return a

    def NEB_selling(a):
        a = enzyme_table.NEB_sell[(enzyme_table['Enzyme'] == keywd_receive)]
        a = a.to_string(index=False)
        a = str(a).strip()
        return a

    # 함수 가즈아!!!

    if cut_receive == 'sticky':
        enzyme_table = enzyme_table[enzyme_table['cut_feature'] == 'Sticky']
        enzyme_table.reset_index(inplace=True)
        cut_feature = 'Sticky end'
    elif cut_receive == 'blunt':
        enzyme_table = enzyme_table[enzyme_table['cut_feature'] == 'Blunt']
        enzyme_table.reset_index(inplace=True)
        cut_feature = 'Blunt end'
    elif cut_receive == 'nicked':
        enzyme_table = enzyme_table[enzyme_table['cut_feature'] == 'Nicked']
        enzyme_table.reset_index(inplace=True)
        cut_feature = "Nicked"
    else:
        cut_feature = "W/O filter"
        pass
    if NEB_receive == 'NEB':
        enzyme_table = enzyme_table[enzyme_table['NEB_sell'] == 'Yes']
        enzyme_table.reset_index(inplace=True)
        NEB_filter = 'NEB only'
    else:
        NEB_filter = 'All'
        pass
    if search_receive == 'name':
        pass
    elif search_receive == 'sequence':
        pass
    else:
        pass
    return jsonify({'msg': '입력되었습니다!'})

근데 함수를 이렇게 써도 되는겨? 아무튼… print를 전부 변수로 바꾸고 문자열 할당했다.

@app.route('/searcher', methods=['POST'])
def searcher():
    enzyme_table = pd.read_csv('/home/koreanraichu/restriction_merge.csv')
    NEB_receive = request.form['NEB_give']
    cut_receive = request.form['cut_give']
    search_receive = request.form['search_give']
    keyword_receive = request.form['keyword_give']

    def SeqtoString(a):
        a = enzyme_table.sequence[(enzyme_table['Enzyme'] == keyword_receive)]
        a = a.to_string(index=False)
        a = str(a).strip()
        return a

    def SitetoString(a):
        a = enzyme_table.restriction_site[(enzyme_table['Enzyme'] == keyword_receive)]
        a = a.to_string(index=False)
        a = str(a).strip()
        return a

    def NEB_selling(a):
        a = enzyme_table.NEB_sell[(enzyme_table['Enzyme'] == keyword_receive)]
        a = a.to_string(index=False)
        a = str(a).strip()
        return a

    # 함수 가즈아!!!

    if cut_receive == 'sticky':
        enzyme_table = enzyme_table[enzyme_table['cut_feature'] == 'Sticky']
        enzyme_table.reset_index(inplace=True)
        cut_feature = 'Sticky end'
    elif cut_receive == 'blunt':
        enzyme_table = enzyme_table[enzyme_table['cut_feature'] == 'Blunt']
        enzyme_table.reset_index(inplace=True)
        cut_feature = 'Blunt end'
    elif cut_receive == 'nicked':
        enzyme_table = enzyme_table[enzyme_table['cut_feature'] == 'Nicked']
        enzyme_table.reset_index(inplace=True)
        cut_feature = "Nicked"
    else:
        cut_feature = "W/O filter"
        pass
    if NEB_receive == 'NEB':
        enzyme_table = enzyme_table[enzyme_table['NEB_sell'] == 'Yes']
        enzyme_table.reset_index(inplace=True)
        NEB_filter = 'NEB only'
    else:
        NEB_filter = 'All'
        pass

    if search_receive == 'name':
        find_seq = SeqtoString(keyword_receive)
        Site_seq = SitetoString(keyword_receive)
        NEB_sell = NEB_selling(keyword_receive)
        result_iso = ''
        result_neo = ''
        result_iso_list = []
        result_neo_list = []
        Iso = []
        Neo = []
        message_give =  "{0} | {1} | {2} | {3} | Input enzyme".format(keyword_receive, find_seq, Site_seq, NEB_sell)
        for i in range(len(enzyme_table)):
            DB_enzyme = str(enzyme_table['Enzyme'][i]).strip()
            DB_seq = str(enzyme_table['sequence'][i]).strip().upper()
            DB_site = str(enzyme_table['restriction_site'][i]).strip().upper()
            if find_seq == str(DB_seq) and DB_enzyme != keyword_receive:
                if Site_seq == DB_site:
                    Iso.append(DB_enzyme)
                    result_iso = "{0} | {1} | {2} | {3} | Isoschizomer".format(DB_enzyme, DB_seq, DB_site,
                                                                                   NEB_sell)
                    result_iso_list.append(result_iso)

                    # 인식하는 시퀀스와 자르는 방식이 같은 제한효소
                elif Site_seq != DB_site:
                    Neo.append(DB_enzyme)
                    result_neo = "{0} | {1} | {2} | {3} | Neoschizomer".format(DB_enzyme, DB_seq, DB_site,
                                                                                   NEB_sell)
                    result_neo_list.append(result_neo)
                    # 인식하는 시퀀스는 같으나 자르는 방식이 다른 제한효소
            elif find_seq == str(DB_seq) and DB_enzyme == keyword_receive:
                pass
            else:
                pass
    elif search_receive == 'sequence':
        find_seq = keyword_receive
        message_give = ("Searched by: {0}".format(keyword_receive))
        for i in range(len(enzyme_table)):
            DB_enzyme = str(enzyme_table['Enzyme'][i]).strip()
            DB_seq = str(enzyme_table['sequence'][i]).strip().upper()
            DB_site = str(enzyme_table['restriction_site'][i]).strip().upper()
            DB_NEB = str(str(enzyme_table['NEB_sell'][i]).strip())
            if find_seq == DB_seq:
                print("{0} | {1} | {2} | {3}".format(DB_enzyme, DB_seq, DB_site, DB_NEB))
        else:
            enzyme_RE = keyword_receive
            enzyme_RE = enzyme_RE.upper()
            enzyme_RE_2 = '^' + enzyme_RE
            message_give = ("Enzyme with start with {0}".format(enzyme_RE))
            for i in range(len(enzyme_table)):
                DB_enzyme = str(enzyme_table['Enzyme'][i]).strip()
                DB_seq = str(enzyme_table['sequence'][i]).strip().upper()
                DB_site = str(enzyme_table['restriction_site'][i]).strip().upper()
                DB_NEB = str(str(enzyme_table['NEB_sell'][i]).strip())
                if re.search(enzyme_RE_2, DB_enzyme):
                    print("{0} | {1} | {2} | {3}".format(DB_enzyme, DB_seq, DB_site, DB_NEB))
    return jsonify({'Message_give': message_give,'Result_iso':result_iso_list,'Result_neo':result_neo_list})

이건데(일단 이름 검색만 됨)

    if search_receive == 'name':
        find_seq = SeqtoString(keyword_receive)
        Site_seq = SitetoString(keyword_receive)
        NEB_sell = NEB_selling(keyword_receive)
        result_iso = ''
        result_neo = ''
        result_iso_list = []
        result_neo_list = []
        Iso = []
        Neo = []
        message_give =  "{0} | {1} | {2} | {3} | Input enzyme".format(keyword_receive, find_seq, Site_seq, NEB_sell)
        for i in range(len(enzyme_table)):
            DB_enzyme = str(enzyme_table['Enzyme'][i]).strip()
            DB_seq = str(enzyme_table['sequence'][i]).strip().upper()
            DB_site = str(enzyme_table['restriction_site'][i]).strip().upper()
            if find_seq == str(DB_seq) and DB_enzyme != keyword_receive:
                if Site_seq == DB_site:
                    Iso.append(DB_enzyme)
                    result_iso = "{0} | {1} | {2} | {3} | Isoschizomer".format(DB_enzyme, DB_seq, DB_site,
                                                                                   NEB_sell)
                    result_iso_list.append(result_iso)

                    # 인식하는 시퀀스와 자르는 방식이 같은 제한효소
                elif Site_seq != DB_site:
                    Neo.append(DB_enzyme)
                    result_neo = "{0} | {1} | {2} | {3} | Neoschizomer".format(DB_enzyme, DB_seq, DB_site,
                                                                                   NEB_sell)
                    result_neo_list.append(result_neo)
                    # 인식하는 시퀀스는 같으나 자르는 방식이 다른 제한효소

이 부분을 잘 보면 print문이 있어야 할 곳에 웬 메시지 리절트 이런 변수들이 있는 것을 볼 수 있다. 왜 이렇게 했냐고?

return jsonify({'Message_give': message_give,'Result_iso':result_iso_list,'Result_neo':result_neo_list})

얘때문임. Ajax로 다시 JS로 보내려면 JSON파일로 만들어야 하거든… 그래서 결과를 딕셔너리로 만든 다름 JSON으로 넘길거다. 

success : function (response) {
    var message = response['Message_give']
    var iso = response['Result_iso']
    var neo = response['Result_neo']
    let result = document.getElementById('search_result');
    result.innerText = message;
    for (let i = 0; i < iso.length; i++) {
        console.log(iso[i])
        result.innerText = iso[i]
    }
    for (let i = 0; i < neo.length; i++) {
        console.log(neo[i])
        result.innerText = neo[i]
    }
}

여기서 줄바꿈 안먹어서 개고생했는데(백틱 이스케이프 다 안됨)

success : function (response) {
    if (search_method_val == 'name') {
        let message = response['doc_result']['Message_give'];
        let iso = response['doc_result']['Result_iso'];
        let neo = response['doc_result']['Result_neo'];
        let result = document.getElementById('search_result');
        result.innerHTML = message;
        for (let i = 0; i < iso.length; i++) {
            result.innerHTML = result.innerHTML.concat("\n", iso[i])
        }
        for (let i = 0; i < neo.length; i++) {
            result.innerHTML = result.innerHTML.concat("\n", neo[i])
        }
    } else if (search_method_val == 'sequence') {
        let message = response['doc_result']['Message_give'];
        let same_seq = response['doc_result']['Result_seq'];
        let result = document.getElementById('search_result');
        result.innerHTML = message;
        for (let i = 0; i < same_seq.length; i++) {
            result.innerHTML = result.innerHTML.concat("\n", same_seq[i])
        }
    } else {
        let message = response['doc_result']['Message_give'];
        let spell = response['doc_result']['Result_spell'];
        let result = document.getElementById('search_result');
        result.innerHTML = message;
        for (let i = 0; i < spell.length; i++) {
            result.innerHTML = result.innerHTML.concat("\n", spell[i])
        }
    }
}

지나가던 분의 .concat()신공과 innerText 말고 innerHTML도 있잖아? 로 해⭐결!

전체 코드

app.py

@app.route('/searcher', methods=['POST'])
def searcher():
    enzyme_table = pd.read_csv('/home/koreanraichu/restriction_merge.csv')
    NEB_receive = request.form['NEB_give']
    cut_receive = request.form['cut_give']
    search_receive = request.form['search_give']
    keyword_receive = request.form['keyword_give']

    def SeqtoString(a):
        a = enzyme_table.sequence[(enzyme_table['Enzyme'] == keyword_receive)]
        a = a.to_string(index=False)
        a = str(a).strip()
        return a

    def SitetoString(a):
        a = enzyme_table.restriction_site[(enzyme_table['Enzyme'] == keyword_receive)]
        a = a.to_string(index=False)
        a = str(a).strip()
        return a

    def NEB_selling(a):
        a = enzyme_table.NEB_sell[(enzyme_table['Enzyme'] == keyword_receive)]
        a = a.to_string(index=False)
        a = str(a).strip()
        return a

    # 함수 가즈아!!!

    if cut_receive == 'sticky':
        enzyme_table = enzyme_table[enzyme_table['cut_feature'] == 'Sticky']
        enzyme_table.reset_index(inplace=True)
        cut_feature = 'Sticky end'
    elif cut_receive == 'blunt':
        enzyme_table = enzyme_table[enzyme_table['cut_feature'] == 'Blunt']
        enzyme_table.reset_index(inplace=True)
        cut_feature = 'Blunt end'
    elif cut_receive == 'nicked':
        enzyme_table = enzyme_table[enzyme_table['cut_feature'] == 'Nicked']
        enzyme_table.reset_index(inplace=True)
        cut_feature = "Nicked"
    else:
        cut_feature = "W/O filter"
        pass
    if NEB_receive == 'NEB':
        enzyme_table = enzyme_table[enzyme_table['NEB_sell'] == 'Yes']
        enzyme_table.reset_index(inplace=True)
        NEB_filter = 'NEB only'
    else:
        NEB_filter = 'All'
        pass

    global result_dic
    global result_iso
    global result_neo
    global result_seq
    global result_spell

    if search_receive == 'name':
        find_seq = SeqtoString(keyword_receive)
        Site_seq = SitetoString(keyword_receive)
        NEB_sell = NEB_selling(keyword_receive)
        result_iso = ''
        result_neo = ''
        result_iso_list = []
        result_neo_list = []
        result_dic = dict()
        message_give = ''
        Iso = []
        Neo = []
        message_give =  "{0} | {1} | {2} | {3} | Input enzyme".format(keyword_receive, find_seq, Site_seq, NEB_sell)
        for i in range(len(enzyme_table)):
            DB_enzyme = str(enzyme_table['Enzyme'][i]).strip()
            DB_seq = str(enzyme_table['sequence'][i]).strip().upper()
            DB_site = str(enzyme_table['restriction_site'][i]).strip().upper()
            if find_seq == str(DB_seq) and DB_enzyme != keyword_receive:
                if Site_seq == DB_site:
                    Iso.append(DB_enzyme)
                    result_iso = "{0} | {1} | {2} | {3} | Isoschizomer".format(DB_enzyme, DB_seq, DB_site,
                                                                                   NEB_sell)
                    result_iso_list.append(result_iso)

                    # 인식하는 시퀀스와 자르는 방식이 같은 제한효소
                elif Site_seq != DB_site:
                    Neo.append(DB_enzyme)
                    result_neo = "{0} | {1} | {2} | {3} | Neoschizomer".format(DB_enzyme, DB_seq, DB_site,
                                                                                   NEB_sell)
                    result_neo_list.append(result_neo)
                    # 인식하는 시퀀스는 같으나 자르는 방식이 다른 제한효소
            elif find_seq == str(DB_seq) and DB_enzyme == keyword_receive:
                pass
            else:
                pass
            result_dic = {'Message_give': message_give,'Result_iso':result_iso_list,'Result_neo':result_neo_list}
    elif search_receive == 'sequence':
        find_seq = keyword_receive
        result_seq = ''
        result_dic = dict()
        result_seq_list=[]
        message_give = "Searched by: {0}".format(keyword_receive)
        for i in range(len(enzyme_table)):
            DB_enzyme = str(enzyme_table['Enzyme'][i]).strip()
            DB_seq = str(enzyme_table['sequence'][i]).strip().upper()
            DB_site = str(enzyme_table['restriction_site'][i]).strip().upper()
            DB_NEB = str(str(enzyme_table['NEB_sell'][i]).strip())
            if find_seq == DB_seq:
                result_seq = "{0} | {1} | {2} | {3}".format(DB_enzyme, DB_seq, DB_site, DB_NEB)
                result_seq_list.append(result_seq)
            result_dic = {'Message_give':message_give,'Result_seq':result_seq_list}
    else:
        enzyme_RE = keyword_receive
        enzyme_RE = enzyme_RE.upper()
        enzyme_RE_2 = '^' + enzyme_RE
        result_spell=''
        result_spell_list = []
        result_dic = dict()
        message_give = "Enzyme with start with {0}".format(enzyme_RE)
        for i in range(len(enzyme_table)):
            DB_enzyme = str(enzyme_table['Enzyme'][i]).strip()
            DB_seq = str(enzyme_table['sequence'][i]).strip().upper()
            DB_site = str(enzyme_table['restriction_site'][i]).strip().upper()
            DB_NEB = str(str(enzyme_table['NEB_sell'][i]).strip())
            if re.search(enzyme_RE_2, DB_enzyme):
                result_spell = "{0} | {1} | {2} | {3}".format(DB_enzyme, DB_seq, DB_site, DB_NEB)
                result_spell_list.append(result_spell)
            result_dic = {'Message_give':message_give,'Result_spell':result_spell_list}
    return jsonify({'doc_result':result_dic})

JS

let search_method_val = '';
let NEB_filter_val = '';
let cut_filter_val = '';
let keyword_val = '';

function searchFilter() {
    const search_method = document.getElementsByName('search_val');
    const NEB_filter = document.getElementsByName('option_NEB');
    const cut_filter = document.getElementsByName('option_cut');
    keyword_val = document.getElementById('keywd').value;

    for (let i = 0; i < search_method.length; i++) {
        if (search_method[i].checked == true) {
            search_method_val = search_method[i].value;
        }
    }
    for (let i = 0; i < NEB_filter.length; i++) {
        if (NEB_filter[i].checked == true) {
            NEB_filter_val = NEB_filter[i].value;
        }
    }
    for (let i = 0; i < cut_filter.length; i++) {
        if (cut_filter[i].checked == true) {
            cut_filter_val = cut_filter[i].value
        }
    }

    $.ajax({
        type: "POST",
        url: "/searcher",
        data: {
            NEB_give: NEB_filter_val,
            cut_give: cut_filter_val,
            search_give: search_method_val,
            keyword_give: keyword_val
        },
        success: function (response) {
            if (search_method_val == 'name') {
                let message = response['doc_result']['Message_give'];
                let iso = response['doc_result']['Result_iso'];
                let neo = response['doc_result']['Result_neo'];
                let result = document.getElementById('search_result');
                result.innerHTML = message;
                for (let i = 0; i < iso.length; i++) {
                    result.innerHTML = result.innerHTML.concat("\n", iso[i])
                }
                for (let i = 0; i < neo.length; i++) {
                    result.innerHTML = result.innerHTML.concat("\n", neo[i])
                }
            }
            else if (search_method_val == 'sequence') {
                let message = response['doc_result']['Message_give'];
                let same_seq = response['doc_result']['Result_seq'];
                let result = document.getElementById('search_result');
                result.innerHTML = message;
                for (let i = 0;i < same_seq.length;i++) {
                    result.innerHTML = result.innerHTML.concat("\n", same_seq[i])
                }
            }
            else {
                let message = response['doc_result']['Message_give'];
                let spell = response['doc_result']['Result_spell'];
                let result = document.getElementById('search_result');
                result.innerHTML = message;
                for (let i = 0;i < spell.length;i++) {
                    result.innerHTML = result.innerHTML.concat("\n", spell[i])
                }
            }
        }
    })
}

그래서 결론

이름으로 검색
효소 시퀀스로 검색
그 뭐더라 그 X로 시작하는거

차후 추가할 것

검색결과 없을 때 보낼 텍스트(…) 및 검색 용어별 가이드(라디오버튼을 누르면 각각에 해당하는 도움말이 나오게)