85일차 2023-07-07
PYTHON
console 수정, 삭제, 조회
Database10 폴더
controller.py
from view import *
from model import *
#데이타베이스 연결
conn=connectdb()
while True:
# '1.입력 2. 수정 3. 삭제 4. 조회 9. 종료'
menu=showMenu()
print(menu)
if menu == 9:
print('프로그램을 종료합니다')
close(conn)#데이타베이스 닫기
break
elif menu == 1:
#뷰(화면) 호출
list_ = inputData(*['아이디','비번','이름'])
#print(list_)
# 모델 호출
affected=insert(conn,list_)
print(f'{str(affected)+"행이 입력되었습니다" if affected==1 else "입력시 오류발생"}')
elif menu==2:
# 뷰 호출(메시지 뿌려주기)
username = showMessage('수정')
#모델 호출(입력한 이이디 존재 여부 파악)
if selectOne(conn,username):
#뷰 호출(수정코자 하는값 입력받기)
list_ = inputData(*['비번','이름'])
list_.append(username)
#모델 호출(수정처리)
print(update(conn,*list_),'행이 수정되었어요',sep='')
else:
print('아이디가 존재하지 않아요')
elif menu==3:
# 뷰 호출(메시지 뿌려주기)
username = showMessage('삭제')
# 모델 호출(입력한 이이디 존재 여부 파악)
if selectOne(conn, username):
# 모델 호출(삭제처리)
print(delete(conn,username), '행이 삭제되었어요', sep='')
else:
print('아이디가 존재하지 않아요')
else:
# 모델 호출
records = selectAll(conn)
if records:
# 뷰호출
showRecords(records)
view.py
def showMenu():
print('=' * 31)
print('1.입력 2.수정 3.삭제 4.조회 9.종료')
print('=' * 31)
return int(input('메뉴번호를 입력하세요?'))
def inputData(*args):#사용자로부터 가변적인 항목을 입력받기 위한 UI
list_=[]
for arg in args:
list_.append(input(f'{arg}을(를) 입력하세요?'))
return list_#입력받은 값을 리스트로 반환
def showMessage(title):
return input(f'{title}하려는 아이디를 입력하세요?')
def showRecords(records):
print('*' * 40)
for user,password,name,joindate in records:
print('%-10s%-10s%-10s%s' % (user,password,name,str(joindate)[0:10]))
print('*' * 40)
if __name__ =='__main__':
showMenu()
print('아이디:',showMessage("수정"),sep='')
model.py
from cx_Oracle import connect
from configparser import ConfigParser
def connectdb():#데이타베이스 연결:Connection 객체 반환
config=ConfigParser()
config.read('oracle.ini')
#데이타베이스 연결
return connect(user=config['ORACLE']['USER'],
password=config['ORACLE']['PASSWORD'],
dsn=config['ORACLE']['URL'],
encoding="UTF-8")
def close(conn):#커넥션객체 닫기
if conn:
conn.close()
#list_는 입력 데이타
def insert(conn,list_):#입력처리:성공시 1,실패시 0
with conn.cursor() as cursor:
try:
cursor.execute('INSERT INTO users VALUES(:1,:2,:3,SYSDATE)',list_)
conn.commit()
return 1
except Exception as e:
#print(e)
return 0
def update(conn,*args):#수정처리:성공시 1,실패시 0
with conn.cursor() as cursor:
try:
cursor.execute('UPDATE users SET password=:1,name=:2 WHERE username=:3',args)
conn.commit()
return cursor.rowcount
except Exception as e:
#print(e)
return 0
def delete(conn,username):#삭제처리:성공시 1,실패시 0
with conn.cursor() as cursor:
try:
cursor.execute('DELETE FROM users WHERE username=:1',(username,))
conn.commit()
return cursor.rowcount
except Exception as e:
#print(e)
return 0
def selectOne(conn,username):
with conn.cursor() as cursor:
try:
cursor.execute('SELECT * FROM users WHERE username=:1',[username])
return cursor.fetchone()
except Exception as e:
print(e)
return None
def selectAll(conn):
with conn.cursor() as cursor:
try:
cursor.execute('SELECT * FROM users ORDER BY joindate DESC')
return cursor.fetchall()
except Exception as e:
print(e)
return None
if __name__ =='__main__':
conn=connectdb()
#print(insert(conn,['KIM','1234','최길동']),'행 입력')
print(update(conn,*['9999','KIMKILDONG','KIM']))
결과)
Class11 폴더 생성
class1.py
'''
접근 지정자가 없다 .따라서 캡술화도 없다
생성자 오버로딩도 없다
즉 클래스에선 무조건 __init__()이 하나만 와야 하고,
마치 private처럼 비공개 속성을 위해선 변수 혹은 함수 앞에
언더바 __를 붙여야한다
'''
#클래스 정의:__init__ 스페셜 메소드(생성자에 해당) 미 정의한 경우
#def __init__(self):
# pass
#가 생략된거와 같다
#class 클래스명:혹은 class 클래스명(object):
#클래스명은 대문자로 시작하자
class Person:#class Person(object):와 같다
'''
클래스 독 스트링
사람 클래스입니다
클래스 바로 밑에 위치 시킵니다
'''
def sleep(self):#인스턴스 메소드
'''
메소드 독 스트링
sleep()메소드 입니다
:return: 없다
'''
print(self)#인스턴스화된 객체 자신을 의미
print('자다')
def eat(self):#인스턴스 메소드
print('먹다')
#인스턴스화 : 클래스명()
person1 = Person()
print(f'value:{person1},type{type(person1)},주소:{id(person1)}')
person1.sleep()
person1.eat()
person2 = Person()
print(f'value:{person2},type{type(person2)},주소:{id(person2)}')
#클래스명.__doc__ 혹은 인스턴스변수(객체).__doc__ : 클래스 독 스트링
print(Person.__doc__)
print(person1.__doc__)
#print(sleep.__doc__)#NameError: name 'sleep' is not defined
#클래스명.메소드명.__doc__ 혹은 인스턴스변수.메소드명.__doc__ : 메소드 독 스트링
print(Person.sleep.__doc__)
print(person1.sleep.__doc__)
print(Person.eat.__doc__)#None
#클래스 정의: __init__ 스페셜 메소드(생성자에 해당) 정의
class Person2(object):
def __init__(self,name):
# self는 인스턴스화된 객체 자신.인스턴스화시 자동으로 전달된다
self.name = name
print('생성자')
def sleep(self):
print(self.name,'이(가) 자다',sep='')
def eat(self):
print(self.name,'이(가) 먹다',sep='')
# 인스턴스화
#person3 = Person2()#TypeError: Person2.__init__() missing 1 required positional argument: 'name'
person3 = Person2('가길동')
person3.sleep()
person3.eat()
#인스턴스변수가 특정 클래스의 인스턴스인지 확인
#isinstance(인스턴스변수,클래스명)
print(isinstance(person1,Person))
print(isinstance(person1,Person2))
결과)
class2.py
#클래스안에서 클래스 자신의 메소드 호출하기
def sleep():print('클래스 밖(모듈의) 메소드:sleep()')
def eat():print('클래스 밖(모듈의) 메소드:eat()')
#클래스 정의
class Person:
def __init__(self,name):
self.name=name
def sleep(self):print(self.name,'이(가) 자다',sep='')
def eat(self):print(self.name, '이(가) 먹다', sep='')
def print(self):
# 클래스 밖(모듈)의 함수호출
#sleep()
#eat()
# 클래스안의 인스턴스 메소드 호출시에는 self지정
self.sleep()
self.eat()
#인스턴스화
person =Person('가길동')
person.print()
결과)
class3.py
#클래스의 속성(인스턴스 속성)만들기
#인스턴스화 된 모든 객체가 갖는 속성이 됨.즉 모든 인스턴스에 존재하는 속성이 된다
#클래스의 인스턴스 속성 만들기1 : __init__메소드 안에서 self.속성명 = 값 혹은 매개변수
class Person:
def __init__(self,name,age):
self.name = name
self.age = age
self.desc = None
def print(self):#인스턴스 메소드
# 메소드 안에서 인스턴스 속성에 접근시 : self.속성명
print('이름:{},나이:{},설명:{}'.format(self.name,self.age,self.desc))
# print 메서드를 호출해야만 속성(self.addr)이 생성된다.
# 호출 전까지는 없는 속성이다
# 클래스의 인스턴스 속성 만들기2 : 인스턴스 메소드안에서 self.속성명=값 혹은 변수
self.addr = '이 속성은 print()호출시 생성된다'
#인스턴스트화(객체화)
person1 = Person('가길동',20)
print('print호출 전 이름공간:',dir(person1))
#print(person1.addr)#AttributeError: 'Person' object has no attribute 'addr'
#클래스 밖에서 속성 접근 : 인스턴스변수.속성명
print('이름:{},나이:{},설명:{}'.format(person1.name,person1.age,person1.desc))
person1.print()
print('print호출 후 이름공간:',dir(person1))
print(person1.addr)
#클래스의 인스턴스 속성 만들기3: 인스턴스화 후 인스턴스변수.속성명=값 속성추가
person2 = Person('나길동',30)
person2.tel='010-1234-5678'
print('person2의 이름공간:',dir(person2))
#print(person1.tel)#AttributeError: 'Person' object has no attribute 'tel'
결과)
class4.py
#클래스 속성 : __init__(self)메소드 안이 아닌 클래스 안에 선언한 변수(self없이)
# 클래스명.속성로 접근
# 모든 인스턴스화된 객체가 공유한다
#인스턴스 속성:self.변수 로 선언한 변수 인스턴스변수.속성로 접근
class Person:
count =0#클래스 속성
def __init__(self,name):
self.info='사람 클래스입니다'#인스턴스 속성
self.name=name#인스턴스 속성
#self.count+=1#도 가능하나 self로 접근하면 count가 인스턴스 속성인지 클래스 속성인지 애매모호
#count+=1#count=count+1#UnboundLocalError: cannot access local variable 'count' where it is not associated with a value
# 클래스안에서 클래스 속성 접근 : 자신 클래스 안에서도 반드시 클래스명.클래스속성
Person.count+=1
def print(self):
print('지금까지 생성된 총 객체 수:',Person.count,sep='')
#클래스명으로 클래스 속성 접근
print(Person.count)
#인스턴스화
person1 = Person('가길동')
person1.print()
person2 = Person('가길동')
person2.print()
print(Person.count)
#인스턴스 변수로 클래스 속성 접근
#파이썬은 속성 이나 메서드를 찾을 때 인스턴스(속성,메소드)-> 클래스(속성,메소드) 순으로 찾는다.
#그래서 인스턴스 속성이 없으면 동작은 한다. 클래스 속성을 찾게 됨으로 문제 없이
print(person1.count)#역시 인스턴스 변수로 접근하면 인스턴스 속성인지 클래스 속성인지 애매모호
결과)
class5.py
'''
인스턴스 메소드:self(인스턴스화된 객체자신)를 인자로 받는 메소드로 인스턴스 변수로 접근
즉 self는 인스턴스 속성이나 인스턴스 메소드 접근시 사용
정적 메소드:self,cls(인스턴스화가 되지 않는 클래스 자신)를 인자로 받지 않는 메소드로
@staticmethod라는 데코레이터를 붙인 메소드
클래스 메소드:cls를 받은 메소드로 @classmethod라는 데코레이터가 붙은 메소드
즉 cls는 클래스 속성이나 클래스 메소드 접근시
정적메소드와 클래스메소드는 클래스명.메소드명으로 접근.인스턴스화 불필요
'''
class MyClass:
clsAttr='클래스 속성'
# 생성자
def __init__(self,instanceAttr):
self.instanceAttr=instanceAttr
# 인스턴스 메소드
def instanceMethod(self,start,end):
# 인스턴스 메소드에서 클래스 속성에 접근
print(MyClass.clsAttr)
print(f'self:{self},type:{type(self)}')
return self.instanceAttr[start:end]
# 정적 메소드 :인스턴스 속성이 필요 없는 경우 즉 인스턴스 내용과는 상관없이 결과만
# 구하면 될 때는 정적(혹은 클래스) 메서드를 사용
'''
@staticmethod를 데코레이터라 함
@staticmethod
def 메소드명([매개변수들]):
명령문
'''
@staticmethod
def staticMethod(delim,list_):
#print(self)#정적 메소드에서 인스턴스 멤버에 접근 불가
print(MyClass.clsAttr)# 정적 메소드에서 클래스 속성(메소드)에 접근
return delim.join(list_)
'''
정적메소드와 유사하다 그리고 클래스 메서드는 메서드 안에서 클래스 속성 이나
또 다른 클래스 메서드에 접근 할 때 주로 사용한다.
cls는 클래스를 의미한다
@classmethod
def 메서드(cls[,매개변수들]):
명령문
'''
@classmethod
def classMethod(cls,value,delim):
#print(self)#클래스 메소드에서 인스턴스멤버에 접근 불가
print(f'cls:{cls},type:{type(cls)}')
print(f'MyClass:{MyClass},type:{type(MyClass)}')
# 클래스 메소드에서 클래스 속성 접근
print(cls.clsAttr)#cls.클래스속성
print(MyClass.clsAttr)
# 클래스메소드에서 정적 메소드 접근
#cls.staticMethod('',[])
#MyClass.staticMethod('',[])
print(value.split(delim))
#MyClass를 인스턴스화 없이 클래스명으로 접근해서 정적 메소드 및 클래스 메소드 호출하기
value = MyClass.staticMethod('▲',['한라산','지리산','설악산'])
print(value)
MyClass.classMethod(value,'▲')
#클래스 속성 접근:클래스명으로 접근
print(MyClass.clsAttr)
#인스턴스 속성및 메소드 접근
myclass = MyClass('PYTHON')
print(myclass.instanceAttr)
print(myclass.instanceMethod(3,len('PYTHON')))
결과)
class6.py
'''
-클래스밖에서 접근 불가한 멤버(비 공개 속성 /메소드)
-해당 클래스안 에서만 접근 가능
-클래스 밖에서 마음대로 값을 변경하면 안되는 속성등에 적용한다
-비공개 속성은 메소드를 통해 값을 변경하도록 한다
self.__속성명=값 - 비공개 속성
def __메소드명(self[매개변수]): - 비공개 메소드
pass
__속성=값 - 비공개 클래스 속성
'''
class Private:
__clsAttr='비 공개 클래스 속성'
def __init__(self,value):
self.publicAttr=None#공개 속성
self.__privateAttr = value#비공개 속성
# 비공개 메소드
def __privateMethod(self):
print('비 공개 인스턴스 메소드')
# 공개 메소드
def publicMethod(self,value):
self.__privateAttr=value# 비공개 인스턴스 속성 값 설정
print(self.__privateAttr)
print(Private.__clsAttr)# 비공개 클래스 속성 출력
self.__privateMethod()# 비공개 메소드 호출
print(dir(Private))
#print(Private.__clsAttr)#AttributeError: type object 'Private' has no attribute '__clsAttr'
print(Private._Private__clsAttr)
#인스턴스화
pv = Private('비 공개 인스턴스 속성')
print(dir(pv))
print(pv.publicAttr)
#print(pv.__privateAttr)#ttributeError: 'Private' object has no attribute '__privateAttr'
print(pv._Private__privateAttr)
#pv.__privateMethod()#AttributeError: 'Private' object has no attribute '__privateMethod'
pv._Private__privateMethod()
pv.publicMethod('공개 메소드를 통해 접근')
결과)
class7.py
#파이썬에서 게터/세터 만들기
#방법1
'''
class Account:
def __init__(self):
self.__accNo=None
self.__name=None
self.__balance=None
# 게터
def getAccNo(self):return self.__accNo
def getName(self):return self.__name
def getBalance(self):return self.__balance
# 세터
def setAccNo(self,accNo):self.__accNo=accNo
def setName(self,name):self.__name=name
def setBalance(self,balance):self.__balance=balance
def print(self):
print(f'예금주:{self.__name},계좌번호:{self.__accNo},잔액:{self.__balance}')
#인스턴스화
acc = Account()
acc.print()
#세터로 설정
acc.setAccNo('123-456')
acc.setName('가길동')
acc.setBalance(1000)
acc.print()
print(acc.getName())
'''
#방법2
#데코레이터 사용하기
##@property사용시 형태는 메소드 형식이나
#속성으로 사용한다 함수객체가 아니다
class Account:
def __init__(self):
self.__accNo=None
self.__name=None
self.__balance=None
# 게터
@property
def accNo(self):return self.__accNo
# -> 다음이 반환타입 : 함수 바디
@property
def name(self)->object:return self.__name
@property
def balance(self)->object:return self.__balance
# 세터 : @메소드명.setter
@accNo.setter
def accNo(self,accNo):self.__accNo=accNo
@name.setter
def name(self,name):self.__name=name
@balance.setter
def balance(self,balance): self.__balance=balance
def print(self):
print(f'예금주:{self.__name},계좌번호:{self.__accNo},잔액:{self.__balance}')
acc = Account()
#@property를 붙인 경우:메소드를 마치 속성처럼 사용한다
print(acc.accNo)
#print(acc.accNo())#TypeError: 'NoneType' object is not callable
#게터/세터를 사용할때는 속성처럼 사용(메소드 호출 식하면 에러)
#세터 호출
acc.name='나길동'
acc.balance=1000
acc.accNo='123-456'
acc.print()
#게터 호출
print(acc.name)
결과)
class8.py
#자식의 생성자 정의시 부모의 생성자를 super()로 명시적으로 호출하지 않으면
#부모 생성자는 호출되지 않는다
#즉 부모의 생성자를 호출하여 부모의 속성을 초기화 하려면 반드시
#super().__init__()를 호출해 해야 한다
#부모클래스
class Person(object):#object클래스 상속
def __init__(self,name,age):
print('부모의 생성자')
self.name=name
self.age=age
def eat(self):
print(self.name,'님께서 드신다',sep='')
def print(self):
print(f'성함:{self.name},연세:{self.age}',end='')
#자식 클래스
class Student(Person):#Person클래스 상속
#생성자 미 정의시 자동으로 아래 코드가 추가된다
#즉 Student의 생성자는 인자 name 및 age를 생성자이다(부모의 생성자 형태대로 자식의 생성자가 생성된다)
'''
def __init__(self,name,age):
super().__init__(name,age)#부모 생성자 호출
'''
def __init__(self,name,age,hakbun):
super().__init__(name,age)#부모의 생성자는 무조건 명시적으로 호출하자
self.hakbun =hakbun
def study(self):
self.eat()
super().eat()
print(f'나이가 {self.age}살이고 이름이 {self.name}이고 학번이 {self.hakbun}인 학생이 공부하다')
def printInfo(self):
self.print()
print(',학번:',self.hakbun)
#[자식의 생성자 미 정의]
#1. 인자가 없는 생성자로 객체 생성
#student = Student()#TypeError: Person.__init__() missing 2 required positional arguments: 'name' and 'age'
#2. 인자 name,age를 전달하는 생성자로 객체 생성
'''
student = Student('가길동',20)
student.eat()
student.print()
'''
#[자식의 생성자 정의]
student = Student('가길동',20,'2023')
print(dir(student))
student.study()
student.printInfo()
결과)
class9.py
'''
-부모 클래스에 있는 메서드를 동일한 이름으로 재정의 하는 것을
메서드 오버라이딩(Overriding)이라고 한다.
이렇게 메서드를 오버라이딩하면 부모 클래스의 메서드 무시되고
오버라이딩한 메서드가 호출된다.
- 메소드 오버라이딩은 원래 기능을 유지하면서 새로운 기능을 추가할때 주로 사용한다
'''
class Base:
def __init__(self,attr):
self.attr=attr
def getInfo(self):
return f'부모의 속성 attr:{self.attr}'
def print(self):
print(self.getInfo())
class Derived(Base):
def __init__(self,attr,attr_):
super().__init__(attr)
self.attr_ = attr_
def getInfo(self):
#부모로 부터 상속받은 속성이나 메소드접근시 self.속성 혹은 self.메소드()
#단,오버라이딩시에는 부모의 메소드명과 이름동일하기때문에
#super().메소드명으로 호출하자
#return f'{self.getInfo()},자식의 속성 attr_:{self.attr_}'#RecursionError: maximum recursion depth exceeded
return f'{super().getInfo()},자식의 속성 attr_:{self.attr_}'
dev = Derived('base','derived')
print(dev.getInfo('코스모'))
dev.print()#오바라이딩한 메소드(자식의 getInfo())가 호출됨
결과)
결과는 같지만 동작 방식이 다름
처음 print(dev.getInfo())는 자식에서 오버라이딩된 걸 출력한다면,
dev.print()는 dev가 자식이니 부모 메서드를 다 가지고 있을 것이고, 그중에 getInfo()만 오버라이딩되고, print()는 부모걸 씀, 또 getInfo()를 부르는데 부모 걸 부르겠지만 오버라이딩은 최신화 개념으로 여기서 자식걸 가져온다
한마디로 자식 된 메서드를 부르는가, 아니면 부모걸 부르는데 오버라이딩된 메서드어서 그걸 가져오게 되는 것인가 그 차이이다.
class10.py
'''
1.abc 모듈을 import한다(abc는 abstract base class의 약자)
2.클래스의 (괄호) 안에 metaclass=ABCMeta를 지정
3.메서드 위에 @abstractmethod를 붙여서 추상 메서드로 지정
4.pass로 빈 메소드 정의
5.추상 메소드를 정의하면 인스턴스화 불가
'''
from abc import *
print(dir())
class Abstract(metaclass=ABCMeta):#추상 클래스
# 생성자는 가질수 있다
def __init__(self,attr):
print('추상 클래스의 생성자')
self.attr=attr
@abstractmethod
def abstract(self):#추상 메소드-구현부가 없어야 한다(오버라이딩이 목적)
pass
def general(self):
print('일반 메소드')
#추상 메소드를 오버라이딩 하지 않은 경우 역시 자식도 추상클래스가 된다
class General(Abstract):
'''
def __init__(self,attr):
super().__init__(attr)
'''
def abstract(self):#추상 메소드 오버라이딩
print('자식에서 오버라이딩:',self.attr)
#추상 클래스 인스턴스화(단,추상 메소드가 없는 경우는 인스턴스화 가능)
#ac = Abstract('추상 클래스')#TypeError: Can't instantiate abstract class Abstract with abstract method abstract
#추상 메소드 오버라이딩 하지 않은 경우
#ge = General('자식클래스')#TypeError: Can't instantiate abstract class Abstract with abstract method abstract
#추상 메소드 오버라이딩 한 경우
ge = General('자식클래스')
ge.abstract()
결과)
※ 이제 끝나고 basic폴더를 하나 생성해서 넣었음
Flask
패키지 중에서 파이썬이 너무 최신 버전이면 안 되는 패키지들이 있음
그걸 가능하게 만들기 위해 파이썬 3.11 버전을 3.9 버전으로 변경,
낮은 버전의 파이썬을 실행하기 위한 가상환경을 먼저 구축,
파이썬 주소:3.9 버전
https://www.python.org/downloads/release/python-390/
flask 설치
https://flask-docs-kr.readthedocs.io/ko/latest/quickstart.html
빠르게 시작하기 — Flask 0.11-dev documentation
웹 어플리케이션에 있어서 클라이언트에서 서버로 보내는 데이타를 처리하는 것은 중요한 일이다. Flask에서 이 정보는 글로벌한 request 객체에 의해 제공된다. 여러분이 파이썬 경험이 있다면,
flask-docs-kr.readthedocs.io
가상환경 설치
그럼 이제 파이참에서
app1.py
만약 myapp =Flask(__name__) 이렇게 썼으면
아래는 @myapp 이렇게 써야 된다.
debug를 주면 코드가 변경되면 자동으로 로드
실제 배포일 때는 False 줘야 된다.
app1.py
from flask import Flask# Flask 앱 생성용
from flask import request#url에 따른 요청 객체
#하나의 웹 어플리케이션 생성
app = Flask(__name__)#app는 WSGI어플리케이션(WSGI(Web Server Gateway Interface)를 따르는 웹 어플리케이션)
#@app.route('/로 시작하는 url') 데코레이터로 url요청과 요청을 처리할 함수 매핑 : 라우팅한다
#라우팅 함수(view function)는 반드시 리턴해야 한다 즉 응답을 해야한다
#TypeError: The view function for '함수명' did not return a valid response
#1.GET방식(디폴트)요청
@app.route('/')
def index():
print('Hello World')
# 브라우저로 전송되는 문자열(응답바디에 쓰이는 문자열)
# 문자열 전송시 응답헤더 Content-Type 디폴트는 text/html; charset=utf-8
return '<h2>Hello World!</h2>'
#2. 데이타 받기:GET - URL
@app.route('/query',methods=['GET'])#반드시 [] 리스트로 설정
def query():
# 쿼리 스트링 받기(GET요청:KEY=VALUE):request.args.get('파라미터명')
name=request.args.get('name')
username = request.args.get('username')
password = request.args.get('password')
return f'''
<ul>
<li>이름 : {name}</li>
<li>아이디 : {username}</li>
<li>비밀번호 : {password}</li>
</ul>
'''
#3. 데이타 받기:POST - 요청바디
@app.route('/post',methods=['POST'])
def post():
# 요청바디 받기(POST요청:KEY=VALUE):request.form['파라미터명']
name = request.form['name']
username = request.form['username']
password = request.form['password']
return f'''
<ul>
<li>이름 : {name}</li>
<li>아이디 : {username}</li>
<li>비밀번호 : {password}</li>
</ul>
'''
#4.GET방식 및 POST요청 모두 받기(파라미터 포함)
@app.route('/both',methods=['POST','GET'])
def both():
# GET/POST상관없이 파라미터 받기
# request.values.get('파라미터명')
name = request.values.get('name')
username = request.values.get('username')
password = request.values.get('password')
method=None
if request.method == 'GET':
method ='<h1>GET방식 요청입니다</h1>'
else:
method = '<h1>POST방식 요청입니다</h1>'
return f'''
{method}
<ul>
<li>이름 : {name}</li>
<li>아이디 : {username}</li>
<li>비밀번호 : {password}</li>
</ul>
'''
#5.데이타 받기 - URL 파라미터(혹은 패스 파라미터)
@app.route('/path/<name>')
def path(name):
return f'<h2>URL 파라미터:{name}</h2>'
if __name__ == '__main__':
#app.run(debug=True)
'''
디폴트 포트 5000
debug=False이 디폴트 .debug=True 서버는 코드 변경을 감지하고 자동으로 리로드
#host='0.0.0.0' 원격의 모든 호스트에서 접속 가능하도록 설정시
(디폴트는 127.0.0.1으로 로컬에서만 접속 가능한 테스트서버가 된다).
'''
# Flask의 테스트 서버(프레임워크에 내장된)에서 실행(배포용은 비권장)
app.run(host='0.0.0.0',port=8282,debug=True)
app2.py
정적 파일들(js,. css, img파일 등)을 가져오기 위해서는 External Libraies에서 templates란 폴더를 만들어 줘야 한다. 이게 기본 파일명이다.
폴더를 어디서 만들어야 되는가는 실험해 보니 똑같음 그냥 flask_env에서 templates를 생성.
맛보기: jinja2 문법
특이하게 중괄호가 2겹이 있다
templates폴더의 form.html로 간다
templates폴더에 있는 static.html
<!DOCTYPE html>
<html lang="en">
<head>
<!--url_for('정적파일위치시킬 루트 폴더명',filename='루트를 제외한 정적파일의 전체 경로')-->
<meta charset="UTF-8">
<link rel="stylesheet" href="{{url_for('static',filename='styles/style.css')}}">
<script src="{{url_for('static',filename='js/jquery-3.6.2.min.js')}}"></script>
<script>
/*
CORS에러 발생시
1. pip install flask_cors 설치
2. app.py에서 from flask_cors import CORS
3. app = Flask(__name__)
CORS(app)# 이 코드 추가
*/
$(function(){
$('#ajax').click(function(){
$.ajax({
url:'http://localhost:8282/ajax',
data:JSON.stringify({name:'한소인'}),
contentType:'application/json',
type:'post',
dataType:'json'
}).
done(function(data){
console.log('서버로 부터 받은 데이타:',data)
}).
fail(function(e){
console.log('에러:',e)
});
});
});
</script>
<title>정적파일</title>
</head>
<body>
<h2>정적파일 사용하기</h2>
<img src="{{url_for('static',filename='images/flask.png')}}" alt="Flask이미지"/>
<a href="#" id="ajax">AJAX요청</a>
</body>
</html>
app2.py 전체
from flask import Flask# Flask 앱 생성용
from flask import request#url에 따른 요청 객체(Request)
from flask import render_template#템플릿 파일(.html) 서비스용
from flask import make_response#응답 객체(Response) 생성용
#app=Flask(__name__,template_folder='webapp')#템플릿 파일의 기본 폴더 위치명 변경시
app=Flask(__name__,)
'''
[템플릿 파일 사용하기]
Flask 템플릿 파일은 .html을 사용하고 템플릿 엔진은 jinja2
.html파일을 기본적으로 app.py가 실행되는 같은 위치에 templates폴더에서 찾는다
단,app = Flask(__name__,template_folder='임의의 폴더명')코드로 templates 폴더명 변경 가능
템플릿 파일인 .html파일을 templates 폴더에 저장
'''
#HTML FORM요소로 요청 보내고 받기
#1.str타입으로 응답하기
@app.route('/')# 입력폼으로 이동
def index():
# 렌더링된 HTML소소 문자열 반환(문자열로 응답)
# 디폴트로 form.html파일을 templates폴더에서 찾는다
return render_template('form.html')
@app.route('/form',methods=['POST'])
def form():
name = request.form['name']
username = request.form['username']
password = request.form['password']
#직접 문자열(str) 반환
return f'''
<ul>
<li>이름 : {name}</li>
<li>아이디 : {username}</li>
<li>비밀번호 : {password}</li>
</ul>
'''
#2.Response객체로 응답하기
@app.route('/response')
def response():
# 브라우저로 응답하는 방법
# 방법1. 문자열로 응답 - 응답헤더 설정 불가(Content-Type은 디폴트 text/html;charset=UTF-8)
# render_template('html파일명')함수(즉 렌더링된 HTML소스 문자열 반환) 혹은 직접 문자열 반환
# 방법2. Response객체로 응답
# 응답헤더 설정 가능 즉 응답헤더를 설정해야할때 사용(JSON으로 응답시(내부적으로 utf8을 사용))
response=make_response(render_template('index.html'))
# 응답헤더 설정
# response.headers['헤더명'] = '헤더값'
# response.헤더명='헤더값'
#response.content_type='text/plain;charset=utf-8'
response.headers['content-type']='text/html;charset=utf-8'
return response
#3.정적 자원(이미지,.css,.js등) 사용하기
@app.route('/static')
def static_resource():
return render_template('static.html')
if __name__ =='__main__':
app.run(host='0.0.0.0',port=8282,debug=True)