파이썬하면 요즘 ML/DL, 데이터분석 등으로 엄청난 인기를 끌고 있는데요. 웹프로그래밍에서도 매우 많은 인기가 있습니다. 우리나라에서는 점유율이 많이 못미치지만, 해외에서 Django, FastAPI등은 매우 좋은 반응을 보이고 있습니다. 오늘 소개할 도구는 Django나 FastAPI와 같은 서버도구는 아닌, 파이썬으로 만들어진 정적사이트 생성기 펠리칸(Pelican)입니다.
1. 설치
우선 일반적인 파이썬 프로젝트 시작방법과 마찬가지로 가상환경을 만들어줍니다. (pycharm을 활용하면 쉽게 가상환경이 만들어집니다. VSCode로 진행하면 조금 까다로우니, 다른 포스팅을 참고하세요). 가상환경이 만들어지면 아래의 pip install ~ 로 pelican을 설치합니다.
pip install pelican
2. 추가 라이브러리 설치
github page 배포를 위한 라이브러리 및 마크다운 문서 표시를 위한 추가 라이브러리를 설치합니다.
pip install ghp-import markdown
3. 프로젝트 생성
본격적인 프로젝트를 생성합니다. 첫번째 물음에서 [.]으로 되어있으면 현재 사이트에 생성한다는 의미입니다.
pelican-quickstart
생성이 완료되면 아래와 같이 프로젝트 구성이 보입니다.
4. 샘플 페이지 작성
content 폴더에 Hello.md파일을 작성합니다.
# hello.md #
Title: Are ‘you’ just inside your skin oris your smartphone part of you?
Date: 2018-02-26
Category: Psychology
Slug: are-you-just-inside-your-skin-or-is-your-smartphone-part-of-you
In November 2017, a gunman entered a church in Sutherland Springs in Texas, where he killed 26 people and wounded 20 others. He escaped in his car, with police and residents in hot pursuit, before losing control of [...]
5. 빌드
pelican content
6. 실행
특이하게도 실행은 output폴더로 이동해서 수행해야합니다. 이점은 다른 SSG(Static Site Generator)에 비해 조금 불편하네요. 그리고 일반적인 파이썬 프로젝트와 달리 main.py에서 실행하는게 아니고 pelican.server로 실행해야 합니다. 스크립트를 만들면 되긴 할텐데, 파이썬 공부한지가 오래되어 잘 기억이 안나네요.
cd output
python -m pelican.server
<결과>
드디어 결과가 나왔습니다. 기본 구성 치고는 여러 요소들을 포함하고 있어 보이는데, 이뻐보이진 않습니다. 손대야 할 부분이 많아보이네요.
펠리칸(Pelican) 정적사이트 생성기
오늘은 간단히 파이썬 정적사이트 생성기인 펠리칸(pelican)에 대해 간단히 알아봤습니다. 파이썬을 좋아하시는 분들이라면 한번 시도해보셔도 좋을 것 같습니다.
Django앱을 Gitlab에 올리고, Heroku로 자동 배포하는 방법, 그리고 Freenorm의 무료 DNS를 적용하는 방법을 알아보겠습니다. 순서는 아래와 같습니다.
django 앱 생성 (본문은 Django의 사용법을 다루는 글이 아니므로, 기본적인 앱은 만들어져 있어야 합니다.)
Heroku repo 생성
Gitlab repo 생성
CD/CI설정 (Gitlab 추가설정 및 파일 추가 생성)
추가 설정 (오류 점검)
외부DNS(Freenom) 적용
1. Django 앱 생성
기본적인 앱이 구현되어있겠지만, 앱을 배포하기 위해서는 추가적인 라이브러리 설치가 필요합니다.
pip install gunicorn whitenoise django-herok
# gunicorn: 위에서 설명한 파이썬 HTTP 서버(Python WSGI HTTP Server)입니다.# whitenoise: 헤로쿠(Heroku)에서 정적 파일(Static files)을 사용하기 위해 필요한 모듈입니다.# django-heroku: 헤로쿠(Heroku)에 배포하는 django 프로젝트의 각종 설정을 간단하게 해주는 모듈입니다.
settings.py에 아래의 내용을 추가해줍니다.
import django_heroku
import dj_database_url
# Add this line
PRODUCTION = os.environ.get('DATABASE_URL') != None
ALLOWED_HOSTS = ['wilky.ga','.herokuapp.com']
MIDDLEWARE = [
....중략....
'whitenoise.middleware.WhiteNoiseMiddleware',
]
if PRODUCTION:
DATABASES['default'] = dj_database_url.config()
django_heroku.settings(locals())
2. Heroku에 앱 생성
터미널에서 아래와 같이 입력하여 heroku에 로그인 후 새로운 앱을 생성합니다. (Heroku CLI는 설치되어 있어야 합니다.)
heroku login # Heroku 로그인
heroku create django-repo # 앱 생성
heroku git:remote -a django-repo # 저장소를 등록해서 연결합니다.
git remote -v # 원격 저장소 확인
이렇게 생성 및 연결이 되었다면, 이번엔 Heroku 사이트로 이동하여 몇가지 확인해놓아야 하는 부분을 체크합니다.
(1) App Name 확인: django-repo 라고 만들었습니다.
(2) App URL 확인 : django-repo.herokuapp.com이 됩니다. App의 settings하단에 Domains 섹션에 보시면 URL이 나와있습니다. 또는 Open App으로 직접 이동하여 URL을 확인할 수도 있습니다.
(3) API 키 확인 (내 계정 - Account Settings)
3. Gitlab에 Repository 생성 후 업로드
Gitlab에 Repository를 만들어줍니다. Repository 만드는 방법이나 Git 사용법은 다른 사이트를 참고하시기 바랍니다.
git을 이용해 소스코드를 저장해야 하는데, 저장하기전에 .gitignore파일을 아래의 사이트를 이용해 생성해 놓습니다.
추가파일을 생성 후 "git push origin master"를 수행하면, 해당 시점부터는 자동으로 Heroku로 배포가 되어, 사이트 확인이 가능해집니다.
5. Collectstatic 설정 변경
배포를 하는 과정을 보다보면 collectstatic 부분에서 에러가 나는 모습을 볼 수 있습니다.
이를 해결하기 위해서는 터미널에 아래와 같이 입력해줍니다.
heroku config:set DISABLE_COLLECTSTATIC=1
다른 방법도 여럿 보였지만, 위 방법이 제일 간단하고 정상작동됩니다.
참고로, Database(db.sqlite3)를 못읽어오는 경우도 있었는데, 혹시 다른 폴더 하위에 있다면(예: "db/db.sqlite3") 프로젝트폴더 내 바로 두고 실행하시기 바랍니다.
이렇게 하여 Heroku에 직접 소스코드를 push하여 올리지 않고 Gitlab만 관리하더라도 배포가 되는 것을 확인할 수 있습니다.
6. Freenom의 무료 DNS 적용하기
Heroku에서 제공하는 URL이 있긴 하지만, 좀더 우리가 원하는 URL을 적용하기 위해 DNS를 적용하는 방법을 알아보겠습니다.우선 Freenom으로 가서 원하는 이름의 도메인을 만듭니다. (다른 사이트를 참조하시기 바랍니다.) 우선 만들기만 하고 추가적인 세팅은 잠시 뒤에 하겠습니다.
얼마전 Heroku 정책 변경으로 인해 DNS를 변경하기 위해서는 신용카드를 등록해야한다고 합니다. 돈이 나가는 것은 아니고 보안 목적이라고 하니 걱정은 안해도 될 것 같습니다. 우상단의 Account Setting > Billing 메뉴로 진입하여 개인의 신용카드를 등록합니다.
Settings > Domains 섹션에서 "Add domain"버튼을 클릭해줍니다.
그러면 우측에 아래와 같은 화면이 나타나는데, 위의 freenom에서 만들어준 주소를 적어주고, 하단의 Next버튼을 눌러줍니다. 그러면 DNS target이 나타납니다. 이 주소를 메모해서 Freenom에 적용시켜줘야 합니다.
Freenom에 로그인 후 Services > My Domains > Manage Domain > Manage Freenom DNS로 진입한 후,
Heroku에서 제공받은 DNS Target의 정보를 붙여넣습니다. 그리고 다른 정보는 아래와 같이 설정합니다.
Name: WWW
Type: CNAME
TTL: 144400
이렇게 하면 드디어 내 주소가 반영된 모습을 확인하실 수 있을겁니다.
※ 아직 데이터베이스(sqlite3)연결이 잘 안된는 것 같습니다. 블로그/로그인/사용자등록 기능이 제대로 나오지 않고 있는데, 좀 더 공부해봐야 겠습니다.
1:N관계에서 N쪽 테이블(TempDataroomHstry클래스)에 ForeignKey로 1쪽 테이블명(Temp래스)을 지정해줍니다. 이때, 1쪽 테이블의 참조하려는 필드가 Primary Key로 지정되어있으면 상관없지만, 없을 경우 필드 정의에(ForeignKey 함수 내부에서) to__field='목표필드' 를 지정해줘야 합니다. 그리고, db_column='참조칼럼명' 에서 해당 테이블에서 참조할 실제 칼럼(필드)명을 지정해줘야 합니다.
(*) Oracle DB에서만 이런 문제가 발생하는 것인지.. 아직은 잘 모르겠습니다. 이것 때문에 한참을 헤메었네요..^^;; 또한 이번의 경우 Temp의 emp_field와 TempDataroomHstry의 id는 사실 칼럼명은 동일하게 'emp_#'이었습니다. db_column에 넣어주는 값이 현재 테이블의 칼럼명인지, 목표 테이블의 칼럼명인지 좀 헷갈립니다...
<models.py>
from django.db import models
classTemp(models.Model):
emp_field = models.CharField(db_column='emp_#', primary_key=True, max_length=7) # Field renamed to remove unsuitable characters. Field renamed because it ended with '_'.
emp_x = models.CharField(max_length=2, blank=True, null=True)
kornm_n = models.CharField(max_length=32, blank=True, null=True)
res_1 = models.CharField(db_column='res_#1', max_length=12, blank=True, null=True) # Field renamed to remove unsuitable characters.
sex_n = models.CharField(max_length=2, blank=True, null=True)
dept_c = models.CharField(max_length=16, blank=True, null=True)
classMeta:
managed = False
db_table = 'TEMP'classTempDataroomHstry(models.Model):
seq_field = models.IntegerField(db_column='seq_#',primary_key=True) # Field renamed to remove unsuitable characters. Field renamed because it ended with '_'.id = models.ForeignKey(Temp, to_field='emp_field', db_column='emp_#',on_delete=models.CASCADE, null=True, related_name='id') #, related_name='tempdataroomhstry'
in_d = models.DateField(blank=True, null=True)
classMeta:
managed = False
db_table = 'TEMP_DATAROOM_HSTRY'
2. 데이터 활용하기
Join을 위해서는 "select_related()"나 "prefetch_related()"를 사용하는데, 이번에는 select_related()만 알아보도록 하겠습니다. select_related는 1:1 또는 1:N 의 경우에 사용할 수 있는 함수입니다. (정방향 참조필드). select_related()의 인자로는 해당 Table의 ForeinKey를 넣어줍니다. 아래의 예제에서는 우선 'id'칼럼을 이용하여 join후 모든 데이터를 불러오고 'in_d'를 기준으로 역정렬(desc)을 하여 list를 만들고, 이를 home.html에 넘겨줍니다.
<views.py>
from django.core.paginator import Paginator
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse
from .models import TempDataroomHstry
#### 초기화면 및 조회함수 ####defindex(request):list = {}
list = TempDataroomHstry.objects.select_related('id').all().order_by('-in_d')
# HTML에서 인자가 전달될 경우 처리
q = request.GET.get('q', '')
if q:
list = list.filter(id=q)
# 여기까지
context = {'member_list': list}
return render(request, 'home.html', context)
A테이블에 B가 조인될 경우 "[A].[조인된A칼럼명].[B칼럼명]"과 같이 사용하면 됩니다. 아래 home.html파일은 실제 Join된 데이터를 불러와 사용하는 예시를 볼 수 있습니다.
<home.html>
....
<tbody>
{% if member_list %}
{% for member in member_list %}
<tr><td>{{ member.id.emp_field }}</td><td>{{ member.id.kornm_n }}</td><td>{{ member.id.res_1 }}</td><td>{{ member.id.sex_n }}</td><td>{{ member.id.dept_c }}</td><td>{{ member.in_d }}</td></tr>
{% endfor %}
{% endif %}
</tbody>
import pandas as pd
import requests
from bs4 import BeautifulSoup
key = '내 서비스키'
# url='http://openapi.molit.go.kr:8081/OpenAPI_ToolInstallPackage/service/rest/RTMSOBJSvc/getRTMSDataSvcAptTrade?LAWD_CD=11110&DEAL_YMD=201512&serviceKey='+key
url='http://openapi.molit.go.kr:8081/OpenAPI_ToolInstallPackage/service/rest/RTMSOBJSvc/getRTMSDataSvcAptTrade?serviceKey='+key
rowList=[] # 전체 행을 저장할 변수
nameList=[] # 열(칼럼) 이름을 저장할 변수
item_content=[] # 각 행별 칼럼값들을 저장할 임시공간
# 지역코드는 11000(서울)~39020(서귀포)
city_list=["26440","26410","26710","26290","26170","26260","26230","26320","26530","26380","26140","26500","26470","26200","26110","26350"]
for city in city_list:
params ={'LAWD_CD' : city, 'DEAL_YMD' : '202110' }
response = requests.get(url, params=params).text #인코딩이 필요할 경우 .encode('utf-8')
soup = BeautifulSoup(response, "lxml-xml")
item_list = soup.find_all('item') # 전체 contents를 담은 변수
rowsLen = len(item_list) # 전체 행 수
for i in range(rowsLen):
columns = item_list[i].find_all() # 1번째 행(row)의 모든 요소값들을 칼럼으로 한다.
columnsLen = len(columns) # 1번째 행(row)의 요소길이를 열(column) 길이로 한다.
for j in range(0, columnsLen):
if i == 0 and city=="26440": # 첫번째 행 데이터 수집시 컬럼 값 저장
nameList.append(columns[j].name) # name 값만 추출한다
eachColumn = columns[j].text # 각 행(i)의 각 열(j)의 텍스트만 추출한다.
item_content.append(eachColumn) # 각 칼럼값을 append하여 1개 행을 만든다.
rowList.append(item_content) # 전체 리스트 공간에 개별 행을 append한다.
item_content=[] # 다음 row의 값을 입력받기 위해 비워준다.
df = pd.DataFrame(rowList, columns=nameList)
df.head(50)
블로그 앱의 모델을 작성해 줍니다. 1:N의 관계에서 1은 N의 테이블(클래스)에서 ForeignKey로 지정해줍니다. 예를 들어 Category와 Post는 1:N의 관계입니다. 이 경우 Post 테이블에 Category 필드를 지정해주며, ForeignKey 속성을 부여합니다.
on_delete=models.SET_NULL은 해당 필드가 삭제될 경우 null로 세팅하라는 의미이며,
on_delete=model.CASCADE 해당 필드가 삭제될 경우 해당 값을 모두 삭제하라는 의미입니다.
blog url을 가져올 수 있도록 등록합니다. 또한 이미지 파일이 불려와질 수 있도록 urlpatterns 구문을 추가합니다.
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path, include
from mysite.views import HomeView
urlpatterns = [
path('admin/', admin.site.urls),
path('', HomeView.as_view(), name='home'),
path('blog/', include('blog.urls')),
]
# 이미지 url 접근 시 이미지 파일이 접근 가능하도록 설정
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
7. blog/urls.py 작성
실제 blog의 세부 url을 작성합니다. url에 따라 PostDV클래스를 찾습니다.
from django.urls import path
from blog import views
app_name = 'blog'
urlpatterns = [
# /blog/post/99/
path('post/<int:pk>/', views.PostDV.as_view(), name='post_detail'),
]
8. blog/views.py 작성
PostDV를 정의합니다. 모델은 Post모델을 사용하며, 사용할 template을 정의합니다.
from django.views.generic import DetailView
from blog.models import Post
classPostDV(DetailView):
model = Post
template_name = 'blog/post_detail.html'
9. templates/blog/post_detail.html 작성
보여질 post_detail.html파일을 작성합니다.
<!DOCTYPE html><htmllang="en"><head><metacharset="UTF-8"><title>post_detail.html</title></head><body>
This is post_detail.html...
</body></html>
아직은 해당 경로로 이동해도 보여지지 않습니다. 포스트를 생성해야합니다.
10. admin site로 이동하여 포스트 생성
포스트를 몇개 등록합니다.(아래 이미지에서는 첫번째 등록한 포스트가 지워졌습니다.)
11. url 입력
위에서 입력한 포스트의 id를 유념하여 url을 입력합니다. 아래와 같이 작성된 post_detail.html 이 나타나면 정상입니다.
12. home.html 수정
url을 매번 입력하여 이동할 수는 없으므로, home.html파일의 첫번째 이미지 클릭 시 포스트가 나타나도록 수정하겠습니다.
현재 폴더에 ( . ) mysite라는 프로젝트를 생성해줍니다. 이 경우 manage.py파일이 현재 폴더에 생성됩니다. (현재 폴더를 지정하지 않으면 한단계 더 아래 폴더에 프로젝트 및 manage.py 파일을 생성합니다. )
django-admin startproject mysite .
4. setting.py 수정
DB / Template / Media / Static 관련된 폴더들을 만들고, 이들 경로를 BASE_DIR을 기준으로 지정해줍니다. 그리고 TIME_ZONE, USE_TZ 값을 수정해줍니다.
"""
Django settings for mysite project.
Generated by 'django-admin startproject' using Django 3.2.8.
For more information on this file, see
https://docs.djangoproject.com/en/3.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.2/ref/settings/
"""from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-1tq5c@vtc5f@-^2%sxpu5(42=3^n24fow@i1m*%+h(5#ghx9ml'# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'mysite.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'], # 수정'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'mysite.wsgi.application'# Database# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db' / 'db.sqlite3', # 수정
}
}
# Password validation# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization# https://docs.djangoproject.com/en/3.2/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'Asia/Seoul'# 수정
USE_I18N = True
USE_L10N = True
USE_TZ = False# 수정# Static files (CSS, JavaScript, Images)# https://docs.djangoproject.com/en/3.2/howto/static-files/
STATIC_URL = '/static/'# Default primary key field type# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'### 추가 ###
STATICFILES_DIRS = (BASE_DIR / 'static',)
# STATIC_ROOT = # 배포시 사용
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'# AUTH_USER_MODEL =# LOGGING =
5. DB생성
python manage.py migrate
6. 관리자계정 생성
python manage.py createsuperuser
7. mysite/urls.py 수정
"""adv URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""from django.contrib import admin
from django.urls import path
from adv.views import HomeView
urlpatterns = [
path('admin/', admin.site.urls),
path('', HomeView.as_view(), name='home')
]
8. mysite/views.py 생성
from django.views.generic import TemplateView
classHomeView(TemplateView):
template_name = 'home.html'
Database에서 간단히 CRUD만 구성할 일이 있었는데, Backend 와 Frontend를 분리해서 구축하려니 조금 번거로워서 찾게되었습니다. Python 프레임워크들은 Jinja2 템플릿을 사용하여 Frontend도 쉽고 빠르게 구축할 수 있도록 지원해주기 때문에, 이런 용도로는 잘 맞는 것 같습니다. FastAPI도 일반적으로는 API 형태의 backend를 구성하겠지만, Jinja2를 이용하여 Frontend 연결까지 해보도록 하겠습니다.
1. 폴더구조
아래와 같이 폴더구조를 만들겠습니다. 이전에 만들었던 main.py를 업데이트하기 위해 mainlist.py 파일을 새로 작성하였습니다. 실행도 mainlist.py로 실행하겠습니다.
from sqlalchemy import Column, Integer, String
# from pydantic import BaseModelfrom db.db import Base
classUserTable(Base):
__tablename__ = 'user'id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(50), nullable=False)
age = Column(Integer)
<routes/index.py>
Jinja2Templates를 불러오고 html파일이 위치할 디렉토리를 지정해주면 해당 파일에서 Jinja2문법을 사용할 수 있습니다. Jinja2에서는 Post와 Get 메서드만 지원되며, put, delete 등의 다른 메서드는 지원되지 않습니다. Form 요소의 사용법에 대해서는 여기 문서를 참조하세요
from fastapi import APIRouter, Request, Form
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
from starlette.responses import RedirectResponse
from db.db import session
from model.model import UserTable, User
router = APIRouter()
templates = Jinja2Templates(directory="templates")
# 전체 리스트@router.get("/users", response_class=HTMLResponse)asyncdefread_users(request: Request):
context={}
users = session.query(UserTable).all()
context["request"] = request
context["users"] = users
return templates.TemplateResponse("user_list.html", context)
# 특정 인원 보기@router.get("/users/{user_id}", response_class=HTMLResponse)asyncdefread_user(request: Request, user_id: int):
context={}
user = session.query(UserTable).filter(UserTable.id == user_id).first()
context["request"] = request
context["name"] = user.name
context["age"] = user.age
return templates.TemplateResponse("user_list.html", context)
# 인원 생성@router.post("/user")asyncdefcreate_user(
name: str = Form(...),
age:int = Form(...)):print(name, age)
user = UserTable()
user.name = name
user.age = age
session.add(user)
session.commit()
return RedirectResponse(url="/users", status_code=302)
# 인원 수정@router.post("/users", response_class=HTMLResponse)asyncdefupdate_user(
user_id: int = Form(...),
n_name: str = Form(...),
n_age: int = Form(...)):
user = session.query(UserTable).filter(UserTable.id == user_id).first()
user.name = n_name
user.age = n_age
print(n_name, n_age)
session.commit()
return RedirectResponse(url="/users", status_code=302)
# 인원 삭제@router.post("/delete/{user_id}", response_class=HTMLResponse)asyncdefdelete_users(request: Request, user_id: int):print('delete', user_id)
session.query(UserTable).filter(UserTable.id == user_id).delete()
session.commit()
return RedirectResponse(url="/users", status_code=302)