Python

85일차 2023-07-07

choi Hoon 2023. 7. 7. 22:01

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폴더를 하나 생성해서 넣었음

이건 원래 있던 파이썬 3.11버전

 

 

Flask

 

 

패키지 중에서 파이썬이 너무 최신 버전이면 안 되는 패키지들이 있음

 

그걸 가능하게 만들기 위해 파이썬 3.11 버전을 3.9 버전으로 변경,

낮은 버전의 파이썬을 실행하기 위한 가상환경을 먼저 구축,

virtualenv.txt
0.00MB

 

 

 

 

파이썬 주소:3.9 버전

https://www.python.org/downloads/release/python-390/

Windows x86-64 execytable installer 설치

flask 설치

https://flask-docs-kr.readthedocs.io/ko/latest/quickstart.html

 

빠르게 시작하기 — Flask 0.11-dev documentation

웹 어플리케이션에 있어서 클라이언트에서 서버로 보내는 데이타를 처리하는 것은 중요한 일이다. Flask에서 이 정보는 글로벌한 request 객체에 의해 제공된다. 여러분이 파이썬 경험이 있다면,

flask-docs-kr.readthedocs.io

가상환경 설치

가상환경 이런 류는 최신버전으로 설치(안해도됨, 권장)

 

 

파이썬 3.9버전으로 설치
디렉토리 확인
경로 flask_env로 잡음
이런식으로 경로 이동
(flask_env) 이렇게된게 활성화 이다

그럼 이제 파이참에서

여기로 오픈 폴더
우측 톱니바퀴로 설정을 들어감

app1.py

 

app란 이름 설정
@app가 받는 이름

만약 myapp =Flask(__name__) 이렇게 썼으면

아래는 @myapp 이렇게 써야 된다.

 

 

debug=True로 안줘도 된다

debug를 주면 코드가 변경되면 자동으로 로드

실제 배포일 때는 False 줘야 된다.

 

쿼리스트링

 

/pah/chi

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란 폴더를 만들어 줘야 한다. 이게 기본 파일명이다.

꼭, templates로 만들어야됨

폴더를 어디서 만들어야 되는가는 실험해 보니 똑같음 그냥 flask_env에서 templates를 생성.

 

 

 

 

 

 맛보기: jinja2 문법

templates폴더에 있는 static.html에 있는 것이다

 

 

 

 

 

특이하게 중괄호가 2겹이 있다

templates폴더의 form.html로 간다

 

 

결과

 

 

templates폴더에 있는 index.html
8282/response로 보냄

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)