주관적인 추천이다. 하지만 Jquery라이브러리를 시작으로 여러가지 프레임워크를 통해 작은 프로젝트를 해본 결과를 바탕으로 추천해 본다.
추천하고 싶은 프레임웍은 바로: 스벨트이다.
영번째 재미있다.
첫번째 이유는 매우 쉽다. 다른 프레임웍에 비해 러닝커브가 완만하다. 자바스크립트만 어느정도 알면 바로 시작할 수 있을 정도로 쉽게 배울 수 있다. 예전에 웹을 점령했던 JQuery도 이러한 장점이 있었다. 예전에 웹을 배우는 방식은 자바스크립트로 아주 조금 맛배기를 보곤 바로 jquery로 넘어갔던 기억이 있다. 왜냐면 jquery가 자바스크립트 자체를 배우는것 보다 쉽고 실전에서 써먹기 좋았기 때문이다.
스벨트도 jquery와 같이 쉽게 배울 수 있다는 점에서 추후 사용자들을 흡수 할 것으로 예상 할 수 있다.
두번째 이유는 빠르다.
스벨트를 설치해보면 알겠지만 설치도 쉽다. 그 설치 자체도 빠르다. 새로운 프로젝트를 계속해서 만들어 내는 사람들에게 특히나 좋아 할 수 있다. 설치만 빠르면 좋은게 아니다. 실행도 빠르고, 동작도 빠르게 빠르게 움직인다.
얼마나 가볍고 빠르게 동작하는지를 보고 싶다면 스벨트 프로젝트들을 모아둔 이 사이트에 들어가서 구경해보길 바란다. 게임에서 부터 쇼핑몰, threejs를 적용한 svelte 패키지까지 구경할 수 있다.
이렇게 빠르게 동작할 수 있는 이유는 svelte는 vuejs와 reactjs처럼 virtual DOM을 사용 하는게 아니라. 스벨트가 컴파일러 역활을 하여 작성한 코드를 순수한 자바스크립트로 컴파일 해주기 때문이다.
세번째 이유는 가볍다
위에서 말했듯 순수한 자바스크립트로 컴파일을 해준다는 말은 필요없는 패키지들을 불러오지 않고 딱 필요한 코드만 생성해내는 것이다. 그렇기 때문에 빌드된 파일의 크기는 매우 작다. 이는 실행이 빠르게 되도록 만들어준다.
네번째 이유는 간결하다.
리액트를 사용하면 간단한 프로젝트도 많은 보일러플레이트 코드가 필요하다. 플러터에 관심이 있어서 사용해 플러터웹을 사용해서 작은 관리자 앱을 만들었는데 플러터웹을 이용해서 만든걸 후회 하고 있다. (물론 플러터는 모바일에서는 좋다.) 둘다 보일러플레이트 코드량이 많다. 그런데 스벨트코드를 보면 너무나도 심플하다. 스토어도 기본적으로 제공해주는데 심플하게 사용할 수 있다. 예전에 리덕트를 배우려고 머리 아픈것에 비하면 심플해서 머리 아플게 없다.
다섯번째 제공 repl
간단하게 코드를 작성할 수 있는 repl을 제공하는데 깃 계정을 통해서 심플하게 만든 앱을 저장 할 수 있다. 잘 사용하면 생각보다 쓸만하다.
차트의 레이블을 일일이 마우스 클릭하여 입력하고, 색상까지 바꿔주는게 귀찮아서 자동으로 완성해줄 수 있는 VBA가 있는지 찾아봤다.
그리고 그 코드를 약간 수정해서 아래의 결과물을 보여질 수 있는 코드를 만들었다.
결과
사용방법
차트를 클릭한 뒤 메크로로 아래의 코드를 넣은 모듈을 실행시키면 된다.
Sub LastPointLabel()
Dim mySrs As Series
Dim iPts As Long
Dim vYVals As Variant
Dim vXVals As Variant
If ActiveChart Is Nothing Then
MsgBox "Select a chart and try again.", vbExclamation
Else
Application.ScreenUpdating = False
For Each mySrs In ActiveChart.SeriesCollection
With mySrs
vYVals = .Values
vXVals = .XValues
' clear existing labels
.HasDataLabels = False
For iPts = .Points.Count To 1 Step -1
If Not IsEmpty(vYVals(iPts)) And Not IsError(vYVals(iPts)) _
And Not IsEmpty(vXVals(iPts)) And Not IsError(vXVals(iPts)) Then
' add label
Set pt = mySrs.Points(iPts)
pt.ApplyDataLabels _
ShowSeriesName:=True, _
ShowCategoryName:=False, ShowValue:=False, _
AutoText:=True, LegendKey:=False
Set dl = pt.DataLabel
With dl
'text color match to the it's line of the chart
.Font.Color = mySrs.Format.Line.ForeColor
.Top = pt.Top - 10
.Left = pt.Left + 20
.Font.Size = 12
.Font.Bold = True
End With
End If
Exit For
Next
' Change the font size to 12
End With
Next
' legend is now unnecessary
ActiveChart.HasLegend = False
Application.ScreenUpdating = True
End If
End Sub
__init__.py파일 안에 아래와 같이 코드를 만들었더니 디비가 생성되지 않는 에러가 나타났다. 그런데
def create_app():
with app.app_context():
db.create_all()
from .views import main_views
app.register_blueprint(main_views.bp)
return app
아래 처럼
with app.app_context():
db.create_all()
을 맨 마지막에 적으니 작동이 된다.
def create_app():
from .views import main_views
app.register_blueprint(main_views.bp)
with app.app_context():
db.create_all()
return app
코드 나눈건 아래 같은 방식으로 나누었다.
__init__.py
from flask import Flask
from flask_cors import CORS
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
# *** 중요 (팩토리 패턴세팅) ***
db = SQLAlchemy()
migrate = Migrate()
# ***** 팩토리 패턴에서 자동으로 실행되는 create_app() 함수
def create_app():
app = Flask(__name__)
CORS(app)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///inventory.db" # sqllite
# app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://로컬유저네임:로컬비번@localhost/default'
# app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://닉네임:비밀번호@파이썬애니웨어닉네임.mysql.pythonanywhere-services.com/디비네임$default'
app.config['SQLALCHEMY_ENGINE_OPTIONS'] = {'pool_recycle': 280}
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
UPLOAD_FOLDER = './downloads'
# *** 중요 (팩토리 패턴세팅) ***
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
db.init_app(app)
migrate.init_app(app, db)
from .views import main_views
app.register_blueprint(main_views.bp)
with app.app_context():
db.create_all()
return app
views.py
# *** 중요 (팩토리 패턴세팅): Blueprint 임포트하기 ***
from flask import Blueprint
from flask import request
import pandas as pd
from myapp import db
from myapp.models import ProductInfo, Quots, SalesDetail, StockLevel, Sales, Purchase, Bom, QuotsDetail, PurchaseDetail
import json
from werkzeug.utils import secure_filename
from flask import make_response
# *** 중요 (팩토리 패턴세팅): url 경로 / 기준으로 엔드포인트 만듬 ***
bp = Blueprint('main', __name__, url_prefix='/')
@bp.route("/add_product_info", methods=['GET', 'POST'])
def add_product_info():
if request.method == 'POST':
objects = []
...
return '0'
else:
return '0'
@bp.route("/csv_upload", methods=['POST'])
def csv_upload():
if request.method == 'POST':
counts = {'total':0, 'insert': 0, 'update':0}
if 'file' not in request.files:
print('No file part')
file = request.files['file']
if file.filename == '':
print('No selected file')
if file and allowed_file(file.filename):
...
print('success')
return {'stauts':'success', 'counts':counts}
@bp.route("/product_edit", methods=['POST'])
def product_edit():
if request.method == 'POST':
row = json.loads(request.data)['data']
...
db.session.commit()
return {'res':0}
models.py
# *** 중요 (팩토리 패턴세팅)__init__에 만든 db 가져오기 ***
from myapp import db
import datetime
class ProductInfo(db.Model):
id = db.Column(db.Integer, primary_key=True)
article = db.Column(db.String(32), unique=True, nullable=False)
...
#server deafult는 string
online_shop = db.Column(db.Boolean, nullable=False, server_default='0', default=0)
stocks = db.relationship("StockLevel")
def as_dict(self):
return {c.name: getattr(self, c.name) for c in self.__table__.columns}
class Sales(db.Model):
__tablename__ = 'sales'
id = db.Column(db.Integer, primary_key=True)
...
status = db.Column(db.String(16))
children = db.relationship("SalesDetail")