Now Loading ...
-
-
Django advance
Advance
HttpRequest
HttpRequest.headers # request의 headers 객체
HttpRequest.body # request의 body 객체
HttpRequest.COOKIES # 모든 쿠키를 담고 있는 딕셔너리 객체
HttpRequest.method # reqeust의 메소드 타입
HttpRequest.FILES # 로 보낸 UploadFile!
HttpRequest.META # HTTP 헤더가 포함하는 모든 접근 가능한 정보를 담고 있는 dict, 메타 정보는 (당연히) web-server에 영향을 받는다.
HttpRequest.GET # GET 파라미터를 담고 있는 QueryDict instance
HTTpRequest.POST # POST 파라미터를 담고 있는 QueryDict instance
queryDict instance
Query Expression
F function
python에서 핸들링 하는것이 아닌 Query로 만들어서 database에서 핸들링을 할 수 있는 방법입니다.
{% highlight python %}
User.objects.all().update(user_id=F(‘user_id’) + 1) # Base
company = Company.objects.annotate(chairs_needed=F(‘num_employees’) - F(‘num_chairs’)) # annotate same field
from django.db.models import DateTimeField, ExpressionWrapper, F
Ticket.objects.annotate(
expires=ExpressionWrapper(
F(‘active_at’) + F(‘duration’),
output_field=DateTimeField()
)
) # annotate different field
{% endhighlight %}
Docs
Func function
Func 방식은 Django에서 구현되지 않은 query의 구문을 사용하고자 할때 활용 가능합니다.
{% highlight python %}
class UNNEST(Func):
function = ‘UNNEST’
temp = Test.objects.annotate(user=UNNEST(‘user’))
{% endhighlight %}
Func
Q function
Q 방식은 Django에서 구현되어 있는 구현체로 조건들을 활용할때 사용하기 좋습니다.
{% highlight python %}
Product.objects.filter(Q(category=’A’) & Q(sub_category=’AB’))
{% endhighlight %}
Value function
Value는 기본적인 형태로 단순한 값을 의미합니다.
{% highlight python %}
User.objects.filter(“user”, Value(“_”), “id”)
{% endhighlight %}
annotate function
annotate는 별칭을 주는것과 같으며 nested와 같은 구조에서 명칭이 복잡할때 사용 가능합니다.
{% highlight python %}
logs = OrderLog.objects.annotate(
name=F(“product__name”),
price=F(“product__price”)
).values(
‘created’, ‘name’, ‘price’
)
{% endhighlight %}
subquery function
subquery는 query를 사용하여 query를 만드는 복잡한 형태의 query를 구성할때 사용합니다.
{% highlight python %}
from django.db.models import OuterRef, Subquery
newest = Comment.objects.filter(post=OuterRef(‘pk’)).order_by(‘-created_at’)
Post.objects.annotate(newest_commenter_email=Subquery(newest.values(‘email’)[:1]))
{% endhighlight %}
Transaction
database에서 일관적으로 한번에 작업이 되어야하는 단위를 transaction 이라합니다. 이를 통하여 안정된 서비스를 구현할 수 있으나 과도한 transaction은 오히려 서비스를 느리게 만들 수 있습니다.
{% highlight python %}
from django.db import transaction
@transaction.atomic()
def update_user(user_id: int, updated_company_name: str):
Profile.objects.filter(user__id=user_id).update(company_name=updated_company_name)
User.objects.filter(id=user_id).update(company_name=updated_company_name)
{% endhighlight %}
commit()
transaction을 종료하며 저장합니다.
rollback()
transaction을 종료하며 처음으로 돌아갑니다.
on_commit()
transaction commit 종료 이후에 동작이 되야할 경우 사용
savepoint()
transaction 도중에 savepoint를 지정하여 commit 또는 rollback같은 작업을 할 수 있습니다.
Signal
signal은 main logic과 별개로 실행해야하는 작업이 있을때 사용할 수 있습니다. 하지만 비동기적으로 작동되는 로직이 아니라서 celery와 같은것을 활용하는것을 추천합니다.
{% highlight python %}
우선 signals.py 를 특정 앱(여기선 user) 안에 만든다.
from django.db.models.signals import post_save
from django.contrib.auth.models import User
def create_profile(sender, instance, created, **kwargs):
if created == True:
user = instance
profile = Profile.objects.create(
owner = user,
user_name = user.username,
email = user.email,
name = user.first_name,
)
post_save.connect(create_profile, sender=User)
아래에서 더 자세히 보겠지만, connect를 쓰기 싫으면, 아래 app config를 진행하면 된다.
signal의 코드 분리를 위해 app config에서, app이 load 될 때 signal을 import하게 한다.
(user) apps.py
class UserConfig(AppConfig):
name = ‘user’
def ready(self) -> None:
# DB signal
import app.user.signals
return super().ready() {% endhighlight %}
-
Django view
What is View
How to use View
view를 사용하는 방식은 Fuction, Class 두가지 방식이 있습니다. 원래의 Django는 Fuction으로 구성되어 있었으나 OOP의 장점을 이용하는 Class 형식이 추후에 추가 되었습니다.
FBV
다음은 Fuction을 사용한 View의 기본 예제입니다.
{% highlight python %}
@api_view([‘GET’, ‘POST’])
def index(request):
if request.method == ‘POST’:
return HttpResponse(“Post method”)
else:
return HttpResponse(“Get method”)
{% endhighlight %}
CBV
다음은 class를 사용한 View의 기본 예제입니다. 이러한 방식은 상속과 같이 확장성을 가지지만 모든 상황에서 최선은 아닙니다.
{% highlight python %}
from django.views import View
class ContactView(View):
def post(self, request):
return HttpResponse(“Post method”)
def get(self, request):
return HttpResponse(“Get method”)
{% endhighlight %}
{% highlight python %}
quickstart/views.py
from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework.parsers import JSONParser # 그냥 json 파싱만 위해,,
@csrf_exempt
def snippet_list(request):
“””
List all code snippets, or create a new snippet.
“””
if request.method == ‘GET’:
snippets = Snippet.objects.all()
serializer = SnippetSerializer(snippets, many=True)
return JsonResponse(serializer.data, safe=False)
elif request.method == 'POST':
data = JSONParser().parse(request)
serializer = SnippetSerializer(data=data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data, status=201)
return JsonResponse(serializer.errors, status=400) {% endhighlight %}
Prev(how to start)
Prev
-
Django serializer
What is serializer
Django의 serializer는 많은 역활을 담당합니다. 그중 대표적인 사용처는 json <-> dict 형태로의 치환을 주로 해주게 됩니다. 이러한 이유는 rest api에서 사용하는 형식과 python에서 사용하는 형식이 다르기 때문입니다.
normal serializer
일반적인 seriallizer는 serializers.Serializer의 상속을 받아 아래와 같이 작성하게 됩니다.
{% highlight python %}
class UserSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
name = serializers.CharField(required=False, allow_blank=True, max_length=10)
def create(self, validated_data):
return models.User.objects.create(**validated_data) {% endhighlight %}
위와 같은 방식은 model과 상관없이 serializer를 설정하고 싶을때 사용할 수 있으며, model을 활용하여 사용하는 방법도 있습니다.
model serializer
model seriallizer는 serializers.ModelSerializer의 상속을 받아 아래와 같이 작성하게 됩니다. 아래의 방식은 model이 선언되어 있을때 사용하기 용이하며 코드를 간편하게 해줍니다.
{% highlight python %}
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = models.User
fields = [‘id’, ‘name’]
{% endhighlight %}
method field
method field는 다른 field를 활용하여 재가공하여 사용하는 방식입니다. 대표적으로 id값이 있고 id의 길이를 확인하는 방법입니다.
{% highlight python %}
class UserSerializer(serializers.ModelSerializer):
is_long = serializers.SerializerMethodField()
class Meta:
model = models.User
fields = ['id', 'name']
def get_is_long(self, instance: CheckedCrn):
if len(instance.id) > 2:
return "long"
else:
return "short" {% endhighlight %}
dict -> json -> dict
때에 따라서는 데이터의 형태가 계속 변경이 되어야 할 수 있습니다. 그에따라 형변환을 하는 법을 나타냅니다.
{% highlight python %}
import io
from rest_framework.renderers import JSONRenderer
content = JSONRenderer().render(serializer.data) # json
stream = io.BytesIO(content)
data = JSONParser().parse(stream)
serializer = UserSerializer(data=data)
serializer.is_valid()
serializer.validated_data # check data
serializer.save()
serializer.data # dict
{% endhighlight %}
nested serializer
N in (1:N)
1:N 의 형식에서 N의 입장은 다음과 같이 바로 활용이 가능합니다.
seriallizer
{% highlight python %}
class GroupOnlySerializer(serializers.ModelSerializer):
class Meta:
model = Group
fields = “all”
class UserWithGroupSerializer(serializers.ModelSerializer):
product = GroupOnlySerializer(read_only=True)
class Meta:
model = User
fields = "__all__" {% endhighlight %}
view
{% highlight python %}
class UserListAPIView(generics.ListAPIView):
“””
User GET ALL API
“””
queryset = User.objects.all().order_by(“-id”)
serializer_class = UserWithGroupSerializer
{% endhighlight %}
1 in (1:N)
1:N 의 형식에서 1의 입장은 역참조를 해야 하기 때문에 조금은 복잡합니다.
Read case
seriallizer
{% highlight python %}
class GroupSerializer(serializers.ModelSerializer):
class Meta:
model = Group
fields = “all”
class UserSerializer(serializers.ModelSerializer):
product = GroupSerializer(read_only=True, many=True)
class Meta:
model = User
fields = "__all__" {% endhighlight %}
view
{% highlight python %}
class UserListAPIView(generics.ListAPIView):
“””
User GET ALL API
“””
queryset = User.objects.all().order_by(“-id”)
serializer_class = UserSerializer
{% endhighlight %}
Write case
write case에서는 원래 read만 가능하기 때문에 create를 override하여 새로이 구성해줘야 합니다.
seriallizer
{% highlight python %}
class GroupSerializer(serializers.ModelSerializer):
class Meta:
model = Group
fields = “all”
class UserSerializer(serializers.ModelSerializer):
product = GroupSerializer(read_only=True, many=True)
class Meta:
model = User
fields = "__all__" {% endhighlight %}
view
{% highlight python %}
class UserListAPIView(generics.ListAPIView):
“””
User GET ALL API
“””
queryset = User.objects.all().order_by(“-id”)
serializer_class = UserSerializer
def create(self, validated_data):
groups = validated_data.pop(‘group’)
user = User.objects.create(**validated_data)
for group in groups:
Group.objects.create(user=user, **group)
return user
{% endhighlight %}
Prev(how to start)
Prev
-
Django models
What is model
Django에서 model은 DB의 구조를 나타내어집니다.
How to use model
model의 사용법은 다음과 같습니다.
<app-name>.models.py 생성
{% highlight shell %}
from django.contrib.auth.models import User
from django.db import models
class UserDetail(models.Model):
user = models.ForeignKey(
User, verbose_name=”user 정보”, on_delete=models.DO_NOTHING
)
user_email = models.IntegerField(verbose_name=”user email”, null=False, primary_key=True)
class Meta:
db_table = "userdetail"
managed = True
verbose_name = "user 상세 정보"
verbose_name_plural = "user 상세 정보 목록" {% endhighlight %}
<app-name>.admin.py 추가(case 1)
{% highlight shell %}
from django.contrib import admin
from .models import Cart
class CartAdmin(admin.ModelAdmin): # admin 페이지에 표기할 column 지정
list_display = (‘', '')
admin.site.register(Cart, CartAdmin) # admin page에 등록
{% endhighlight %}
<app-name>.admin.py 추가(case 2)
{% highlight shell %}
from django.contrib import admin
from .models import Cart
@admin.register(Cart) # admin page에 등록
class CartAdmin(admin.ModelAdmin): # admin 페이지에 표기할 column 지정
list_display = (‘', '')
{% endhighlight %}
Field of model
model의 column들을 정의 하는 field는 다음과 같이 사용할 수 있습니다.
ID Field
Field 타입
설명
AutoField
1에서 부터 자동적으로 증가합니다.
BigAutoField
1 ~ 9223372036854775807까지 1씩 자동으로 증가하는 필드입니다.
UUIDField
UUID 전용 필드입니다.
String Field
Field 타입
설명
CharField
적은 문자열을 저장하는 필드입니다.
TextField
많은 문자열을 저장하는 필드입니다.
URLField
URL을 저장하는 필드입니다.
EmailField
E-mail을 저장하는 필드입니다.
String Field
Field 타입
설명
CharField
적은 문자열을 저장하는 필드입니다.
Data Field
Field 타입
설명
BinaryField
Binary 데이터를 저장하는 필드입니다.
DecimalField
Decimal 데이터를 저장하는 필드입니다.
IntegerField
Interger 데이터를 저장하는 필드입니다.
PositiveIntegerField
양수만 취급하는 Interger 데이터를 저장하는 필드입니다.
FloatField
Float 데이터를 저장하는 필드입니다.
BooleanField
참/거짓 데이터를 저장하는 필드입니다.
NullBooleanField
Null값이 가능한 참/거짓을 저장하는 필드입니다.
Time Field
Field 타입
설명
DateField
날짜 데이터를 저장하는 필드입니다.
TimeField
시간 데이터를 저장하는 필드입니다.
DateTimeField
날짜와 시간 데이터 모두 저장할 수 있는 필드입니다.
File Field
Field 타입
설명
ImageField
이미지 데이터를 저장하는 필드입니다.
FileField
파일 업로드 데이터를 저장하는 필드입니다.
FilePathField
파일 경로 데이터를 저장하는 필드입니다.
Relation Field
Field 타입
설명
OneToOneField
일대일 관계를 저장하는 필드입니다.
ForeignKey
일대다 관계를 저장하는 필드입니다.
ManyToManyField
다대다 관계를 저장하는 필드입니다.
더 많은 정보는 다음에 포함되어 있습니다.
relations
Field Option
Field의 옵션은 다음과 같으며 모든 Field가 모든 옵션을 사용할 수는 없습니다.
Field 옵션
설명
기본값
default
필드의 기본값을 설정합니다.
-
help_text
도움말 텍스트를 설정합니다.
-
null
Null 값 허용 유/무를 설정합니다.
False
blank
비어있는 값 허용 유/무를 설정합니다.
False
unique
고유 키 유/무를 설정합니다.
False
primary_key
기본 키 유/무를 설정합니다. (null=False, unique=True와 동일)
False
editable
필드 수정 유/무를 설정합니다.
False
max_length
필드의 최대 길이를 설정합니다.
-
auto_now
개체가 저장될 때마다 값을 설정합니다.
False
auto_now_add
개체가 처음 저장될 때 값을 설정합니다.
False
on_delete
개체가 제거될 때의 동작을 설정합니다.
-
db_column
데이터베이스의 컬럼의 이름을 설정합니다.
-
Meta Option
Meta 옵션은 다음과 같습니다.
Meta 옵션
설명
기본값
abstract
추상 클래스 유/무를 설정합니다.
False
db_table
모델에 사용할 데이터베이스 테이블의 이름을 설정합니다.
-
managed
데이터베이스의 생성, 수정, 삭제 등의 권한을 설정합니다.
True
ordering
객체를 가져올 때의 정렬 순서를 설정합니다.
-
verbose_name
사람이 읽기 쉬운 객체의 이름을 설정합니다. (단수형으로 작성)
-
verbose_name_plural
사람이 읽기 쉬운 객체의 이름을 설정합니다. (복수형으로 작성)
-
model manager
model은 기본적으로 objects를 manager로 가지게 되어있습니다. 하지만 아래와 같이 override할 수 있습니다.
{% highlight shell %}
class DeletedManager(models.Manager):
use_for_related_fields = True # default manager로 사용시 관계에서 모두 활용 가능
def deleted(self, **kwargs):
return self.filter(is_deleted=False, **kwargs)
def get_queryset(self):
return super().get_queryset().filter(is_deleted=False) {% endhighlight %}
{% highlight shell %}
class Post(models.Model):
objects = DeletedManager()
{% endhighlight %}
structure of model
구조는 위에 나열한 Field를 추가하여 주면 되며, Meta를 사용한 abstract기능을 True로 해주면 상속을 할 수 있는 상태가 됩니다. 아래는 default로 있는 User정보의 abstract를 활용한 예시입니다. Mixedin은 2개이상의 상속을 받을때 사용하며, abstract와 같으나 명칭만 다릅니다.
{% highlight python %}
class User(AbstractBaseUser, PermissionsMixin):
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['nickname', ]
class Meta:
ordering = ('-date_joined',)
def __str__(self): # object 호출시 지정할 명칭
return self.nickname
{% endhighlight %}
migration
migration은 DB와 코드간의 상태를 확인하는 작업입니다. 아래의 코드는 migration을 하는데 있어 주로 사용되는 코드입니다.
{% highlight shell %}
python manage.py showmigrations # migration의 상태확인
python manage.py makemigrations # migration 생성
python manage.py migrate # migration 적용
python manage.py –fake zero # 의 migration 초기화
python manage.py --fake-initial # fake migration 생성
{% endhighlight %}
-
-
Django additional module
What is Django debug toolbar
Django의 webpage들에서 debug 정보를 바로 확인하기 위한 middleware입니다.
How to setting
다음은 Django debug toolbar를 설치하는 방법입니다.
django-debug-toolbar 설치
{% highlight shell %}
pip install django-debug-toolbar
{% endhighlight %}
<proj-name>.settings.py에서 확인, 추가
{% highlight python %}
INSTALLED_APPS = [
# …
“django.contrib.staticfiles”,
# …
]
STATIC_URL = “static/”
{% endhighlight %}
<proj-name>.settings.py에서 확인, 추가
{% highlight python %}
TEMPLATES = [
{
“BACKEND”: “django.template.backends.django.DjangoTemplates”,
“APP_DIRS”: True,
# …
}
]
{% endhighlight %}
<proj-name>.settings.py에 추가
{% highlight python %}
INSTALLED_APPS = [
# …
“debug_toolbar”,
# …
]
{% endhighlight %}
<proj-name>.urls.py에 추가
{% highlight python %}
from django.conf import settings
if settings.DEBUG:
import mimetypes
mimetypes.add_type(“application/javascript”, “.js”, True)
import debug_toolbar
urlpatterns += [
path(r’^debug/’, include(debug_toolbar.urls)),
]
{% endhighlight %}
<proj-name>.settings.py에 추가
{% highlight python %}
MIDDLEWARE = [
# …
“debug_toolbar.middleware.DebugToolbarMiddleware”,
# …
]
{% endhighlight %}
<proj-name>.settings.py에 추가
{% highlight python %}
INTERNAL_IPS = [
# …
“127.0.0.1”,
# ...
]
{% endhighlight %}
위의 방식을 전부 완료하고 나서 Django proj를 실행하면 오른쪽에 debug toolbar가 보여집니다. 혹시나 보여지지 않으시다면 아래의 코드를 추가해주세요.
<proj-name>.urls.py에 추가
{% highlight python %}
import mimetypes
mimetypes.add_type(“application/javascript”, “.js”, True)
{% endhighlight %}
What is Django celery
Django에서 celery를 활용하여 worker와 broker를 사용하는 기능입니다.
How to setting
다음은 Django celery(W.redis)를 설치하는 방법입니다.
<proj-name>.celery.py 생성
{% highlight python %}
import os
from celery import Celery
Set the default Django settings module for the ‘celery’ program.
os.environ.setdefault(‘DJANGO_SETTINGS_MODULE’, ‘mysite.settings’)
app = Celery(‘projs’)
Using a string here means the worker doesn’t have to serialize
the configuration object to child processes.
- namespace=’CELERY’ means all celery-related configuration keys
should have a CELERY_ prefix.
app.config_from_object(‘django.conf:settings’, namespace=’CELERY’)
Load task modules from all registered Django apps.
app.autodiscover_tasks()
@app.task(bind=True, ignore_result=True)
def debug_task(self):
print(f’Request: {self.request!r}’)
{% endhighlight %}
<proj-name>.settings.py에 추가
{% highlight python %}
CELERY_BROKER_URL = ‘redis://127.0.0.1:6379/0’
CELERY_RESULT_BACKEND = ‘redis://127.0.0.1:6379/0’
CELERY_ACCEPT_CONTENT = [‘application/json’]
CELERY_RESULT_SERIALIZER = ‘json’
CELERY_TASK_SERIALIZER = ‘json’
CELERY_TIMEZONE = ‘Asia/Seoul’
CELERY_BROKER_CONNECTION_RETRY_ON_STARTUP = True
{% endhighlight %}
<proj-name>.__init__.py에 추가
{% highlight python %}
from .celery import app as celery_app
all = (‘celery_app’,)
{% endhighlight %}
shared_task 데코레이터를 사용한 함수 delay로 실행
{% highlight python %}
from celery import shared_task
{% endhighlight %}
위와 같이 코드를 완성하고 나서 다음의 코드로 celery를 구동시키면 사용이 가능합니다.
{% highlight shell %}
celery -A worker -l INFO
{% endhighlight %}
-
Django intro
What is Django
Django python으로 구현된 web framework입니다.
Getting start
다음은 아주 기본적인 django 의 실행방식입니다.
{% highlight shell %}
pip install Django # Django 설치
python -m django –version # Django 설치 확인
django-admin startproject # 프로젝트 생성
cd
python manage.py runserver # 프로젝트 실행
{% endhighlight %}
다음은 startproject로 생성되는 파일의 구조입니다.
<proj-name>/
manage.py
<proj-name>/
__init__.py
settings.py
urls.py
asgi.py
wsgi.py
Creating App
다음은 django에서 App을 만들고 연결하는 방법입니다.
{% highlight shell %}
python manage.py startapp # create App
{% endhighlight %}
다음은 startapp으로 생성되는 dir의 구조 입니다.
<app-name>/
__init__.py
admin.py
apps.py
migrations/
__init__.py
models.py
tests.py
urls.py
views.py
<app-name>/views.py
{% highlight python %}
from django.http import HttpResponse
def index(request):
return HttpResponse(“Hello, world. You’re at the polls index.”)
{% endhighlight %}
<app-name>/urls.py
{% highlight python %}
from django.urls import path
from . import views
urlpatterns = [
path(“”, views.index, name=”index”),
]
{% endhighlight %}
<proj-name>/urls.py
{% highlight python %}
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path(“/", include(".urls")),
path("admin/", admin.site.urls),
]
{% endhighlight %}
Setting database
다음은 django에서 database를 세팅하는 방법입니다. Django는 기본으로 SQLite를 활용하지만 설정을 변경하여 수정이 가능합니다.
mysql
다음은 mysql 예시입니다.
필수 모듈 설치
{% highlight shell %}
pip install mysqlclient
{% endhighlight %}
<proj-name>.settings.py에 DB 옵션변경
{% highlight python %}
DATABASES = {
‘default’: {
‘ENGINE’: ‘django.db.backends.mysql’,
‘NAME’: ‘',
'USER': '',
'PASSWORD': '',
'HOST': 'localhost',
'PORT': '3306',
}
}
{% endhighlight %}
postgre
다음은 postgre 예시입니다.
필수 모듈 설치
{% highlight shell %}
pip install psycopg2
{% endhighlight %}
postgre setting
{% highlight shell %}
sudo su - postgres # postgre 실행
psql
CREATE DATABASE django_test; # postgre 유저 및 DB 생성
CREATE USER django_user WITH PASSWORD ‘django_pass’;
ALTER ROLE django_user SET client_encoding TO ‘utf8’;
ALTER ROLE django_user SET default_transaction_isolation TO ‘read committed’;
ALTER ROLE django_user SET timezone TO ‘UTC’;
GRANT ALL PRIVILEGES ON DATABASE django_test TO django_user;
\q
{% endhighlight %}
<proj-name>.settings.py에 DB 옵션변경
{% highlight python %}
DATABASES = {
‘default’: {
‘ENGINE’: ‘django.db.backends.mysql’,
‘NAME’: ‘',
'USER': '',
'PASSWORD': '',
'HOST': 'localhost',
'PORT': '3306',
}
}
{% endhighlight %}
Next(Web page)
Next
Next(Rest API)
Next
-
-
-
-
FastAPI SQL
SQL
SQL은 다음과 같이 구조화 하여 사용할 수 있습니다.
sql_app/__init__.py: empty
sql_app/database.py
sql_app/models.py
sql_app/schemas.py
sql_app/crud.py
sql_app/main.py
sql_app/database.py
database 파일은 다음과 같이 구성됩니다.
{% highlight python %}
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
SQLALCHEMY_DATABASE_URL = “sqlite:///./sql_app.db”
SQLALCHEMY_DATABASE_URL = “postgresql://user:password@postgresserver/db”
engine = create_engine(
SQLALCHEMY_DATABASE_URL, connect_args={“check_same_thread”: False}
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
{% endhighlight %}
sql_app/models.py
models 파일은 다음과 같이 구성됩니다.
{% highlight python %}
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String
from sqlalchemy.orm import relationship
from .database import Base
class User(Base):
tablename = “users”
id = Column(Integer, primary_key=True)
email = Column(String, unique=True, index=True)
hashed_password = Column(String)
is_active = Column(Boolean, default=True)
items = relationship("Item", back_populates="owner")
class Item(Base):
tablename = “items”
id = Column(Integer, primary_key=True)
title = Column(String, index=True)
description = Column(String, index=True)
owner_id = Column(Integer, ForeignKey("users.id"))
owner = relationship("User", back_populates="items") {% endhighlight %}
sql_app/schemas.py
schemas 파일은 다음과 같이 구성됩니다.
{% highlight python %}
from typing import Union
from pydantic import BaseModel
class ItemBase(BaseModel):
title: str
description: Union[str, None] = None
class ItemCreate(ItemBase):
pass
class Item(ItemBase):
id: int
owner_id: int
class Config:
orm_mode = True
class UserBase(BaseModel):
email: str
class UserCreate(UserBase):
password: str
class User(UserBase):
id: int
is_active: bool
items: list[Item] = []
class Config:
orm_mode = True {% endhighlight %}
sql_app/crud.py
crud 파일은 다음과 같이 구성됩니다.
{% highlight python %}
from sqlalchemy.orm import Session
from . import models, schemas
def get_user(db: Session, user_id: int):
return db.query(models.User).filter(models.User.id == user_id).first()
def get_user_by_email(db: Session, email: str):
return db.query(models.User).filter(models.User.email == email).first()
def get_users(db: Session, skip: int = 0, limit: int = 100):
return db.query(models.User).offset(skip).limit(limit).all()
def create_user(db: Session, user: schemas.UserCreate):
fake_hashed_password = user.password + “notreallyhashed”
db_user = models.User(email=user.email, hashed_password=fake_hashed_password)
db.add(db_user)
db.commit()
db.refresh(db_user)
return db_user
def get_items(db: Session, skip: int = 0, limit: int = 100):
return db.query(models.Item).offset(skip).limit(limit).all()
def create_user_item(db: Session, item: schemas.ItemCreate, user_id: int):
db_item = models.Item(**item.dict(), owner_id=user_id)
db.add(db_item)
db.commit()
db.refresh(db_item)
return db_item
{% endhighlight %}
sql_app/main.py
main 파일은 다음과 같이 구성됩니다.
{% highlight python %}
from fastapi import Depends, FastAPI, HTTPException
from sqlalchemy.orm import Session
from . import crud, models, schemas
from .database import SessionLocal, engine
models.Base.metadata.create_all(bind=engine)
app = FastAPI()
Dependency
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
@app.post(“/users/”, response_model=schemas.User)
def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)):
db_user = crud.get_user_by_email(db, email=user.email)
if db_user:
raise HTTPException(status_code=400, detail=”Email already registered”)
return crud.create_user(db=db, user=user)
@app.get(“/users/”, response_model=list[schemas.User])
def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
users = crud.get_users(db, skip=skip, limit=limit)
return users
@app.get(“/users/{user_id}”, response_model=schemas.User)
def read_user(user_id: int, db: Session = Depends(get_db)):
db_user = crud.get_user(db, user_id=user_id)
if db_user is None:
raise HTTPException(status_code=404, detail=”User not found”)
return db_user
@app.post(“/users/{user_id}/items/”, response_model=schemas.Item)
def create_item_for_user(
user_id: int, item: schemas.ItemCreate, db: Session = Depends(get_db)
):
return crud.create_user_item(db=db, item=item, user_id=user_id)
@app.get(“/items/”, response_model=list[schemas.Item])
def read_items(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
items = crud.get_items(db, skip=skip, limit=limit)
return items
{% endhighlight %}
W. middleware
다음은 미들웨어를 사용한 예시를 제시합니다.
{% highlight python %}
@app.middleware(“http”)
async def db_session_middleware(request: Request, call_next):
response = Response(“Internal server error”, status_code=500)
try:
request.state.db = SessionLocal()
response = await call_next(request)
finally:
request.state.db.close()
return response
Dependency
def get_db(request: Request):
return request.state.db
{% endhighlight %}
-
FastAPI types
Enum
Enum 클래스는 다음과 같이 사용할 수 있습니다.
{% highlight python %}
from enum import Enum
class ModelName(str, Enum):
alexnet = “alexnet”
resnet = “resnet”
lenet = “lenet”
{% endhighlight %}
값을 사용하는 방식은 다음과 같이 사용 가능합니다.
model.value
Model.<key>
{% highlight python %}
app = FastAPI()
@app.get(“/models/{model_name}”)
async def get_model(model_name: ModelName):
if model_name is ModelName.alexnet:
{% endhighlight %}
Optional
Optional type의 경우 None일 수 있는 데이터를 의미하며 다음과 같이 작성할 수 있습니다.
{% highlight python %}
from typing import Optional
app = FastAPI()
@app.get(“/items/{item_id}”)
async def read_item(item_id: Optional[int]):
return {“item_id”: item_id}
{% endhighlight %}
httpUrl
httpUrl type의 경우 url형식을 받을 수 있는 형식입니다.
{% highlight python %}
from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl
app = FastAPI()
class Image(BaseModel):
url: HttpUrl
name: str
@app.put(“/items”)
async def update_item(image: Image):
results = {“image”: image}
return results
{% endhighlight %}
output type
output type의 경우 일반적인 방식으로 활용이 가능합니다.
response_model=None은 2종류 이상의 타입이 가능할경우 pydantic의 규제를 피할때 사용할 수 있습니다.
response_model_exclude_unset=True은 output을 넘겨줄때 pydantic의 default value는 무시하는 방법입니다.
response_model_exclude={""}은 output을 넘겨줄때 넘겨주지 않을 value를 지정하는 방법입니다.
{% highlight python %}
from fastapi import FastAPI, Response
from fastapi.responses import RedirectResponse
app = FastAPI()
@app.get(“/portal”, response_model=None, response_model_exclude_unset=True, response_model_exclude={“tax”})
async def get_portal(teleport: bool = False) -> Response | dict:
if teleport:
return RedirectResponse(url=”https://www.youtube.com/watch?v=dQw4w9WgXcQ”)
return {“message”: “Here’s your interdimensional portal.”}
{% endhighlight %}
and others
이외에도 다양한 data type이 존재하며 다음과 같습니다.
datetime.datetime
datetime.date
datetime.time
datetime.timedelta
frozenset
bytes
Decimal
schema examples
pydantic으로 형식을 만들때는 다음과 같이 예시문을 만들 수 있습니다. 예시문을 활용하면 docs에서 예시문을 확인할 수 있습니다.
{% highlight python %}
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
model_config = {
"json_schema_extra": {
"examples": [
{
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
}
]
}
} {% endhighlight %}
pydantic이 아닐경우는 Body, Query, …에서 직접 예시문을 작성할 수도 있습니다.
{% highlight python %}
Body(
examples=[
{
“name”: “Foo”,
“description”: “A very nice Item”,
“price”: 35.4,
“tax”: 3.2,
}
],
),
{% endhighlight %}
-
FastAPI intro Num.3
Security
API를 만드는데 있어서 보안사항은 매우 중요합니다. 아래의 순서를 따라 보안을 설정할 수 있습니다.
{% highlight shell %}
pip install python-jose # jwt token module
pip install passlib[bcrypt] # password hashing module
{% endhighlight %}
만약 (trapped) error reading bcrypt version과 같은 문제가 발생하면 아래의 코드를 작동시켜야 합니다.
{% highlight shell %}
pip install bcrypt==4.0.1
{% endhighlight %}
아래의 방법은 보안을 설정하는 방법들을 제안합니다.
{% highlight python %}
from datetime import datetime, timedelta, timezone
from typing import Annotated, Union
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import JWTError, jwt
from passlib.context import CryptContext
from pydantic import BaseModel
to get a string like this run:
openssl rand -hex 32
SECRET_KEY = “09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7”
ALGORITHM = “HS256”
ACCESS_TOKEN_EXPIRE_MINUTES = 30
fake_users_db = {
“johndoe”: {
“username”: “johndoe”,
“full_name”: “John Doe”,
“email”: “johndoe@example.com”,
“hashed_password”: “$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW”,
“disabled”: False,
}
}
class Token(BaseModel):
access_token: str
token_type: str
class TokenData(BaseModel):
username: Union[str, None] = None
class User(BaseModel):
username: str
email: Union[str, None] = None
full_name: Union[str, None] = None
disabled: Union[bool, None] = None
class UserInDB(User):
hashed_password: str
pwd_context = CryptContext(schemes=[“bcrypt”], deprecated=”auto”)
oauth2_scheme = OAuth2PasswordBearer(tokenUrl=”token”)
app = FastAPI()
def verify_password(plain_password, hashed_password):
return pwd_context.verify(plain_password, hashed_password)
def get_password_hash(password):
return pwd_context.hash(password)
def get_user(db, username: str):
if username in db:
user_dict = db[username]
return UserInDB(**user_dict)
def authenticate_user(fake_db, username: str, password: str):
user = get_user(fake_db, username)
if not user:
return False
if not verify_password(password, user.hashed_password):
return False
return user
def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None):
to_encode = data.copy()
if expires_delta:
expire = datetime.now(timezone.utc) + expires_delta
else:
expire = datetime.now(timezone.utc) + timedelta(minutes=15)
to_encode.update({“exp”: expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=”Could not validate credentials”,
headers={“WWW-Authenticate”: “Bearer”},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get(“sub”)
if username is None:
raise credentials_exception
token_data = TokenData(username=username)
except JWTError:
raise credentials_exception
user = get_user(fake_users_db, username=token_data.username)
if user is None:
raise credentials_exception
return user
async def get_current_active_user(
current_user: Annotated[User, Depends(get_current_user)],
):
if current_user.disabled:
raise HTTPException(status_code=400, detail=”Inactive user”)
return current_user
@app.post(“/token”)
async def login_for_access_token(
form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
) -> Token:
user = authenticate_user(fake_users_db, form_data.username, form_data.password)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=”Incorrect username or password”,
headers={“WWW-Authenticate”: “Bearer”},
)
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(
data={“sub”: user.username}, expires_delta=access_token_expires
)
return Token(access_token=access_token, token_type=”bearer”)
@app.get(“/users/me/”, response_model=User)
async def read_users_me(
current_user: Annotated[User, Depends(get_current_active_user)],
):
return current_user
@app.get(“/users/me/items/”)
async def read_own_items(
current_user: Annotated[User, Depends(get_current_active_user)],
):
return [{“item_id”: “Foo”, “owner”: current_user.username}]
{% endhighlight %}
Middleware
미들웨어는 다양한 작동에 있어서 중간에 행동을 하는 행동입니다. 현재 fastapi는 http protocol이 진행되는 시점의 middleware만 사용이 가능합니다. 사용방법은 다음 두가지 방법을 활용할 수 있습니다.
{% highlight python %}
class CustomMiddleware(BaseHTTPMiddleware):
def __init__(self, app):
super().__init__(app)
async def dispatch(self, request, call_next):
response = await call_next(request)
return response
app.add_middleware(CustomMiddleware)
{% endhighlight %}
{% highlight python %}
@app.middleware(“http”)
async def add_process_time_header(request: Request, call_next):
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
response.headers[“X-Process-Time”] = str(process_time)
return response
{% endhighlight %}
advance middleware
CORS
CORS는 Cross-Origin-Resource-sharing의 약자로 API를 호출하는 사용자의 ip를 관리하는 방법입니다.
{% highlight python %}
from fastapi.middleware.cors import CORSMiddleware
origins = [
“http://localhost”,
“http://localhost:8080”,
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=[“”],
allow_headers=[“”],
)
{% endhighlight %}
Background Task
main logic이 진행되는 것과 별개로 Background Task를 동작시킬 수 있습니다. 이렇게 동작되면 main logic에 영향을 주지 않는 동작을 빠르게 실행 할 수 있습니다.
{% highlight python %}
from fastapi import BackgroundTasks, FastAPI
app = FastAPI()
def write_log(message: str):
with open(“log.txt”, mode=”a”) as log:
log.write(message)
@app.post(“/send-notification/{email}”)
async def send_notification(
email: str, background_tasks: BackgroundTasks
):
message = f”message to {email}\n”
background_tasks.add_task(write_log, message)
return {“message”: “Message sent”}
{% endhighlight %}
Info
fastapi는 기본적인 info를 지정 할 수 있습니다. 이는 docs를 통하여 보여지며 아래와 같이 작성이 가능합니다.
{% highlight python %}
app = FastAPI(
title=”ChimichangApp”,
description=description,
summary=”Deadpool’s favorite app. Nuff said.”,
version=”0.0.1”,
terms_of_service=”http://example.com/terms/”,
contact={
“name”: “Deadpoolio the Amazing”,
“url”: “http://x-force.example.com/contact/”,
“email”: “dp@x-force.example.com”,
},
license_info={
“name”: “Apache 2.0”,
“identifier”: “MIT”,
},
)
{% endhighlight %}
static files
fastapi로 static file을 사용할 수 있습니다. 이러한 기능을 통하여 간단한 소개글이나 홈페이지 같은것도 제작이 가능해집니다.
{% highlight python %}
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
app = FastAPI()
app.mount(“/static”, StaticFiles(directory=”static”), name=”static”)
{% endhighlight %}
API Test
fastapi를 작성하고나면 정상적으로 작성이 되었는지 걱정이 될 수 있습니다. 이럴때 test를 해볼 수 있는 기능을 지원합니다. 아래와 같이 작성 후 pytest를 통하여 확인을 해볼 수 있습니다.
test_*.py
{% highlight python %}
from fastapi import FastAPI
from fastapi.testclient import TestClient
app = FastAPI()
@app.get(“/”)
async def read_main():
return {“msg”: “Hello World”}
client = TestClient(app)
def test_read_main():
response = client.get(“/”)
assert response.status_code == 200
assert response.json() == {“msg”: “Hello World”}
{% endhighlight %}
run uvicorn(W. code)
다음과 같이 코드상에서 uvicorn을 작동하면 코드를 관리하는데 더욱 장점을 가질 수 있습니다.
{% highlight python %}
import uvicorn
from fastapi import FastAPI
app = FastAPI()
@app.get(“/”)
def root():
return {“value”: “hello world”}
if name == “main”:
uvicorn.run(app, host=”0.0.0.0”, port=8000)
{% endhighlight %}
Prev
Prev
-
FastAPI intro Num.2
Error handling
API를 만드는데 있어서 Error 상황이 있을 수 있습니다. 이런경우 error 상태를 요청자에게 안내와 함께 시스템의 결과 관리를 해줘야 합니다.
HTTPException
가장 일반적인 exception으로 아래와 같이 사용 가능합니다. 일반적으로 headers를 작성할 필요가 없으나 Token을 만들거나 하는 상황이나 보안적인 문제가 있을때 사용하기에 좋습니다.
{% highlight python %}
from fastapi import FastAPI, HTTPException
app = FastAPI()
items = {“foo”: “The Foo Wrestlers”}
@app.get(“/items/{item_id}”)
async def read_item(item_id: str):
if item_id not in items:
raise HTTPException(
status_code=404,
detail=”Item not found”,
headers={“X-Error”: “There goes my error”},
)
return {“item”: items[item_id]}
{% endhighlight %}
Custom Exception
Exception은 다음과 같이 custom해서 사용 가능합니다.
{% highlight python %}
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
class UnicornException(Exception):
def init(self, name: str):
self.name = name
app = FastAPI()
@app.exception_handler(UnicornException)
async def unicorn_exception_handler(request: Request, exc: UnicornException):
return JSONResponse(
status_code=418,
content={“message”: f”Oops! {exc.name} did something. There goes a rainbow…”},
)
@app.get(“/unicorns/{name}”)
async def read_unicorn(name: str):
if name == “yolo”:
raise UnicornException(name=name)
return {“unicorn_name”: name}
{% endhighlight %}
다음 보여드릴 방식은 기본 설정된 starlette, RequestValidation을 custom해서 추가 기능을 구현하려고 할때 활용 가능합니다.
{% highlight python %}
from fastapi import FastAPI
from fastapi.exception_handlers import (
http_exception_handler,
request_validation_exception_handler,
)
from fastapi.exceptions import RequestValidationError
from starlette.exceptions import HTTPException as StarletteHTTPException
app = FastAPI()
@app.exception_handler(StarletteHTTPException)
async def custom_http_exception_handler(request, exc):
print(f”OMG! An HTTP error!: {repr(exc)}”)
return await http_exception_handler(request, exc)
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
print(f”OMG! The client sent invalid data!: {exc}”)
return await request_validation_exception_handler(request, exc)
{% endhighlight %}
Routing
routing을 하는 방식은 크게 2가지를 볼 수 있습니다.
use tags
{% highlight python %}
from fastapi import FastAPI
app = FastAPI()
@app.get(“/items/”, tags=[“items”])
async def create_item():
return None
{% endhighlight %}
use router
{% highlight python %}
from fastapi import FastAPI, APIRouter
app = FastAPI()
router = APIRouter(prefix=’/slack’, tags=[“items”])
app.include_router(user.router)
@router.get(“/items/”)
async def create_item():
return None
{% endhighlight %}
JsonEncoder
pydantic으로 인하여 dict형이 아니거나 2개이상의 dict형을 융합하여 활용하고 싶을때 사용할 수 있는 방법입니다.
{% highlight python %}
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel
class Item(BaseModel):
title: str
timestamp: datetime
description: str | None = None
@app.put(“/items/{id}”)
def update_item(id: str, item: Item):
jsonable_encoder(item)
{% endhighlight %}
Dependencies
Dependencies는 FastAPI가 동작하는데 있어서 종속성을 주입하는 것입니다. 이는 더욱 안정적으로 동작할 수 있게 해줍니다. pydantic으로 사용하는것을 권장하나 아래와 같이 사용할 수 도 있습니다.
Function Dependencies
다음과 같이 함수형으로도 만들 수 있습니다.
{% highlight python %}
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(
skip: int = 0, limit: int = 100
):
return {“skip”: skip, “limit”: limit}
@app.get(“/items/”)
async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
return commons
{% endhighlight %}
Class Dependencies
다음과 같이 클래스형으로 만들 수 있습니다.
{% highlight python %}
from typing import Annotated, Union
from fastapi import Depends, FastAPI
app = FastAPI()
class CommonQueryParams:
def init(self, skip: int = 0, limit: int = 100):
self.skip = skip
self.limit = limit
@app.get(“/items/”)
async def read_items(commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]):
return commons
{% endhighlight %}
Path Operation Dependencies
다음과 같이 함수의 입력이 아니라 path operation dependency에 입력하여 값을 검증 할 수도 있습니다.
{% highlight python %}
from typing import Annotated
from fastapi import Depends, FastAPI, Header, HTTPException
app = FastAPI()
async def verify_token(x_token: Annotated[str, Header()]):
if x_token != “fake-super-secret-token”:
raise HTTPException(status_code=400, detail=”X-Token header invalid”)
@app.get(“/items/”, dependencies=[Depends(verify_token)])
async def read_items():
return None
{% endhighlight %}
Global Dependencies
전역 Dependency도 사용할 수 있습니다. 이는 token 검증과 같은 활동에 있어서 유용합니다.
{% highlight python %}
app = FastAPI(dependencies=[Depends(verify_token), Depends(verify_key)])
{% endhighlight %}
Dependencies using yield
Dependency를 사용하여 DB의 무결성도 확인이 가능합니다. 아래의 예시는 sqlalchemy를 사용하였으나 다음과 같이 구성하면 활용성을 향상시킬 수 있습니다.
{% highlight python %}
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
engine = create_engine(
,
pool_pre_ping=True
)
Session = sessionmaker(autocommit=False, autoflush=False, bind=engine)
def get_db():
db = Session()
try:
yield db
finally:
db.close()
def router(s: Annotated[Service, Depends(get_db)]):
s.action()
{% endhighlight %}
{% highlight python %}
class MySuperContextManager:
def init(self):
self.db = DBSession()
def __enter__(self):
return self.db
def __exit__(self, exc_type, exc_value, traceback):
self.db.close()
async def get_db():
with MySuperContextManager() as db:
yield db
{% endhighlight %}
아래의 로직을 이해한다면 fastapi를 자유롭게 사용하는데 문제가 없다고 볼 수 있습니다.
Prev
Prev
Next
Next
-
FastAPI intro Num.1
What is FastAPI
FastAPI는 python으로 구현된 web framework입니다. FastAPI는 빠르게 개발이 가능하고 python으로 구현된 web framework중 가장 빠르다고 이야기 되고 있습니다.
type check를 해주는 pydantic과 Asynchronous Server Gateway interface로 구현된 starlette가 구성되어 있습니다. 그에 따라 다음과 같은 장점을 가지게 됩니다.
type check
비동기적 작업 지원
fast to create docs
FastAPI는 docs를 자체적으로 지원을 해줘서 빠른 문서작업이 가능해집니다.
FastAPI는 Swagger UI를 기반으로한 API docs를 지원해줍니다. 해당 자료는 FastAPI를 구동하면 https://localhost:port/docs에서 확인을 할 수 있습니다.
FastAPI는 ReDoc을 기반으로한 API docs 또한 지원을 해줍니다. 해당 자료는 FastAPI 구동이후 https://localhost:port/redoc에서 확인을 할 수 있습니다.
How to start FastAPI
FastAPI를 사용하기 위하여 우선 두가지 모듈을 다운 받아야합니다.
{% highlight shell %}
pip install fastapi
pip install uvicorn
{% endhighlight %}
이후 실행을 위하여 아래의 코드 작성 및 실행이 필요합니다.
main.py
{% highlight python %}
from fastapi import FastAPI
app = FastAPI()
@app.get(“/”)
async def root():
return {“message”: “Hello World”}
{% endhighlight %}
you should run in cli
{% highlight shell %}
uvicorn main:app –reload
{% endhighlight %}
main:app은 main.py에 있는 app을 실행한다는 의미입니다.
Input Datas
API의 데이터 입출력을 위하여 다양한 방식의 input data가 존재합니다. 아래는 해당 값들을 순차적으로 설명드리겠습니다.
Path Parameters
경로 파라미터라고 불리는 것으로 아래의 코드에서 item_id를 의미합니다. FastAPI는 type에 있어서 매우 엄격합니다. 그래서 아래의 코드와 같이 type hint(or pydantic)가 없거나 일치 하지 않을 경우 작동하지 않습니다. 주소창에 입력하는 값으로보면 숫자를 입력해도 문자로 보일 수 있으나 type hint에 따라서 숫자로 인식됩니다.
{% highlight python %}
@app.get(“/items/{item_id}”)
async def read_item(item_id: int):
return {“item_id”: item_id}
{% endhighlight %}
위와 같은 주소체계를 사용할때 주의 할점은 "/items/item"이라고 만약 새로운 주소체계를 선언할 경우 path parameter로 구성된 주소체계보다 상단에 존재하여야합니다. 이는 중복된 입력으로 판단이 될 수 있기 때문입니다.
Path Parameter가 "/"와 같이 경로 데이터가 포함이 되어있을 경우 starlette에서 지원해주는 type check 기능으로 :path를 추가해 아래와 같이 활용 가능합니다.
{% highlight python %}
@app.get(“/items/{item_id:path}”)
async def read_item(item_id: str):
return {“item_id”: item_id}
{% endhighlight %}
Path Parameter는 아래와 같이 상세한 유효성 검사를 지원하며 사용법은 다음과 같습니다.
gt: 보다 크다.
ge: 크거나 같다.
lt: 보다 작다.
le: 작거나 같다.
{% highlight python %}
from typing import Annotated
from fastapi import FastAPI, Path
app = FastAPI()
@app.get(“/items/{item_id}”)
async def read_items(
q: str, item_id: Annotated[int, Path(title=”The ID of the item to get”)]
):
results = {“item_id”: item_id}
if q:
results.update({“q”: q})
return results
{% endhighlight %}
Query Parameters
Path Parameter이외에 입력값을 작성하면 Query Parameter로 인식됩니다. url로 값을 직접 전송하려면 URL/?data=data와 같이 전송이 가능합니다.
Query Parameter의 경우 default값을 제공해주지 않거나 Ellipsis를 주면 필수 입력 조건으로 사용이됩니다.
Query Parameter는 다음과 같이 유효성 검사를 추가적으로 진행 할 수 있습니다. 이것이 의미하는 바는 q는 str인데 None일 수 있으며 최대 글자수가 50이 넘으면 안되는 기본값 None을 가진 parameter라고 볼 수 있습니다.
{% highlight python %}
from typing import Annotated
from fastapi import FastAPI, Query
app = FastAPI()
@app.get(“/items/”)
async def read_items(q: Annotated[str | None, Query(max_length=50)] = None):
results = {“items”: [{“item_id”: “Foo”}, {“item_id”: “Bar”}]}
if q:
results.update({“q”: q})
return results
{% endhighlight %}
Query에는 다음과 같이 다양한 입력을 줄 수 있습니다.
alias: 입력 명칭을 변경
deprecated: 사용 가능 여부
include_in_schema: 문서에 표현 여부
{% highlight python %}
Query(
alias=”item-query”,
title=”Query string”,
description=”Query string for the items to search in the database that have a good match”,
min_length=3,
max_length=50,
pattern=”^fixedquery$”,
deprecated=True,
include_in_schema=False
),
{% endhighlight %}
Body
다중 입력값이 존재할경우 흔하게 사용되는 방식입니다. fastapi에서 지원하는 Request를 사용해도 가능하지만 pydantic을 이용하는것이 무결성에 있어서 안전합니다.
{% highlight python %}
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
app = FastAPI()
@app.post(“/items/”)
async def create_item(item: Item):
return item
{% endhighlight %}
Single Body
Body를 사용하는데 있어서 단일값일 경우 아래와 같이 사용이 가능합니다.
{% highlight python %}
from typing import Annotated
from fastapi import Body, FastAPI
app = FastAPI()
@app.put(“/items”)
async def update_item(
importance: Annotated[int, Body()]
):
return {“importance”: importance}
{% endhighlight %}
Body Field
body도 query와 같이 Field를 사용하여 추가적인 무결성 검사를 할 수 있습니다.
{% highlight python %}
from typing import Annotated
from fastapi import Body, FastAPI
from pydantic import BaseModel, Field
app = FastAPI()
class Item(BaseModel):
price: float = Field(gt=0, description=”The price must be greater than zero”)
tax: float
@app.put(“/items”)
async def update_item(item: Annotated[Item, Body(embed=True)]):
results = {“item_id”: item_id, “item”: item}
return results
{% endhighlight %}
Cookie
Cookie 데이터가 있을경우 아래와 같이 사용할 수 있습니다.
{% highlight python %}
from typing import Annotated, Union
from fastapi import Cookie, FastAPI
app = FastAPI()
@app.get(“/items/”)
async def read_items(ads_id: Annotated[Union[str, None], Cookie()] = None):
return {“ads_id”: ads_id}
{% endhighlight %}
Header
Header 데이터를 사용할 수 있습니다. Header의 경우 "-"이 "_"으로 자동 치환이 되기때문에 원본을 사용하려면 옵션을 추가해줘야 합니다.
{% highlight python %}
from typing import Annotated, Union
from fastapi import FastAPI, Header
app = FastAPI()
@app.get(“/items/”)
async def read_items(user_agent: Annotated[Union[str, None], Header(convert_underscores=False)] = None):
return {“User-Agent”: user_agent}
{% endhighlight %}
Form
Form data의 경우 우선 pip install python-multipart를 필요로 합니다. Form data는 아래와 같이 활용이 가능합니다.
{% highlight python %}
from typing import Annotated
from fastapi import FastAPI, Form
app = FastAPI()
@app.post(“/login/”)
async def login(username: Annotated[str, Form()], password: Annotated[str, Form()]):
return {“username”: username}
{% endhighlight %}
File
File data의 경우 우선 pip install python-multipart를 필요로 합니다. File data는 2가지 방식으로 활용 가능합니다.
bytes: 이미지의 원본을 binary값으로 가져옵니다.
UploadFile: 이미지의 관련 정보들을 가져옵니다.
filename
content_type
file
read
write
seek
close
{% highlight python %}
from typing import Annotated
from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.post(“/files/”)
async def create_file(file: Annotated[bytes, File()]):
return {“file_size”: len(file)}
@app.post(“/uploadfile/”)
async def create_upload_file(file: Annotated[UploadFile, File()]):
return {“filename”: file.filename}
{% endhighlight %}
Next
Next
-
-
-
Matplotlib & Seaborn
Matplotlib
파이썬 시각화 라이브러리로 matlab을 참고하여 제작함.
주로 논문에서 figure를 작성할때 사용함.
pyplot
빠르고 간단하게 그래프를 그릴때 사용
OOP-style
구체적으로 요소들을 손봐서 그래프를 그릴때 사용
pyplot
아래 3개와 같이 기본적인 형이 존재하며 추가적인 속성들을 변경하여 그래프를 그린다.
단일 plot 생성
{% highlight python %}
plt.figure()
plt.plot()
plt.show()
{% endhighlight %}
단일 plot에 그래프들 겹치기
{% highlight python %}
plt.figure()
plt.plot()
plt.plot()
plt.show()
{% endhighlight %}
다중 plot 작성
{% highlight python %}
plt.figure()
plt.subplot(,,)
plt.subplot(,,)
plt.show()
{% endhighlight %}
다음과 같은 데이터가 있을때
{% highlight python %}
x = [“data1”, “data2”, “data3”, “data4”]
y = [111, 156, 487, 445]
z = [50, 549, 450, 42]
{% endhighlight %}
아래와 같은 그래프들을 그릴 수 있으며
{% highlight python %}
plt.bar(, , *arg)
plt.barh(, , *arg)
plt.plot(, , *arg)
plt.scatter(, , *arg)
{% endhighlight %}
아래와 같은 옵션들을 사용이 가능하다
{% highlight python %}
plt.figure(figsize=(10,5))
plt.plot(x,y, label=”plot”, width=0.2, color=”red”, marker=”^”)
plt.title(“Title”, fontdict={‘fontsize’: 10}, loc=”center”)
plt.xlabel(“menu”, fontdict={‘fontsize’: 10}, loc=”left”)
plt.ylabel(“data”, fontdict={‘fontsize’: 10}, loc=”bottom”)
plt.legend(loc=”upper right”)
plt.yticks([1,2,5,50,100,200])
plt.ylim(0, 1000)
plt.grid(alpha=1, color=”red”, linewidth=10)
{% endhighlight %}
Seaborn(Statisical Data Visualization library based on Matplotlib)
Matplotlib를 참고하여 제작하였으나 파이썬의 라이브러리에 더 친화적이다.
pandas의 dataframe을 사용하는데 용이함
기본적인 세팅은 plt와 같으며 아래와 같이 제공하는 데이터를 불러올 수 있다.
{% highlight python %}
data = sns.load_dataset(“penguins”)
{% endhighlight %}
NaN 데이터는 아래와 같이 정리가 가능하며
{% highlight python %}
data = data.dropna()
data.isnull()
data[data.isnull().any(axis=1)]
{% endhighlight %}
plt외에도 아래와 같은 세팅도 가능하다.
{% highlight python %}
sns.set_palette(“bone”)
{% endhighlight %}
히스토그램
{% highlight python %}
sns.histplot(data=data, x=”body_mass_g”, bins=15, hue=”species”, multiple=”stack”)
{% endhighlight %}
밀도표
{% highlight python %}
sns.displot(data=data, kind=”kde”, x=”body_mass_g”, hue=”species”, col=”island”)
{% endhighlight %}
막대그래프
confidence interval(Default: 에러영역)를 가짐
{% highlight python %}
sns.barplot(data=data, x=”species”, y=”body_mass_g”, hue=”sex”, ci=”sd”)
sns.barplot(data=data, x=”body_mass_g”, y=”species”)
{% endhighlight %}
갯수표
{% highlight python %}
sns.countplot(data=data, x=”sex”)
{% endhighlight %}
박스 그래프
outlier를 확인할 수있음
{% highlight python %}
sns.boxplot(data=data, x=”sex”, y=”bill_depth_mm”)
{% endhighlight %}
violin 그래프
분포를 확인하는데 효과적임
sns.violinplot(data=data, x=”species”, y=”bill_depth_mm”)
라인 그래프
경향성과 confidence interval(Default: 에러영역)를 가짐
{% highlight python %}
sns.lineplot(data=data, x=”body_mass_g”, y=”bill_depth_mm”)
{% endhighlight %}
포인트 그래프
경향성과 confidence interval(Default: 에러영역)를 가짐
{% highlight python %}
sns.pointplot(data=data, x=”body_mass_g”, y=”bill_depth_mm”)
{% endhighlight %}
분산도 그래프
{% highlight python %}
sns.scatterplot(data=data, x=”body_mass_g”, y=”bill_depth_mm”)
{% endhighlight %}
페어 그래프
numeric value들의 비교표들 모음
{% highlight python %}
sns.pairplot(data=data, hue=”species”)
{% endhighlight %}
히트맵 그래프
상관관계를 색상으로 나타냄
상관계수 파악을 위해 corr matrix 생성하여 만듬
{% highlight python %}
corr = data.corr(numeric_only = True)
sns.heatmap(data=corr, square=True, cmap=”Blues”, annot=True, fmt=”.4f”)
{% endhighlight %}
PYTHON
/
Module
· 2023-09-01
-
Pandas
Pandas(Python Data Analysis Library)
정형데이터 조작에 최적화된 라이브러리
행렬로 이루어진 테이블 형태구조의 데이터 연산이 뛰어나다
json,html,csv,xlsx,sql등등 다양한 정형화 데이터를 통일하여 표현가능
기본구조
Pandas는 1차원 구조와 2차원 구조를 가지고 있으며 아래와 같다.
1차원 구조
pd.Series([1,3,5,np.nan, 78])
2차원 구조
pd.DataFrame(
data=np.arange(1, 49).reshape(12, 4),
index=np.arange(12),
columns=[“X1”,”X2”,”X3”,”X4”]
)
data= 구조를 만드는데 사용할 데이터 2차원구조 필요
index= 구조를 만드는데 사용할 인덱스명
data= 구조를 만드는데 사용할 컬럼명
pandas의 내부 구조는 numpy array기반으로 생성해서 universal function 같은 numpy array의 기능을 사용할 수 있다.
Fancy indexing
<pd.data>.<columnName> == <pd.data>[<columnName>]
<pd.data>의 해당 컬럼 기반의 시리즈 추출
<pd.data>.index[<num>]
<pd.data>에서 <num>번째 인덱스이름 가져오기
<pd.data>.loc[<indexName>, <columnName>]
<pd.data>의 (<indexName>, <columnName>)에 해당하는 값을 추출(차원 구조로 작성시 해당 차원의 값이 전부 나옴)
<indexName>임이 중요하다 n을 넣으면 n-1이 아님
<pd.data>.iloc[<indexNum>, <columnNum>]
loc과 작동이 같으나 Name이 아닌 Number를 기준으로 한다.
mask
조건식을 적용하면 조건의 만족여부를 확인가능한 mask가 생성되며 해당 마스크로 데이터를 가공할 수 있다.
<pd.data>[<pd.data>기반 조건]
<pd.data>에서 조건에 해당하는 데이터 추출
기본함수
<pd.data>.index
<pd.data>의 인덱스값 추출
<pd.data>.columns
<pd.data>의 컬럼값 추출
<pd.data>.values
<pd.data>의 값 추출
<pd.data>.apply(<func>)
<pd.data>의 값을 <func>을 통해 가공하여 추출
<pd.data>.str.contains(pat=<string>, regex=Bool)
<pd.data>에 <string>이 있는지 확인 regex=True(default)
<pd.data>[<columnName>]
<pd.data>의 해당 컬럼 기반의 시리즈 추출
<pd.data>.head(<num>)
<pd.data>의 인덱스 0에서 <num>(Null: 5)개 추출
<pd.data>.tail(<num>)
<pd.data>의 인덱스 뒤에서 <num>(Null: 5)개 추출
<pd.data>.info()
<pd.data>의 전반적인 정보를 제공
<pd.data>.describe()
<pd.data>의 전반적인 통계치를 제공
<pd.data>.groupby(<columns_name>)
<pd.data>에서 수치데이터를 <columns_name>의 기준으로 분별한다.
pd.to_numeric(<pd.data>, error=<state>)
<pd.data>를 숫자로 변환한다.
error=”ignore”: 숫자가 안되면 원본
error=”coerce”: 숫자가 안되면 NaN
error=”raise”: 숫자가 안되면 에러발생
pd.to_datetime(<pd.data>)
<pd.data>를 시간타입의 값으로 변환한다.
<pd.data>.dt.hour 과같이 원하는 값을 추출할 수 있다.
<pd.data>.sort_values(by=<pd.columnName>, ascending=False)
<pd.data>의 값에서 <pd.columnName>를 기준으로 정렬
ascending = True: 오름차순 False: 내림차순
Datafram 합치기
pd.merge(<pd.data>, <pd.data>, on=”A”, how=”outer”)
how=”outer”, “inner”, “left”, “right”
<pd.data>끼리 join을 이용한 합치기
pd.merge_asof(<pd.data>, <pd.data>, on=”A”, direction=”backword”)
direction=
backword는 left에 매칭하여 빈공간없이 합치기
forword는 left에 매칭하여 빈공간있게 합치기
nearest는 left에 매칭하여 근처값으로 합치기
pd.concat([<pd.data>, <pd.data>], axis=<num>)
<pd.data>들을 <num>차원으로 합치기
<pd.data>.reset_index(drop=Null)
<pd.data>의 인덱스를 재정의
drop= True는 기존 인덱스 삭제 False는 기존 인덱스 남겨둠
pivot table
특정 컬럼을 기준으로 통계량을 측정하여 판다스 테이블화 하는것
pd.pivot_table(data=<pd.data>, index=[<columnName>], values=[<columnName>], aggfunc=[<option>,<option>])
index에 입력한 <columnName>을 인덱스로 하고 values에 입력한 <columnName>이 columns가 되는 테이블을 만듬
aggfunc에 있는 <option>에 해당하는 값으로 column을 만듬 e.x. sum, mean, count 등등…
unpivot
pivot화 된 데이터를 풀어헤치는 행위
stack은 기준이 없을때 melt는 기준이 있을때 용이
(with)stack
stack -> columns to index / unstack -> index to columns
<pd.data>.stack(level=[0,…], dropna=True).reset_index().set_axis([], axis=1)
level은 columns의 최상단부터 0으로 매겨지며 해당하는 columns를 index로 보내고 인덱스를 리셋하여 다시 네이밍을 하는 방법
(with)melt
<pd.data>.melt(id_Vars=None, value_vars=None, var_name=None, value_name=”value”)
id_Vars를 기준으로 데이터를 풀어헤치며 데이터를 value, columns를 variable로 분배한다.
외부 Datafram 불러오기
colab
{% highlight python %}
from google.colab imort drive
drive.mount(‘/content/drive’)
data = pd.read_csv(“/dir/data.csv”)
{% endhighlight %}
window
{% highlight python %}
data = pd.read_csv(“/dir/data.csv”)
{% endhighlight %}
PYTHON
/
Library
· 2023-08-31
-
Numpy
Numpy(Numerical computing with Python)
수치연산과 벡터 연산에 있어서 강한 이점을 가진 라이브러리
np.array
최초 선언 후 사이즈 변경이 불가능
모든 원소의 데이터 타입이 동일해야한다 (homogeneous array)
Mixed Precision
numpy는 아래와 같이 다양한 데이터 타입을 가지고 있다.
np.int[8~64]
np.uint[8~64]
Mixed Precision은 32비트(고용량)에서 메모리가 너무 사용될때 비트수를 내려서 메모리 부담과 속도를 관리하는 방법
np.arange(<num>)
0~-1 의 array 생성
<np.array>.shape
<np.array>의 형태를 확인
<np.array>.reshape(x, y)
<np.array>의 형태를 (x, y)로 변경
(x, ) 1차원 x개원소
(x,1) 2차원 x개원소
(-1, ) 1차원 원소 전부
<np.array> 연산
연산은 벡터 연산으로 실행됨
np.concatenate([<np.array>, <np.array>])
+
-
@(dot product)
하지만 아래의 연산은 원소들 끼리 연산이됨
*
/
또다른 방법으로 연산을 붙이기 연산으로 사용하려면
np.concatenate([<np.array>, <np.array>], axis=<axis>)
해당 차원(<axis>)의 붙이기만 가능
np.vstack([<np.array>, <np.array>])
수직적인 붙이기(axis=1)
np.hstack([<np.array>, <np.array>])
수평적인 붙이기(axis=0)
broadcast
차원이 다른 array의 연산을 할 수있는데 첫번째 차원이라도 원소의 크기가 같아야한다
universal Function
broadcast의 확장적인 의미의 함수
1 / <np.array>는 각각의 원소가 1로 나뉘어진 array가 나옴
numpy indexing
python indexing과 같은 방법을 사용가능하며,
<np.array>[x, y]로 <np.array>[x][y]를 표현 가능하다.
Math Function
np.random.seed(0)
랜덤 생성함수의 시드 고정(테스트 결과 비교할때 좋음)
np.random.rand(<dimen>)
<dimen>에는 차원의 shape을 입력 e.x.(1,3)
0~1로 이루어진 지정 차원의 랜덤 array 생성
np.random.randn(<dimen>)
<dimen>에는 차원의 shape을 입력 e.x.(1,3)
평균 0, 표준편차 1로 이루어진 지정 차원의 랜덤 array 생성
np.abs(<np.array>)
절대값 생성
np.squre(<np.array>)
제곱값 생성
np.sqrt(<np.array>)
루트값 생성
np.abs(<np.array>)
절대값 생성
np.linalg.norm(<np.array>)
<np.array> 제곱합의 루트값 생성 (L2 norm)
np.linalg.eig(<np.array>)
<np.array> eigenvalue(고유값)와 eigenvector(고유 벡터)값을 생성
np.sum(<np.array>, axis=)
<np.array>의 차원에 따른 합
np.mean(<np.array>, axis=)
<np.array>의 차원에 따른 평균
np.std(<np.array>, axis=)
<np.array>의 차원에 따른 표준편차
np.min(<np.array>, axis=)
<np.array>의 차원에 따른 최소값
np.max(<np.array>, axis=)
<np.array>의 차원에 따른 최대값
np.argmin(<np.array>, axis=)
<np.array>의 차원에 따른 최소값의 인덱스
np.argmax(<np.array>, axis=)
<np.array>의 차원에 따른 최대값의 인덱스
np.sort(<np.array>, axis=)
<np.array>의 차원에 따른 정렬(오름차순)
np.sort(<np.array>, axis=)[::-1](내림차순)
np.argsort(<np.array>, axis=)
<np.array>의 차원에 따른 정렬한 값의 인덱스
PYTHON
/
Library
· 2023-08-30
-
멀티 스레드와 멀티 프로세스
threading&multiprocessing
threading
스레드를 늘려서 다른 코드들이 동시에 작동하는것 처럼 만들어주는 라이브러리
class threading.Thread(target=None, name=None, args=(), kwargs={}, *, daemon=None) ***
스레드 생성을 하는 클래스선언
target 매개변수는 스레드에 함수를 할당할 수 있다.
name 매개변수는 스레드에 이름을 할당할 수 있다.
args 매개변수는 스레드에 가변 매개변수들을 할당할 수 있다.
kwargs 매개변수는 스레드에 키워드 가변 매개변수들을 할당할 수 있다.
demon 매개변수는 True/false를 받으며 스레드를 데몬 스레드로 만들어서 메인스레드와 운명을 같이 하게 된다.
.start() ***
스레드 객체의 작동 메서드(.run() 메서드를 작동시킨다.)
.run()
스레드 서브 클래스를 만들때 추가적으로 작동 하고 싶은것을 선언할 수있다.
.join(timeout=None) ***
스레드가 종료 될때까지 이후의 코드를 작동하지 않는다.
timeout 매개변수는 스레드에 시간제한을 줄 수 있으며, 시간제한을 초과하면 스레드를 멈춰줘야한다.
.is_alive()
스레드가 작동중인지 확인 할 수 있으며, 작동시 True를 반환한다.
파이썬의 스레드는 하나의 프로세스에서 여러개의 스레드를 병렬 처리한다. 이때 공유되는 자원들을 동시에 변형가하면 충돌을 발생해 무시될 수 있다. 다음에 소개 할 threading.Lock() 클래스는 이를 해결해준다.
class threading.Lock() ***
스레드의 락 기능을 선언하는 클래스
.acquire(blocking=True, timeout=- 1) ***
락 기능이 작동중인지 작동중이지 않은지 수 있는 메서드.
blocking 매개변수가 True이면 락을 작동(코드 멈춤)하고 True를 반환하고, False이면 락을 작동시키지 않고(코드 진행) 추후에 True/False를 반환합니다.(default: true)
.release() ***
스레드의 락을 해제하며 해제된 스레드에서 작동시 런타임 오류발생.
with구문을 활용하여 acquire()과 release()를 한번에 관리가능하다.
.locked()
스레드가 잠겨있으면 True반환.
락을 사용하는데 A함수와 B함수를 사용하고 A함수가 B함수를 재사용하는 재귀형식의 스레드활용시에는 acquire의 사용에 있어 오류를 발생할 수 있는데 이때 사용하는것이 RLock이다.
class threading.RLock()
스레드의 락 기능을 선언하는 클래스
.acquire(blocking=True, timeout=- 1)
락 기능이 작동중인지 작동중이지 않은지 수 있는 메서드.
blocking 매개변수가 True이면 락을 작동(코드 멈춤)하고 True를 반환하고 재사용시에 1을 반환한다. False이면 락을 작동시키지 않고(코드 진행) 추후에 True/False를 반환합니다.(default: true)
.release()
스레드의 락을 해제하며 해제된 스레드에서 작동시 런타임 오류발생.
with구문을 활용하여 acquire()과 release()를 한번에 관리가능하다.
.locked()
스레드가 잠겨있으면 True반환.
이외에도 많은 함수들이 존재하지만 주로 사용하는 함수만 정리했으며 추가적인 자료는 아래를 참고한다.
원문
{% highlight python %}
from threading import Thread
def subthread():
worker = Thread(target=subthread) # worker에 서브쓰레드 할당
worker.daemon = True # 메인쓰레드가 종료될때 sub도 종료됨(선택)
worker.start() # worker 실행
worker.join() # worker가 끝날때까지 대기(선택)
{% endhighlight %}
---
## **multiprocessing**
---
프로세스를 늘려서 다른 코드들을 동시에 작동시켜주는 라이브러리
multiprocessing의 경우 threading보다 더 다양한 클래스와 메서드들을 가지고 있다.
> **class multiprocessing.Pool(processes=None)** \***
> * 멀티 프로세스중 초기 지정한 프로세스수를 활용하는 클래스선언
> * **processes** 매개변수는 멀티프로세스에서 사용할 프로세스의 갯수를 나타내며 os.cpu_count()를 활용하면 나내 컴퓨터의 최대 프로세스수를 알 수있다. 최대치를 넘는 프로세스는 오류를 유발할 수 있다.
{% highlight python %}
def subprocess():
if __name__ == '__main__':
with Pool(5) as p:
print(p.map(subprocess, ))
{% endhighlight %}
> **class multiprocessing.Process()** \***
> * 멀티 프로세스중 스레드와 유사한 작동방식을 가지며 각각의 프로세스를 관리하는 클래스선언
> [참조](/study/pythonModule/1_threading&multiprocessing#threading)
{% highlight python %}
import multiprocessing as mp
def subprocess():
if __name__ == "__main__":
worker = mp.Process(target=subprocess, args=(...)) # worker에 서브프로세스 할당
worker.daemon = True # 메인쓰레드가 종료될때 sub도 종료됨(선택)
worker.start() # worker 실행
mp.current_process() # PID값을 반환해줌(선택)
worker.is_alive() # PID값을 반환해줌(선택)
worker.terminate() # 강제종료(선택)
worker.join() # worker가 끝날때까지 대기(선택)
{% endhighlight %}
> **class multiprocessing.Queue(maxsize=0)** \***
> * 멀티 프로세스중 프로세스수간 FIFO 데이터 전송을 위한 클래스선언
> * **maxsize** 매개변수는 큐의 최대사이즈를 입력받으며 0은 제한없음을 의미한다.
>
> **.get()** \***
> * 큐에 있는 값을 하나 받아온다.
>
> **.put()** \***
> * 큐에 값을 하나 넣는다.
> **class multiprocessing.Pipe(duplex=None) return(conn1, conn2)** \***
> * 멀티 프로세스중 프로세스수간 한쌍으로 데이터 전송을 위한 클래스선언
> * **duplex** 매개변수는 True일 경우 양방향 통신 False일 경우 단방향 통신(conn1: reciver, conn2: sender)으로 활용된다.
>
> **conn.send()** \***
> * 파이프에 값을 넣는다.
>
> **conn.recv()** \***
> * 파이프에서 값을 받아온다.
> **class multiprocessing.Lock()** \***
> * 락을 관리하는 멀티 프로세스중 스레드 락과 유사한 작동방식을 가지며 각각의 프로세스를 관리하는 클래스선언
> [참조](/study/pythonModule/1_threading&multiprocessing#threading)
> **class multiprocessing.Manager()** \***
> * 멀티 프로세스의 자원을 안전하게 관리하기 위한 클래스선언
> * 다음과 같은 지원을 한다.(더 있음)
> * .list()
> * .dict()
> * .Lock()
> * .RLcok()
> * .Array()
이외에도 많은 함수들이 존재하지만 주로 사용하는 함수만 정리했으며 추가적인 자료는 아래를 참고한다.
[원문](https://docs.python.org/ko/3/library/multiprocessing.html)
PYTHON
/
Module
· 2023-08-29
-
-
Django init summary
Django
django-debug-toolbar -> 디버그 내용 확인 용이
INSTALLED_APPS “debug_toolbar”
MIDDLEWARE “debug_toolbar.middleware.DebugToolbarMiddleware”
INTERNAL_IPS “IP”
djangorestframework -> restAPI 제작에 용이
django-ninja ->
djangorestframework의 느린 serializer 대신 pydantic 사용
swagger 지원 POSTMAN 같은것
Async 지원
api version 지원
django-seed -> db에 임시 데이터 뿌려줌
INSTALLED_APPS “django_seed”
cmd: python manage.py seed <app_name> --number=<num>
서버 기본 세팅
{% highlight shell %}
프로젝트 생성 구문
django-admin startproject
프로젝프 앱 생성 구문
cd
python /manage.py startapp
프로젝프 슈퍼 유저 생성
python /manage.py createsuperuser
프로젝프 기본 마이그레이션
python /manage.py migrate
프로젝프 추가 제작한 마이그레이션
(오류발생시 setting.py -> INSTALLED_APPS에 추가)
python /manage.py makemigrations
서버 구동 구문
python \manage.py runserver
{% endhighlight %}
유저 테이블 제작(models)
커스텀 유저 테이블을 제작하는데 있어서 직접 제작이 가능하며 아래의 방법들이 있다.
추상화 유저 제작
{% highlight python %}
from django.contrib.auth.models import AbstractUser
class Users(AbstractUser):
pay_plan = models.ForeignKey(PayPlan, on_delete=models.DO_NOTHING)
{% endhighlight %}
setting.py에 AUTH_USER_MODEL = ‘<app_name>.Users’ 추가해야함
장고 모듈 활용 유저 제작
{% highlight python %}
from django.contrib.auth.models import User as U
class UserDetail(models.Model):
user = models.OneToOneField(U, on_delete=models.CASCADE)
pay_plan = models.ForeignKey(PayPlan, on_delete=models.DO_NOTHING)
{% endhighlight %}
두개를 모두 사용할 경우 oneToOneField의 입력이 추상화의 Users를 가르켜야한다.
view_html
urls.py
url 패턴을 이용하여 입력받는 주소로 부터 사용할 view단과 연결을 해준다.
{% highlight python %}
from app_test.views import index, redirect_test
urlpatterns = [
path(‘’, index , name=’index’),
path(‘redirect’, redirect_test),
]
{% endhighlight %}
view.py
urls.py에 연결된 view단을 세팅하는 부분
base.html과 같은경우는 <app_name>/templates 폴더에 둔다.
{% highlight python %}
모델(DB)에서 참조할시 해당 모델 추가사항
from .models import Users
모델에서 유저정보를 받아서 보여지는 결과를 다르게 한 예시
def index(request):
user = Users.objects.filter(username=”admin”).first()
email = user.email if user else “Nooooo”
print(email)
print(request.user.is_authenticated)
if not request.user.is_authenticated:
email = “NOoooooooooooooo”
print(email)
return render(request, “base.html”, {“welcome_msg”: f”Hello {email}”})
재참조 형식의 view단 예시
def redirect_test(request):
return redirect(“index”)
{% endhighlight %}
view_restAPI
urls.py
url 패턴을 이용하여 입력받는 주소로 부터 사용할 view단과 연결을 해준다.
<int:user_id>는 query string 사용법
{% highlight python %}
urlpatterns = [
path(‘get_user/', get_user),
]
{% endhighlight %}
view.py
urls.py에 연결된 view단을 세팅하는 부분
csrf_exempt는 token 인증을 임시로 풀기위한것
body가 아닌 JsonResponse는 보통 개발자들끼리 내용을 주고 받을때 사용하기도 한다.
{% highlight python %}
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def get_user(request, user_id):
print(user_id)
if request.method == “GET”:
abc = request.GET.get(“abc”)
xyz = request.GET.get(“xyz”)
user = Users.objects.filter(pk=user_id).first()
return render (request, “base.html”, {“user”: user, “params”: [abc, xyz]})
elif request.method == “POST”:
username = request.GET.get(“username”)
if username:
user = Users.objects.filter(pk=user_id).update(username=username)
return JsonResponse(status=201, data=dict(msg=”POST is”))
{% endhighlight %}
admin_handling1
admin.py
admin page에서 model을 핸들링 가능하게 해준다.
{% highlight python %}
from .models import PayPlan
Register your models here.
admin.site.register(PayPlan)
{% endhighlight %}
django original login setting
urls.py 세팅
views.py
{% highlight python %}
from django.contrib.auth import authenticate, login
from .forms import RegisterForm
def register(request):
if request.method == “POST”:
form = RegisterForm(request.POST)
msg = “not valid data”
if form.is_valid():
form.save() # db에 저장(commit=False로 임시저장가능)
username = form.cleaned_data.get(“username”)
raw_password = form.cleaned_data.get(“password1”)
user = authenticate(username= username, password= raw_password) # 인증
login(request, user) # 로그인
msg = “login”
return render(request, “register.html”, {“form”: form, “msg”: msg})
else:
form = RegisterForm()
return render(request, “register.html”, {“form”: form})
{% endhighlight %}
forms.py
{% highlight python %}
from django import forms
from django.contrib.auth.forms import UserCreationForm
from .models import Users
class RegisterForm(UserCreationForm):
username = forms.CharField(max_length=20, required=True, help_text=”name”, label=”이름”)
email = forms.EmailField(max_length=20, required=False, help_text=”email”, label=”이메일”)
class Meta:
model = Users
fields = (
"username",
"email",
"password1",
"password2",
) {% endhighlight %}
paginator
views.py
페이지 분할 제작법
{% highlight python %}
from django.core.paginator import Paginator
def a(request):
page = int(request.GET.get(“page”, 1))
= <>.objects.all().order_by("-id") # 정렬해야 "-"내림차순
paginator = Paginator(, 5)
= paginator.get_page(page)
return render(request, ".html", {"args": <datas>}) {% endhighlight %}
login_required
setting.py
LOGIN_URL =”/<>”
views.py
로그인 필수 페이지 세팅
{% highlight python %}
from django.contrib.auth.decorators import login_required
@login_required
def a(request):
{% endhighlight %}
template tags
탬플렛을 제작하는데 있어서 조건이나 데이터 활용등을 위한 태그
{\% csrf_token \%}
csrf token을 필요로 하다는것을 나타낼때 사용
{\% cycle “a” “b” \%}
iter적인 상황에서 각 순서마다 서로 다른 영향을 주려고 할때 사용
{\% extends “.html" \%}
한 html에서 다른 html을 확장하여 사용할때 사용
자식페이지에 최상단에 필요하며 은 부모파일이다.
{\% block \%} {\% endblock \%}
한 html에서 다른 html을 확장하여 사용할때 사용
부모페이지에서 자식을 넣을공간에, 자식페이지에서 넣을 내용을 감싼다.
{\% if \%}{\% elsif \%}{\% else \%}{\% endif \%}
조건문을 사용할때 사용
{\% for i in items \%}{\% endfor \%}
for문을 사용할때 사용
forloop.counter 루프의 인덱스(1시작)
forloop.counter0 루프의 인덱스(0시작)
forloop.first 루프의 첫번째 True
forloop.last 루프의 마지막 True
{\% includes “<filename>.html” \%}
html에서 html 파일을 사용할때 사용할 <filename>을 작성
extends보다 느리다.(랜더링이 느리다.)
{\% url “<namespace>” \%}
<namespace>로 이동하게 할때 사용
{\% static “<filepath>” \%}
<filepath>에 있는 static 파일 사용
<app_name>/static/<filepath>으로 구성
{\% load static \%}을 최상단에 작성해야함
custom tags
탬플렛을 제작하는데 있어서
<app_name>/templatetags/custom_tags.py
{% highlight python %}
from django import template
from django.utils.html import mark_safe
register = template.Library()
@register.simple_tag(name=, takes_context=True)
def tags_test(context): # context에는 해당 페이지 정보가 있으며 상세히 다룰 수 있다.
tag_html = "태그"
# mark_safe는 html로 사용해도 안전함을 알려줌 사용안하면 string으로 사용
return mark_safe(tag_html) {% endhighlight %}
{\% load custom_tags \%}
태그 사용할 html 최상단에 적용
{{data|<tag_name>}}
태그 사용할 html 코드에 사용
custom filter
탬플렛을 제작하는데 있어서 원하는 내용만 보여주기 위하여 사용
<app_name>/templatetags/custom_filters.py
{% highlight python %}
from django import template
register = template.Library()
@register.filter(name=)
def email_masker(value):
email_split = value.split("@")
return f"{email_split[0]}@******.***"
{% endhighlight %}
{\% load custom_filters \%}
필터 사용할 html 최상단에 적용
{{data|<filter_name>}}
필터 사용할 html 코드에 사용
-
고급 활용
삼항연산자
단순 True or False 인 상황에서 가독성을 높이는데 좋음
{% highlight python %}
if :
else:
----------------
if else
{% endhighlight %}
# **리스트 컴프리헨션(list comprehension)**
---
리스트를 만드는데 있어서 효과적으로 제작하는방법
{% highlight python %}
list1 = []
for i in range(1, 11):
list1.append(i)
----------------
list1 = [i for i in range(1, 11)]
{% endhighlight %}
# **삼항연산자 & 리스트 컴프리헨션**
---
{% highlight python %}
= [ for in if ]
{% endhighlight %}
# **딕셔너리형 합치기**
---
{% highlight python %}
= {'am': 10}
= {"a": 20, "b": 50}
.update()
----------------
= {'am': 10}
= {"a": 20, "b": 50}
= {**, **}
{% endhighlight %}
# **정규표현식**
---
[참고사이트](https://regexr.com/)
{% highlight python %}
import re
{% endhighlight %}
re.match(\<str\>, \<data\>) 문자열 처음부터 검색(객체)
re.search(\<str\>, \<data\>) 문자열 전체 검색(객체)
re.findall(\<str\>, \<data\>) 문자열 전체를 검색(list형)
re.finditer(\<str\>, \<data\>) 문자열 전체를 검색(iter형)(객체)
re.fullmatch(\<str\>, \<data\>) 완벽한 일치하는 검색(객체)
\<object\>.group() 객체에서 매칭된 문자열을 반환
\<object\>.start() 객체에서 매칭된 문자열의 시작 위치
\<object\>.end() 객체에서 매칭된 문자열의 끝 위치
\<object\>.span() 객체에서 매칭된 문자열의 시작과 끝(tuple형)
re.sub(\<from\>, \<to\>, \<data\>) data에서 \<from\>을 \<to\>로 변환
PYTHON
/
Basic
· 2023-08-24
-
-
-
라이브러리 이해
라이브러리
인코딩(encoding) & 디코딩(decoding)
인코딩(encoding)은 사람이 인지하거나 사용하는 데이터를 컴퓨터가 인지하고 사용하는 0,1의 데이터로 변경하는 과정을 칭한다.
$e.x.,\;$ ASCII, Base64, unicode
{% highlight python %}
data.encode(‘utf-8’)
b.’xxx’ 처럼 byte형식으로 변경이된다.
{% endhighlight %}
디코딩(decoding)은 컴퓨터가 인지하고 사용하는 0,1의 데이터를 사람이 인지하거나 사용하는 데이터로 변경하는 과정을 칭한다.
{% highlight python %}
data.decode(‘utf-8’)
byte형식이 기존의 코드로 변경이된다.
{% endhighlight %}
python은 utf-8(3.x) ASCII(2.x)을 기본 인코딩으로 사용한다.
{% highlight python %}
디폴트 인코딩을 따르지만 선언시 선언한 형식으로 인코딩한다
-- coding: utf-8 --
data = “hello world”
{% endhighlight %}
인코딩과 디코딩은 서로 다른 형식으로 변환을 할경우 에러를 유발한다.
클로저(closure) & 데코레이터(decorator)
클로저(closure)는 함수안의 함수를 결과로 반환할때 출력되는 함수를 클로저 라고 부른다. 클로저는 아래와 같은 경우에 사용한다.
콜백함수
함수 실행 순서 조정
데코레이터 함수
{% highlight python %}
def func1():
def func2():
return
return func2
if name==”main”:
data1 = func1()
real_data = data1() #클로저 사용법
{% endhighlight %}
데코레이터(decorator)는 함수를 인수로 받는 클로저를 의미하며, 함수를 꾸며주는 함수로 어노테이션으로 @를 사용해서 표현이 가능하다.
{% highlight python %}
def func3()
return
def func1(func3):
def func2():
func3()
return
return func2
data1 = func1(func3)
real_data = data1()
—————————#same
def func1(func3):
def func2():
func3()
return
return func2
@func1
def func3()
return
real_data = func3()
{% endhighlight %}
이터레이터(iterator) & 제너레이터(generator)
이터레이터(iterator)는 for문과 같이 순차적으로 사용할 수 있는 객체를 의미하며 한번 사용시 재사용할 수 없다.
iter()를 이용하여 반복 객체 생성
next()를 이용하여 객체에서 각각 다음값을 추출
{% highlight python %}
list1 = []
iterator = iter(list1)
next(iterator)
next(iterator)
…
{% endhighlight %}
제너레이터(generator)는 이터레이터를 생성하는 함수로 함수의 출력이 순차적으로 다른 값을 출력하기 원할때 사용한다.
{% highlight python %}
def generator():
yield ‘a’
yield ‘b’
yield ‘c’
gen = generator()
next(gen)
next(gen)
…
{% endhighlight %}
타입 어노테이션(type annotaion)
타입 어노테이션(type annotaion)은 각변수의 자료형을 적시하는 것으로 에러의 가능성을 감소시키고, 코드의 가독성과 협업의 효율성을 위하여 사용한다.
{% highlight python %}
def func(data1: , data2: ) ->
func__annotations__
#{data1: int, ‘data2’: int, ‘return’: int }
{% endhighlight %}
문자열 처리
문자열을 처리하는 방식으로는 str(), repr() 두가지가 있으며 아래의 특징을 가진다.
str() : 사용자 인터페이스 문자열
repr() : 프로그램 인터페이스 문자열
{% highlight python %}
data = repr(“hello world”)
eval(data) #프로그램에서 다시 사용가능한 형태로 변형
{% endhighlight %}
외부라이브러리 사용
pip 라이브러리 매니저
{% highlight shell %}
pip install
pip uninstall
pip install <pkg==version> 버전별 설치
pip install —upgrade 업그레이드
pip list
pip list —format=freeze > requirements.txt 리스트 파일로 저장
pip install -r requirements.txt 리스트 설치
{% endhighlight %}
PYTHON
/
Basic
· 2023-08-21
-
-
-
-
클래스
클래스
클래스(class)는 각각의 개념화된 사물들을 객체화(object) 할 수 있고 이러한 객체들이 속성을 공유하는 방식을 지칭한다. 클래스 또한 함수와 같이 재사용성에 있어서 효과적이고, 유지보수에 유용하다. 클래스는 아래의 특징을 가진다.
상속(inheritace) : 상위의 개념과 하위의 개념간에 개념을 상속해주고 계승하는것을 의미한다. 상위의 개념은 superclass, 하위의 개념은 subclass라고 칭한다. e.x. 포유류(superclass) 고양이, 삵(subclass)
다양성(polymorphism) : 하위의 개념들이 상위의 개념에서 받은 개념 이외에 다양성을 가지는 것을 의미한다. e.x. 상위 개념(짖는다) 하위개념 (왈왈, 짹짹)
추상화(abstraction) : 클래스의 내부를 보지 않아도 내부의 변수와 같은것들을 보지 않아도 알수 있는것을 의미한다.
은닉화(encapsulation) : 클래스 내부에 변수(class variable) 기능(class method)을 가지게 되는것을 의미한다.
클래스가 사용하는 메서드는 다음과 같이 나눠질 수 있다.
인스턴스 메서드 : 첫번째 파라미터로 self를 가진다.
클래스 메서드 : 클래스의 속성에 접근하는것으로 cls파라미터 사용
정적 메서드 : 메서드가 인스턴스와 독립적으로 사용될때 사용
매직 메서드 :
클래스는 생성자(constructor)(init)를 이용하여 기본형을 정의한다.
(str)은 문자열화를 하여 서로 다른 객체 간의 정보를 전달하는 데 사용된다.
(repr)은 인간이 이해할 수 있는 표현으로 나타내기 위한 것입니다.
우선 순위는 __str__이 __repr__보다 높다.
추상 메서드 : 자식 class에서 필수적으로 구현해야하는 것을 지정
각각의 매서드들은 아래와 같이 사용이된다.
{% highlight python %}
class ():
data0 = 0
def __init__(self, data1, data2):
self.data1 = data1
...
def instance_method1(self, data3, data4): # 인스턴스
action
return 0
@classmethod
def class_method1(cls): # 클래스
print(f”{cls.data0}”)
@staticmethod
def static_method1(): # 정적
return
def str(self) -> str: # 매직
return f””
def repr(self) -> str:
return f””
@abstractmethod
def abstract_method1(self): # 추상
pass
{% endhighlight %}
클래스의 속성은 다음과 같이 구분을 할 수 있다.
각 객체의 속성
{% highlight python %}
class ():
def __init__(self, data1):
self.data1 = data1 # 각 객체의 속성
{% endhighlight %}
모든 객체가 공유하는 속성
{% highlight python %}
class ():
data0 = 0
def __init__(self, data1):
self.data1 = data1
.data0 += 1 # 모든 객체가 공유하는 속성
{% endhighlight %}
클래스 내부에서만 접근 가능한 속성(네임 맹글링(name mangling) 을 이용하여 변경은 가능)
{% highlight python %}
class ():
def __init__(self, data1):
self.__data1 = data1 # 불변 속성
.___data1 = "x" # 네임 맹글링 하는법
{% endhighlight %}
docstring은 모듈, 함수, 클래스 또는 메소드 정의의 첫 번째에 오는 문자열으로 해당 객체의 doc 속성으로 사용됨.
{% highlight python %}
class ():
"""
문서화 자료 입력
"""
def __init__(self, data1):
{% endhighlight %}
PYTHON
/
Basic
· 2023-08-15
-
함수
함수
함수에는 입력과 출력이 존재하며, 입력을 받아서 함수가 가공후 출력을 하는것이 일반적인 형태이다. 어떠한 반복적인 활동(재생산성)이 필요할때 코드의 간편화를 위해 사용이된다. 코드를 함수화 하면 가독성이 증가하는 장점이 있음
{% highlight python %}
def name(input):
action1
action2
return output
var3 = name(var1, var2)
{% endhighlight %}
인수(arguments)는 함수 호출시 전달하는 입력값은 지칭한다.
매개변수(parameter) : 매개변수는 함수에서 input을 의미한다.
디폴트 매개변수 : 매개변수에 디폴트값(초기값)을 설정해 줄수 있다. 매개변수가 여러개일때 디폴트값을 뒤에서 부터 작성
{% highlight python %}
def name(var1, var2=’data2’):
action1
action2
return output
{% endhighlight %}
가변 매개변수 : 매개변수를 여러개 사용할때 (*)을 이용하여 튜플화 하여 불러올 수 있다. 가변 매개변수 뒤에는 일반 매개변수가 올수 없음
{% highlight python %}
def name(var1, *vars): # vars = [‘data2’,’data3’]
action1
return output
name(‘data1’, ‘data2’,’data3’)
{% endhighlight %}
키워드 매개변수 : 매개변수에 값을 넣을때 순서대로 입력을 받는데 키워드를 이용하면 순서와 상관없이 값을 넣을 수 있게된다.
{% highlight python %}
def name(var1, var2):
action1
return output
name(var1 = ‘data1’, var2 = ‘data2’)
{% endhighlight %}
키워드 가변 매개변수 : 키워드 매개변수를 여러개 사용할때 (**)을 이용하여 딕셔너리화 하여 불러올 수 있다.
{% highlight python %}
def name(**vars): # vars = {‘var1’:’data1’, ‘var2’:’data3’}
action1
return output
name(var1 = ‘data1’, var2 = ‘data2’)
{% endhighlight %}
지역변수(local variable)와 전역변수(global variable) : 함수를 사용하게 되면 주의해야하는 것중에 하나가 지역변수와 전역변수의 혼동을 막는것이다. 지역변수는 해당함수에서 사용이 되는 변수를 의미하고 전역변수는 함수의 내외 적으로 사용이 되는 변수를 의미한다.
{% highlight python %}
data2 = ‘value2’
data4 = ‘value4’
def func(data1, data2):
data3 = ‘value3’ # local variable
global data4 # global variable
print(data4) # value4
data2 = ‘value5’
data2는 인수를 받아서 지역변수화 된것을 활용하기에
전역변수인 data2는 변화없이 함수안에서만 value5로 작용
func(‘value1’,data2)
{% endhighlight %}
람다 함수(lambda function)
람다함수는 간단한 함수를 작성할때 사용이된다. 아래는 일반 함수를 람다 함수로 표현한 것이다.
{% highlight python %}
def add(a, b):
return a+b
add = lambda a, b : a + b
———————————– level up
lambda a : True if else False
{% endhighlight %}
map 함수
순서가 있는 자료형의 원소를 순차적으로 함수에서 활용하는 함수이다.
{% highlight python %}
list1 = [1,2]
def func1(data):
return data+1
data = map(func1 ,list1) # map object type
list(data) # type conversion
{% endhighlight %}
filter 함수
순서가 있는 자료형의 원소들에서 원하는 항목을 추출하는 함수이다.
{% highlight python %}
list1 = [1,2]
def func1(data):
return data > 1
data = filter(func1 ,list1) # filter object type
list(data) # type conversion
{% endhighlight %}
reduce 함수
순서가 있는 자료형의 원소들의 스택을 쌓는 함수이다.
{% highlight python %}
from functools import reduce
list1 = [1,2,3,4,5]
def func1(data1, data2):
return data1+ data2
data = reduce(func1 ,list1) # reduce object type
{% endhighlight %}
PYTHON
/
Basic
· 2023-08-14
-
입출력과 제어문
입출력
사용자 입력 및 출력
사용자 입력은 input() 함수를 이용하여 사용자로부터 문자열 자료형 데이터를 입력받는것이다. ()안에 작성하는 내용을 “프롬프트 문자열”이라고 한다.
사용자 출력은 print() 함수를 이용하여 자료형을 출력한다.
(+)를 이용하여 문자열을 더할 수 있다. (+)는 생략가능.
(,)를 이용하여 문자열을 띄워쓰기 가능하다.
파일 입력 및 출력
파일 입력은 open() 함수를 이용해서 파일을 열 수 있다.
{% highlight python %}
data = open(, )
{% endhighlight %}
mode의 종류는 아래와 같다.
write 모드는 파일을 작성하는 방법으로 아래와 같다.
{% highlight python %}
data = open(,"w") #path = D:/mydesk/a.txt or a.txt
data.write("Hello world")
data.close()
with open() as data:
# context manager(수행 방법을 기억하고 있는 방식)
# 기본적으로 사용하는 함수를 with문 안에 사용하면 되며
# with문을 나올 때 close를 자동으로 불러줍니다.
data.write("Hello world")
{% endhighlight %}
append 모드는 파일을 이어서 작성하는 방법으로 아래와 같다.
{% highlight python %}
data = open(,"a")
data.write("Hello world2")
data.close()
{% endhighlight %}
read 모드는 파일을 읽는 방법으로 아래와 같다.
readline() : 파일을 한줄씩 읽기(\n도 불려짐)
readlines() : 파일을 한번에 읽어서 리스트로 출력(\n도 불려짐)
strip() : 줄바꿈 문자(\n) 제거
{% highlight python %}
data = open(,"r")
for i in len(Data.readlines()):
text = data.readline().strip()
print(text)
list_data = []
with open(,"r") as data:
for text in list_data:
list_data.append(text.strip())
{% endhighlight %}
xb모드는 binay형식으로 사용할경우 wb, rb와 같이 사용한다.
제어문
if문
아래와 같은 형식이 가장 기본적인 형식이며 다양한 state에서 어떻게 action이 가해지는지에 대한 제어문이다.
{% highlight python %}
if state1:
action1
elif state2:
action2
else:
action3
{% endhighlight %}
in / not in 연산자는 데이터 안에 있는지 없는지를 구별하는 연산자로 아래와 같이 작용한다.
{% highlight python %}
if ‘a’ not in ‘state’:
action1
else:
action2
{% endhighlight %}
pass 키워드는 조건에 해당하지만 어떠한 액션도 없이 넘기고 싶을때 사용을 하며, 개발자들 사이에서는 추후에 작업을 하기위해 사용하기도 한다.
{% highlight python %}
if ‘a’ not in ‘state’:
pass
else:
action2
{% endhighlight %}
관계 & 논리 연산자
관계 연산자는 a, b의 관계를 알아보기 위한 연산자로 True / False로 값이 나오게 된다.
==(같음)
!=(다름)
<(오른쪽이 큼)
>(왼쪽이 큼)
<=(오른쪽이 크거나 같음)
>=(왼쪽이 크거나 같음)
논리 연산자는 논리적으로 참과 거짓을 나타내는 연산자로 True / False로 값이 나오게 된다.
not(부정)
and(논리 곱)
or(논리 합)
while & for문
loop case는 리스트 형과 같이 루프를 가질 수있는 형식들은 다음과 같다.
문자열 : 문자열은 리스트와 같이 각 문자들을 변수로 사용가능하다.
range() : 범위를 생성해주는 함수. (출력시 range()로 나오며 list()함수로 가시화 가능)
range(n)은 0~n-1의 정수 집합이다.
range(i,n)은 i~n-1의 정수 집합이다.
range(i,k,n)은 i~k-1까지 n의 차
for문은 아래와 같이 ~에서 반복이 될때 사용하는것으로 in에 해당하는 내용이 끝날때 까지 반복이된다. 특이점 중 하나는 딕셔너리형식을 반복할경우 변수로 key값이 도출된다.
{% highlight python %}
for var in list(‘or other loop case’):
action
{% endhighlight %}
while문 : 어떠한 조건이 있을때 조건에 해당하면 반복하는 반복문으로 아래와 같이 사용된다. 일명 무한 루프라고 하며 조건에서 탈출 할 수 없을경우 심각한 오류를 발생할 수 있음
{% highlight python %}
while state:
action1
action2
{% endhighlight %}
break 키워드는 반복문을 탈출 할때 사용이 되는 키워드로 무한 루프와 같은 에러발생이 의심되면 사용가능하다.
continue 키워드는 반복문에서 다음액션을 무시하고 처음부터 다시 시작하고 싶을때 사용이 가능하다.
PYTHON
/
Basic
· 2023-08-11
-
변수와 자료형
변수(variable)
어떠한 값을 담는 저장공간과 그것을 부르는 명칭으로 다음과 같은 규칙이 존재한다.
영문자, _로 시작을해야함
대소문자를 구분함
특수문자 사용불가능
공백이 존재할 수 없음
파이썬의 예약어(if else …) 사용불가능
변수에는 문자, 숫자, 데이터타입등을 선언할 수 있음. 변수를 선언하면 임의의 메모리와 주소를 할당함.
자료형(datatype)
사용자의 데이터를 프로그래밍 언어가 이해가능한 형식으로 정의 하는것을 일컬으며, 프로그램에서 저장하는 데이터의 타입으로 다음과 같은 형식들이 있다.
NoneType : 어디에도 속하지 않는 해석불가능 타입
숫자(numeric)
정수(integral)
정수(int) : -1,0,1,…
부울(bool) : 참과 거짓을 나타내는 자료형
실수(float) : 1.04
복소수(complex) : 1+5i
수열(sequence)
불변(immutable)
문자열(str) : 문자들의 집합
튜플(tuple) : 순서를 가지는 집합으로 ()으로 구성이됨
바이트(bytes) : 바이트 나열 타입 e.x. b’0’ == b’\x00’
변형(mutable)
리스트(list) : 순서를 가지는 집합으로 []으로 구성이됨
비트어레이(byte arrays) : 변형가능한 바이트 나열 타입
매칭(mapping)
딕셔너리 : 순서를 가지지 않은 집합으로 {}으로 구성되며 key와 value 쌍으로 구성이된다.
집합 : 중복이 없고 순서를 가지지 않는 객체의 모음
집합(set) : 중복이 없고 순서를 가지지 않는 객체의 모음
정적집합(frozen set) : 집합과 같지만 변형이 불가능
숫자형
숫자를 나타내는 형식으로 아래와 같다.
정수 : 소숫점이 없는 숫자
실수, 부동 소숫점 : 소숫점이 있는 숫자
숫자연산은 사칙연산, 나머지(%), 몫(//), 제곱(**)으로 구성된다.
숫자형변환은 문자형의 숫자, 형식이 다른 숫자형들 사이의 변환을 지원한다. $e.x., \;$ int(), float()
문자열 자료형
문자를 나타내는 형식으로 아래와 같은 방식을 따른다.
큰 따옴표, 작은 따옴표로 문자열 만들기
문자열 내부에 따옴표 넣기
이스케이프 문자를 사용해 문자열 만들기 e.x.) \n \t …
여러줄 문자열 만들기 e.x.)
줄바꿈 없이 문자열 만들기
문자열도 숫자열 처럼 연산이 가능해진다.
(+)연산자는 문자열을 더함
(*)연산자는 문자열을 반복함
문자열은 숫자열과 다르게 각각의 문자가 독립적으로 구성이 되는데 이에 따라서 인덱싱(열 내부의 값을 지정) 과 슬라이싱(문자열의 범위 선택)이 아래와 같이 가능하다.
([]) 문자 선택 연산자(넘버링을 통해서 순서대로 추출가능)
문자 선택 연산자를 이용하여 넘버링 하는것을 인덱스라고 한다.
순방향 인덱스는 0에서 부터 증가
역방향 인덱스는 -1에서 부터 감소
([:]) 문자 범위 선택 연산자
문자범위 선태가 전후에 인덱스를 이용하여 범위를 선택함
문자열에 다른 문자열과 숫자열을 넣으려고 할때 포멧에 맞춰서 넣어줘야 하며 포멧은 포멧팅은 여러 종류가 있다.
%포멧팅은 아래와 같다.
%d : 정수형 대입
%f : 실수형 대입
%s : 문자열 대입
%c : 문자 대입
%o : 8진수
%x : 16진수
{% highlight python %}
data = “hello %s world %d” %(“to this”, 10)
{% endhighlight %}
.format()포멧팅은 아래와 같다.
{% highlight python %}
data = “hello {0} world {1}”.format(“to this”, 10)
{% endhighlight %}
.f string 포멧팅은 아래와 같다.
{% highlight python %}
data = f”hello world "
{% endhighlight %}
---
문자열을 사용함에 있어서 주로 사용되는 함수는 아래와 같다.
.len() : 문자열 길이 출력
.split(’.’) : 문자열 나누기
.count() : 문자 갯수 세기
.replace(’a’,’b’) : 문자열 바꾸기
.find(’a’) : 문자열 인덱싱 찾기
.upper() : 문자열 대문자로 변경
.lower() : 문자열 소문자로 변경
‘a’.join(x) : 문자열 삽입 (x문자열의 문자사이에 a넣기)
리스트 자료형
([])의 내부에 요소들을 넣는 자료형을 지칭하며 ‘,’으로 구분되며 여러가지 자료형을 담을 수 있다.
리스트도 문자열과 같은 연산이 가능하다.
리스트형도 문자열 처럼 인덱싱과 슬라이싱이 가능하다.
리스트는 인덱싱 또는 슬라이싱을 기반으로 하여 내부의 요소들을 아래와 같이 변경 또는 삭제가 가능하다.
List[1] = ‘b’ : 리스트의 두번째 요소를 ‘b’로 변경
List[1:3] = [’a’,’b’] : 리스트의 두번째, 세번째 요소를 ‘a’,‘b’로 변경
del List[n] = 리스트 n+1번째 요소 삭제
리스트 자료형을 사용함에 있어서 주로 사용되는 함수는 아래와 같다.
len(List[]) : 리스트 길이 출력
.sort() : 리스트 정렬
.reverse() : 리스트 뒤집기
.append(x) : 리스트 뒤에 요소 추가
.extend([]) : 리스트 확장
.insert(n,’a’) : n+1번째에 ‘a’삽입
.remove(n) : 리스트 n+1번째 요소 제거
.pop(n) : 리스트 n+1번째 요소 꺼내기(꺼낸 요소는 삭제됨)
.count(x) : 리스트에 포함된 ‘x’의 갯수 확인
튜플 자료형
(())의 내부에 요소들을 넣는 자료형을 지칭하며 ‘,’으로 구분되며 여러가지 자료형을 담을 수 있다. 리스트와 다른점은 내부의 데이터가 수정 및 삭제가 안되는것이다.
특이점으로는 하나의 요소를 사용할때는 마지막에 (,)가 필요하고, (()) 없이도 튜플로 사용이 가능한것이다.
튜플도 리스트와 같은 연산이 가능하다.
튜플도 리스트형 처럼 인덱싱과 슬라이싱이 가능하다.
딕셔너리 자료형
({})의 내부에 요소들을 넣는 자료형을 지칭하며 key, value로 구분되며 여러가지 자료형을 담을 수 있다. 리스트와 비교해보면 인덱스 대신 key를 사용한다. 딕셔너리에서 value를 추출하기 위해서는 Dic[’key’]와 같이 사용한다.
딕셔너리는 내부의 value를 변경과 삭제가 가능하다.
딕셔너리 자료형을 사용함에 있어서 주로 사용되는 함수는 아래와 같다.
.keys() : key값을 리스트로 만듬
.values() : value값을 리스트로 만듬
.items() : key,value 쌍 얻기
.get(key) : key로 value 얻기
‘key’ in Dic : key가 존재하는지 확인
.clear() : 딕셔너리 내부 삭제
집합 자료형
set()을 사용하는 비중복성 자료형이다. 명제의 집합과 같은 형태를 가진다.
집합은 다음과 같은 연산이 가능하다.
| (합집합) : 집합간의 합집합을 구한다.
& (교집합) : 집합간의 교집합을 구한다.
- (차집합) : 집합간의 차집합을 구한다.
집합 자료형을 사용함에 있어서 주로 사용되는 함수는 아래와 같다.
.add(’a’) : 한개의 값(’a’)을 추가
.update([]) : 여러개의 값([])을 추가
.remove(’a’) : 특정값(’a’) 삭제
부울 자료형
참과 거짓을 나타내는 자료형으로 조건형으로 사용된다. $e.x., \;$ “a” == “a”, bool(’’)⇒False, bool(’d’)⇒True
PYTHON
/
Basic
· 2023-08-10
-
-
Django unit test
What is serializer
test
test_base
normal serializer
일반적인 seriallizer는 serializers.Serializer의 상속을 받아 아래와 같이 작성하게 됩니다.
{% highlight python %}
class UserSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
name = serializers.CharField(required=False, allow_blank=True, max_length=10)
def create(self, validated_data):
return models.User.objects.create(**validated_data) {% endhighlight %}
위와 같은 방식은 model과 상관없이 serializer를 설정하고 싶을때 사용할 수 있으며, model을 활용하여 사용하는 방법도 있습니다.
model serializer
model seriallizer는 serializers.ModelSerializer의 상속을 받아 아래와 같이 작성하게 됩니다. 아래의 방식은 model이 선언되어 있을때 사용하기 용이하며 코드를 간편하게 해줍니다.
{% highlight python %}
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = models.User
fields = [‘id’, ‘name’]
{% endhighlight %}
method field
method field는 다른 field를 활용하여 재가공하여 사용하는 방식입니다. 대표적으로 id값이 있고 id의 길이를 확인하는 방법입니다.
{% highlight python %}
class UserSerializer(serializers.ModelSerializer):
is_long = serializers.SerializerMethodField()
class Meta:
model = models.User
fields = ['id', 'name']
def get_is_long(self, instance: CheckedCrn):
if len(instance.id) > 2:
return "long"
else:
return "short" {% endhighlight %}
dict -> json -> dict
때에 따라서는 데이터의 형태가 계속 변경이 되어야 할 수 있습니다. 그에따라 형변환을 하는 법을 나타냅니다.
{% highlight python %}
import io
from rest_framework.renderers import JSONRenderer
content = JSONRenderer().render(serializer.data) # json
stream = io.BytesIO(content)
data = JSONParser().parse(stream)
serializer = UserSerializer(data=data)
serializer.is_valid()
serializer.validated_data # check data
serializer.save()
serializer.data # dict
{% endhighlight %}
nested serializer
N in (1:N)
1:N 의 형식에서 N의 입장은 다음과 같이 바로 활용이 가능합니다.
seriallizer
{% highlight python %}
class GroupOnlySerializer(serializers.ModelSerializer):
class Meta:
model = Group
fields = “all”
class UserWithGroupSerializer(serializers.ModelSerializer):
product = GroupOnlySerializer(read_only=True)
class Meta:
model = User
fields = "__all__" {% endhighlight %}
view
{% highlight python %}
class UserListAPIView(generics.ListAPIView):
“””
User GET ALL API
“””
queryset = User.objects.all().order_by(“-id”)
serializer_class = UserWithGroupSerializer
{% endhighlight %}
1 in (1:N)
1:N 의 형식에서 1의 입장은 역참조를 해야 하기 때문에 조금은 복잡합니다.
Read case
seriallizer
{% highlight python %}
class GroupSerializer(serializers.ModelSerializer):
class Meta:
model = Group
fields = “all”
class UserSerializer(serializers.ModelSerializer):
product = GroupSerializer(read_only=True, many=True)
class Meta:
model = User
fields = "__all__" {% endhighlight %}
view
{% highlight python %}
class UserListAPIView(generics.ListAPIView):
“””
User GET ALL API
“””
queryset = User.objects.all().order_by(“-id”)
serializer_class = UserSerializer
{% endhighlight %}
Write case
write case에서는 원래 read만 가능하기 때문에 create를 override하여 새로이 구성해줘야 합니다.
seriallizer
{% highlight python %}
class GroupSerializer(serializers.ModelSerializer):
class Meta:
model = Group
fields = “all”
class UserSerializer(serializers.ModelSerializer):
product = GroupSerializer(read_only=True, many=True)
class Meta:
model = User
fields = "__all__" {% endhighlight %}
view
{% highlight python %}
class UserListAPIView(generics.ListAPIView):
“””
User GET ALL API
“””
queryset = User.objects.all().order_by(“-id”)
serializer_class = UserSerializer
def create(self, validated_data):
groups = validated_data.pop(‘group’)
user = User.objects.create(**validated_data)
for group in groups:
Group.objects.create(user=user, **group)
return user
{% endhighlight %}
Next step
models
serializers
views
Prev(how to start)
Prev
-
Touch background to close