본문 바로가기

졸업 프로젝트

Signal을 이용하여 Profile 자동 생성하기 + RDS 접속

# 회원가입시 User의 Voice_Info 객체 생성하기

 

Django는 특정 작업이 발생하면 분리된 다른 앱에서 신호를 받아 특정 작업을 수행하는 Signal 기능이 존재한다.

파라미터는 다음이 있다.

  • sender : 신호를 수신할 특정 발신
  • receiver : 신호에 연결될 callback 함수
  • weak : 기본적으로 weak reference라고 한다. 이건 잘 모르겠다...
  • dispatch_uid : 중복 신호가 전송되는 경우 구별하기 위한 식별자

나는 sender, 즉 유저 회원가입 작업이 발생하면 그 user와 일대일로 매칭되는 voice_info 객체를 생성하는 receiver 함수를 만들 것이다.

# models.py

class Voice_Info(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    speed = models.FloatField(null=True, blank=True)
    pitch = models.FloatField(null=True, blank=True)
    type = models.TextField(null=True, blank=True)

    def __str__(self):
        return f'{self.user} voice_info'
        
# serializers.py

class VoiceInfoSerializer(serializers.ModelSerializer):
    user_id = serializers.ReadOnlyField(source='user.id')
    user = serializers.ReadOnlyField(source='user.nickname')

    speed = serializers.FloatField()
    pitch = serializers.FloatField()
    type = serializers.CharField()

    class Meta:
        model = Voice_Info
        fields=['id', 'user_id', 'user', 'speed', 'pitch', 'type']

voice 모델이랑 serializers 만들기~

# signals.py

from django.db.models.signals import post_save
from django.dispatch import receiver

from .models import Voice_Info, User

@receiver(post_save, sender=User)
def creat_voice_info(sender, instance, created, **kwargs):

    if created:
        Voice_Info.objects.create(user=instance)
        
# post_save.connect(create_voice_info, sender=User)

수신자 함수는 위에 사용한 것처럼 @데코레이터를 이용해도 되고, connect()를 이용해 수동으로 경로를 설정할 수도 있다.

signals 라이브러리에 있는 post_save 를 import 한다.

이름에서 알 수 있듯이 save 작업이 실행될 때 신호를 보낸다.

무엇이 save되느냐? sender=User로 User 모델이 save될때임을 명시했다.

만약 created된다면, user 정보를 받아서(voice가 user를 참조하므로 받아온다) voice 객체를 만드는 함수 생성 완료.

voice의 초기값은 null이 되어야 하므로 나는 아무 값도 넘겨주지 않고, model의 필드도 null=True로 설정했다. 

 

signal은 여러가지가 있다.

# django\db\models\signals.py
pre_init = ModelSignal(use_caching=True)
post_init = ModelSignal(use_caching=True)

pre_save = ModelSignal(use_caching=True)
post_save = ModelSignal(use_caching=True)

pre_delete = ModelSignal(use_caching=True)
post_delete = ModelSignal(use_caching=True)

m2m_changed = ModelSignal(use_caching=True)

pre_migrate = Signal()
post_migrate = Signal()

# django\core\signals.py
request_started = Signal()
request_finished = Signal()
got_request_exception = Signal()
setting_changed = Signal()

이름 보면 대충..아는 것도 있고 모르는 것도 있고...필요한건 나중에 찾아보자.

 

함수를 만들었으니 사용을 명시하자.

# apps.py

from django.apps import AppConfig


class AccountsConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'accounts'

    def ready(self):
        import accounts.signals

ready() 함수에 signals를 import해주면 사용이 가능하다.

ready() 함수는 django가 시작할 때 실행할 코드를 오버라이딩 하기 위해 있는 함수이다.

 

# __init__.py
default_app_config = 'accounts.apps.AccountsConfig'

ready 메소드 발생 등록!

아니면 settins.py에 accounts.apps.AccountsConfig를 등록하거나~

 

신기한 점이 배포 전에는 Config를 따로 등록하지 않아도 signal이 잘 작동했는데, 배포한 후에는 안돼서 Config를 등록하고 재배포 했다.

이유가 뭘까..? 아무튼 이렇게 하면 테스트도 잘 된다~

처음 생성하면 이렇게 null값

 

# Voice_Info 정보 조회/수정 함수
class VoiceInfoView(APIView):
    permission_classes = [IsAuthenticated, IsOwner]
    

    def get(self,request):
        userID=request.user.id
        voice = get_object_or_404(Voice_Info,user_id=userID)
        serializer = VoiceInfoSerializer(voice,context={'request': request})
        
        return Response({'message':'Voice Info 조회 성공','data':serializer.data},status=status.HTTP_200_OK)

    def put(self, request, format=None):
        userID=request.user.id
        voice = get_object_or_404(Voice_Info,user_id=userID)
        serializer = VoiceInfoSerializer(voice, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response({'message': 'voice 정보 수정 성공', 'data': serializer.data}, status=HTTP_200_OK)
        return Response({'message': 'voice 정보 수정 실패', 'data': serializer.errors}, status=HTTP_400_BAD_REQUEST)

또 VoiceInfo를 조회하거나 수정하는 작업도 필요하기에 따로 view를 따로 만들었다. 필요없는 API는..굳이 안만들었다. permission도 따로 만드는데 정말 귀찮았음

 

성공^^^

 

 


# RDS 날리기

 

배포를 다시 한 후...model을 건드렸기에 아예 그동안 가지고 놀았던 DB를 싹 날리고 다시 만들기로 했다.

[AWS] RDS 접속하기&DB 초기화 (tistory.com)

 

[AWS] RDS 접속하기&DB 초기화

로컬 컴퓨터에서 바로 RDS로 접속한다. mysql -h {엔드포인트} -u {계정명} -p 그리고 비밀번호 입력 이걸 한 이유는...데이터베이스를 초기화 하고 싶어서... RDS 삭제하고 다시하기는 싫었다. 외부에

jain5379.tistory.com

이거대로 하면 되기에 별 생각 안하고 시도했는데...오류가 났다!

can't connect to mysql server on 'RDS 주소~~' (10060)

왤까..? 인바운드와 아웃바운드 규칙 모두 허용으로 해두었는데...

헤매다가 깨달았던 것이 있다. 이번에 바뀐 IPv4 요금 정책 때문에 내가 RDS의 퍼블릭 엑세스를 허용하지 않음으로 바꿔놨었음;;

다시 허용으로 바꾸고 RDS 접속해서 DB 다시 만들고...했다.

아무래도 DB는 내가 직접 보고 관리하는게 편하긴 한데 요금 때문에 걱정이다.

일단은 DB 건드리고 엑세스 허용X로 바꿨다.

다시 만들때 EC2 서버 접속해서 migrate를 해줘야하는 불편함이 있다.

아무튼 성공!

sudo docker exec -it web python3 manage.py makemigrations / migrate 잊지않기!

 


# 회고

 

signal을 처음 써봤다. 재밌는 기능임. 뭔가 잘 써보고 싶은데 크게 쓸 일이 없다.

이번에 바뀐 요금 정책 때문에 지금 고생이다. AWS에 질문도 하고 있는데..큰 비용은 아니지만 1-2만원씩 야금야금 빼가는게 굉장히 짜증난다.

tts 호출도 정책..?때문에 서버에서 해야한다는데...할게 많아졌다ㅜ