Henry Lee (이현규)


일자 내용
2024-02-10 GPT기반 카카오챗봇 해몽해드림 개발기 [ " ]
2024-02-02 EC2 재부팅 후 /tmp 경로에 pem 파일 지워져 nginx 오류로 웹페이지 접근 안됨.
다시 pem 파일 생성하여 해결.

$ sudo systemctl status nginx
nginx: [emerg] cannot load ertificate "/tmp/my_domain.pem": ...
nginx: configuration file /etc/nginx/nginx.conf test failed
nginx.service: Control process exited, code=exited, status=1/FAILURE
nginx.service: Failed with result 'exit-code'.
Failed to start A high performance web server and a reverse proxy server.

$ cd /tmp
/tmp$ ls
my_domain.key
my_domain_cert.crt
my_domain_chian_cert.crt
my_domain_root_cert.crt

/tmp$ cat my_domain_cert.crt my_domain_chian_cert.crt my_domain_root_cert.crt > my_domain.pem
/tmp$ ls
my_domain.key
my_domain.pem
my_domain_cert.crt
my_domain_chian_cert.crt
my_domain_root_cert.crt
2024-01-26 가비아 도메인 구매 (zenolink.co.kr) 네임서버 설정 (AWS Route53과 연결) DNS관리 (레코드)

A @ AWS_ELASTIC_IP TTL_600_DEFAULT (zenolink.co.kr를 AWS에 연결)
A www AWS_ELASTIC_IP TTL_600_DEFAULT (www.zenolink.co.kr를 AWS에 연결)
TXT @ SSL_SECRET_AUTH TTL_600_DEFAULT (ssl을 발급받기 위한 DNS 인증)
AWS Route53 호스팅 영역 레코드 생성

zenolink.co.kr A 단순 AWS_ELASTIC_IP TTL_300_DEFAULT
zenolink.co.kr NS 단순 AWS_DOMAIN_DEFAULT TTL_60 (가비아 네임서버와 연결)
zenolink.co.kr SOA 단순 AWS_DOMAIN_DEFAULT TTL_900
www.zenolink.co.kr CNAME 단순 zenolink.co.kr TTL_300_DEFAULT
2024-01-25 AWS EC2 Django Project Deployment

/etc
|- nginx
    |- sites-available
        |- django_project
    |- sites-enabled
|- systemd
    |- system
        |- gunicorn.service
        |- gunicorn.socket
/home
|- ubuntu
    |- .local
        |- bin
            |- gunicorn
    |- django_project
        |- django_app
            |- settings.py
            |- wsgi.py
/tmp
|- gunicorn.sock
/var
|- log
    |- nginx
        |- access.log
        |- error.log

# /etc/systemd/system/gunicorn.service
[Unit]
Description=gunicorn daemon
After=network.target

[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/django_project
ExecStart=/home/ubuntu/.local/bin/gunicorn \
        --workers 3 \
        --bind unix:/tmp/gunicorn.sock \
        django_app.wsgi:application

[Install]
WantedBy=multi-user.target

# /etc/nginx/sites-available/django_project
server {
    listen 80;
    server_name aws_elastic_ip;

    location = /favicon.ico { access_log off; log_not_found off; }

    location /static {
        alias /home/ubuntu/django_project/static;
    }

    location / {
        include proxy_params;
        proxy_pass http://unix:/tmp/gunicorn.sock;
    }
}

> sudo systemctl daemon-reload
> sudo systemctl enable gunicorn.service
> sudo ln -s /etc/nginx/sites-available/django_project /etc/nginx/sites-enabled
> sudo systemctl start gunicorn nginx
2024-01-23 HTML input tag's minlength

<form action="#">
    <input type="text" minlength="3">
    <input type="submit" value="search">
</form>
2024-01-22 Delete duplicates by 'name' at django.
exclude()가 포인트!

from django.db.models import Count
from app_name.models import Model_name

duplicates_names = Model_name.objects.values('name').annotate(count=Count('id')).filter(count__gt=1)
for duplicate in duplicates_names:
    name = duplicate['name']
    duplicate_records = Model_name.objects.filter(name=name)

    besk_pk = None
    for record in duplicate_records:
        if not best_pk:
            best_pk = record.pk
            best_cnt = record.cnt_drugs()
        elif record.cnt_drugs() > best_cnt:
            best_pk = record.pk
            best_cnt = record.cnt_drugs()

    duplicate_records.exclude(pk=best_pk).delete()
2024-01-19 Django Template Filter 만들어 쓰기 (Customize)
Data의 형태가 0.289467와 같이 float type일 때, 28.94 %와 같이 퍼센트로 표시하고 싶었으나, 기본 템플릿 필터에는 해당 기능 없음.
포인트는 html에서 load하는 부분과 python에서 register.filter하는 부분.
floatformat:2로 소수점 둘째자리까지 표시하는 것도 꺠알 팁!

# project_name/app_name/templatetags/__init__.py 있어야 하나?
# project_name/app_name/templatetags/filters.py

from django import template

register = template.Library()
@register.filter
def multiply(value, arg):
    return value*arg

{% load filters %}

{{ obj.rate|multiply:100|floatformat:2 }} %
2024-01-17 리스트 일부 노출 후 더보기 기능 구현
tr을 display: none;으로 가리고 initIndications()을 통해서 일부(5개) 먼저 노출.
그리고 버튼 클릭시 전체 노출하고 버튼을 가리기.

<tbody>
    {% for indication in indications %}
    <tr class="indication" style="display: none;">
        <td>
            {{ indication }}
        </td>
    </tr>
    {% endfor %}
</tbody>
</table>
{% if indications %}
<button class="secondary outline" style="width: 120px; margin-left: 20px;" onclick="seeMore()">
    More
<button>
{% endif %}

function initIndications() {
    const indications = document.getElementsByClassName("indication");
    for (let i=0; i<5; i++) {
        indications[i].style.display = 'table-row';
    };
}
initIndications()

function seeMore() {
    const indications = document.getElementsByClassName("indication");
    for (let i=0; i<indications.length; i++) {
        indications[i].style.display = 'table-row';
    };

    const btnMore = document.querySelector(".secondary");
    btnMore.style.display = 'none';
}
2024-01-16 selenium "out of memory" issue.
엣지(Edge) 브라우저가 out of memory 오류로 이상 종료되고, 크롤링이 중단되는 이슈를 배치 프로세싱으로 해결.

batch_size = 1000
starts = 시작_idx
max_idx = 총_idx
for batch_starts in range(starts, max_idx, batch_size):
    batch_ends = min(batch_starts+batch_size, max_idx)
    # 배치 구성하고 배치 별로 브라우저 실행하여 크롤링 수행.
    driver = webdriver.Edge(service=service, options=options)
    driver.implicitly_wait(2)
    for i in range(batch_starts, batch_ends):
        url = 사이트_주소
        driver.get(url)
        '''
        크롤링 수행 코드
        '''
    # 배치 별 브라우저 메모리 점유 삭제하고 종료.
    driver.delete_all_cookies()
    driver.execute_script("window.localStorage.claer();")
    driver.execute_script("window.sessionStorage.claer();")
    driver.quit()
2024-01-15 AWS Ubuntu server init

$ python --version

Command 'python' not found, did you mean:
    command 'python3' from deb python3
    command 'python' from deb python-is-python3

$ type python python2 python3

-bash: type: python: not found
-bash: type: python2: not found
python3 is hashed (/usr/bin/python3)
2024-01-12 Django ManyToManyFiled 필터링 하기.

from django.db.models import Model

class Gene(Model):
    name = CharField()


class Drug(Model):
    name = CharField()
    gene = ManyToManyFiled(Gene)


class Indication(Model):
    name = CharField()
    drug = ManyToManyFiled(Drug)

from .models import Drug, Indication

def view(request, pk):
    '''
    pk는 gene의 pk
    '''
    drugs = Drug.objects.filter(gene_pk=pk) #-> QuerySet
    indications = Indication.objects.filter(drug_in=drugs)
2024-01-11 selenium Select로 HTML Dropdown 다루기.

from selenium.webdriver.common.by import By
from selenium.webdriver.support.select import Select

select_element = driver.find_element(By.TAG_NAME, 'select')
select = Select(select_element)
select.select_by_index(3) # 4th option has idx 3.
2024-01-10 구글 SMTP 사용하기.
계정 설정, 2단계 인증 후 앱 비밀번호 발급 필수

# settings.py
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = 'henrylee@zefit.co.kr'
EMAIL_HOST_PASSWORD = '앱비밀번호without공백'

# views.py
from django.core.mail import send_mail

send_mail(
    subject='메일 제목',
    message='메일 내용',
    from_email='noreply@zefit.co.kr' # not working, need to check
    recipient_list = ['수신 이메일',]
    fail_silently=False, # 실패시 에러창(디버깅) return
)
2024-01-09 python dictionary 정렬 by value 내림차순
단, return은 tuple's list임. 예.[('C',3), ('B',2), ('A', 1)]

sorted_list = sorted(
    dictionary.items(),
    key=lambda item: item[1],
    reverse=True
)
2024-01-08 Python list는 대괄호[] 내에 작은 따옴표로 element가 존재함. 때문에 JSON.parse에서 에러 발생.
작은 따옴표를 큰 따옴표로 replace한 후 JSON.parse() 통해서 handling할 수 있게 함.

# Django views.py
def view(request):
    ...
    datas = ['elm1', 'elm2', 'elm3', 'elm4']
    return render(request, 'template.html', {'datas': datas})

<!--template.html-->
<div datas="{{datas}}">

// script
const data_string = document.getElementById('keywords').getAttribute('datas');
const data_preprocessed = data_string.replace(/'/g, '"');
if (data_string !== '') {
    const data_array = JSON.parse(data_preprocessed)
    data_array.forEach(element => {
        ...
    });
}
2024-01-07

selenium ver.4 with Edge browser


from selenium import webdriver
from selenium.webdriver.edge.service import Service
from selenium.webdriver.edge.options import Options
from selenium.webdriver.common.by import By

driver = 'path/to/msedgedriver.exe'
service = Service(driver)

options = Options()

browser = webdriver.Edge(service=service, options=options)  
browser.get('http://127.0.0.1:5500/example.html')
browser.implicitly_wait(2)

specific_element = browser.find_element(By.ID, 'id_name')
next_element = specific_element.find_element(By.XPATH, 'following-sibling::*[1]')
# by XPath, following-sibling 키워드로 같은 계층 elements :: 전체(*) 중 첫[1] element

print(next_element.text)
browser.quit()
By가 핵심 변경점!
2024-01-06

html datalist
the list of input should be same with the id of datalist.


<input type="text" name="search" id="search" list="phones">
<datalist id="phones">
    <option value="iPhone"></option>
    <option value="Galaxy"></option>
    <option value="Blackberry"></option>
</datalist>
<input type="button" value="search">
다 좋은데, 데이터가 많아지면 ugly해서 picocss에서는 지원하지 않는다고...
2024-01-05 javascript로 python server에 통신하기.

csrftoken = getCookie('csrftoken')
array = Array(...)

fetch('/', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'X-CSRFToken': csrftoken,
    },
    body: JSON.stringify(array)
})

import json

items = json.loads(request.body)
csrftoken 부분은 re-confirm하기.
2024-01-04 Profile과 Blog(TIL)로 간소화.
2024년 잔디심기 목표 설정: 1)TIL 2)HTML 및 CSS로 꾸미기.
2023-11-23 Fluorescence Microscopy의 핵심은 Excitation과 Emission [ " ]
2023-11-16 윈도우는 tensorflow cuda 2.10 버전까지 지원 [ " ]
2023-11-15 인덱스_지정_박스 = tf.gather(박스s, 인덱스s) [ " ]
2023-10-31 https://www.berkshirehathaway.com/에 영감을 얻어 github page 새로 만듦. [ " ]