아이디어톤이 끝나고 <너낼역>을 가지고 중앙해커톤에 참여하게 되었다
나는 백엔드이기 때문에,,! 나경이랑 같이 백엔드 개발을 했다
먼저 db 설계서를 작성했는데
db 설계서를 바탕으로 User/Warning/UsedEye/Eye 이렇게랑 Seat/Train 이렇게 쪼개서 하기로 했다
나도 그렇고 나경이도 그렇고 당연히 처음보는 기차나 좌석 개발보다는 유저 부분이 더 쉬울줄 알았고,,
그래서 사다리타기로 내가 유저 파트 맡았을때는 기분이 좋았는데,, ㅎㅎㅎㅎㅎㅎ
//그러지 말았어야했다//
drf 로그인 방법에는 세션로그인 방식과 토큰 로그인 방식이 있다
처음에는 멋사 정규 세션때 배운 세션 로그인 방식으로 개발을 했다
models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.
class User(AbstractUser):
name = models.CharField(max_length=255, unique=True, default = False)
username = None
USERNAME_FIELD = "name"
REQUIRED_FIELDS = []
def __str__(self):
return f"{self.name}"
def save_user(self):
self.save()
def delete_user(self):
self.delete()
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
eye = models.IntegerField()
def __str__(self):
return f"{self.user.name}"
def save_profile(self):
self.save()
def delete_profile(self):
self.delete()
@classmethod
def update_profile(cls, user, eye):
profile = cls.objects.filter(user=user).update(eye=eye)
return profile
class Warnings(models.Model):
user = models.IntegerField()
created_at = models.DateTimeField(auto_now_add=True)
station = models.IntegerField()
class UsedEye(models.Model):
user = models.IntegerField()
created_at = models.DateTimeField(auto_now_add = True)
amount = models.IntegerField()
class Eye(models.Model):
user = models.IntegerField()
created_at = models.DateTimeField(auto_now_add = True)
amount = models.IntegerField()
serializers.py
from rest_framework import serializers
from .models import *
from django.contrib.auth import authenticate
from django.contrib.auth.password_validation import validate_password
class UserSerializer(serializers.ModelSerializer):
profile='ProfileSerializer(many=False,read_only=True)'
class Meta:
model = User
fields = ['pk','name','profile','username']
extra_kwargs={
"profile":{'read_only':True}
}
class ProfileSerializer(serializers.ModelSerializer):
user = UserSerializer(read_only=True)
class Meta:
model = Profile
fields = "__all__"
class UpdateProfileSerializer(serializers.ModelSerializer):
user = UserSerializer(read_only=True,many=False)
class Meta:
model = Profile
fields = "__all__"
def get_profile(self,instance,data):
instance.bio = data.get('eye', instance.eye)
instance = super().get_fields(instance, data)
return instance
def update(request, instance, validated_data):
instance.eye = validated_data['eye']
instance.save()
instance=super().update(instance,validated_data)
return instance
class LoginSerializer(serializers.Serializer):
name = serializers.CharField(write_only=True, required=True)
password = serializers.CharField(write_only=True, required=True)
def validate_user(self):
new_user = authenticate(
name=self.validated_data["name"],
password=self.validated_data["password"],
)
if new_user is not None:
return new_user
raise serializers.ValidationError("The User does not Exist")
# User create serializer
class UserCreateSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ("id", "name", "username", "password")
extra_kwargs = {"password": {"write_only": True}}
def create(self, validated_data):
user = User.objects.create_user(**validated_data)
return user
# Changing the password
class ChangePasswordSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=True, validators=[validate_password])
password2 = serializers.CharField(write_only=True, required=True)
old_password = serializers.CharField(write_only=True, required=True)
class Meta:
model = User
fields = ('old_password', 'password', 'password2')
def validate(self, attrs):
if attrs['password'] != attrs['password2']:
raise serializers.ValidationError({"password": "Password fields didn't match."})
return attrs
def validate_old_password(self, value):
user = self.context['request'].user
if not user.check_password(value):
raise serializers.ValidationError({"old_password": "Old password is not correct"})
return value
def update(self, instance, validated_data):
user = self.context['request'].user
if user.pk != instance.pk:
raise serializers.ValidationError({"authorize": "You dont have permission for this user."})
instance.set_password(validated_data['password'])
instance.save()
return instance
class WarningListSerializer(serializers.ModelSerializer):
class Meta:
model = Warnings
fields = '__all__'
class UsedEyeSerializer(serializers.ModelSerializer):
class Meta:
model = UsedEye
fields = '__all__'
class EyeSerializer(serializers.ModelSerializer):
class Meta:
model = Eye
fields= '__all__'
views.py
from django.shortcuts import render
from .models import *
from django.views.generic import ListView
from rest_framework.response import Response
from rest_framework.authtoken.models import Token
from rest_framework.permissions import IsAuthenticated
from rest_framework import status, mixins, generics
from django.contrib.auth import authenticate, login, logout
from .serializers import *
from rest_framework.views import APIView
from drf_yasg.utils import swagger_auto_schema
class LoginAPIView(APIView):
@swagger_auto_schema(request_body=LoginSerializer)
def post(self, request, format=None):
serializer = LoginSerializer(data=request.data)
if serializer.is_valid():
user = serializer.validate_user()
data = {
"message": "User logged in successfully",
"name": user.name,
"user_id":user.id
}
# get auth token
token, created = Token.objects.get_or_create(user=user)
data["token"] = token.key
# data["User"]=user
responseStatus = status.HTTP_200_OK
return Response(data, status=responseStatus)
else:
Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class UserCreateAPIView(APIView):
@swagger_auto_schema(request_body=UserCreateSerializer)
def post(self, request, format=None):
data = request.data
print("data",data)
name = data["name"]
serializer = UserCreateSerializer(data=request.data)
if serializer.is_valid():
serializer.save(user_type=user_type)
data = {"name": data["name"], "message": "User created successfully"}
return Response(data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class LogoutAPIView(APIView):
def get(self, request, format=None):
logout(request)
return Response(status=status.HTTP_200_OK)
class ChangePasswordView(generics.UpdateAPIView):
queryset = User.objects.all()
permission_classes = (IsAuthenticated,)
serializer_class = ChangePasswordSerializer
class ProfileAPIview(generics.GenericAPIView):
lookup_field = 'user'
queryset = Profile.objects.all()
serializer_class = ProfileSerializer
def get(self, request, pk=None):
instance = self.get_object()
print("instance",instance)
instance.eye=request.data['eye']
instance.get_fields=['eye']
return Response('done')
class ProfileUpdateAPIview(generics.GenericAPIView):
lookup_field = 'user'
queryset = Profile.objects.all()
serializer_class = UpdateProfileSerializer
def put(self, request, pk=None):
instance = self.get_object()
print("instance",instance)
instance.eye=request.data['eye']
instance.save(update_fields=['eye'])
return Response('done')
class WarningListView(generics.GenericAPIView, mixins.ListModelMixin):
serializer_class = WarningListSerializer
def get_queryset(self):
return Warnings.objects.all().order_by('id')
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
class WarningView(ListView):
def get_queryset(self, **kwargs):
queryset = Warnings.objects.filter(id = self.request.session.get('user'))
return queryset
class UsedEyeListView(generics.GenericAPIView, mixins.ListModelMixin):
serializer_class = UsedEyeSerializer
def get_queryset(self):
return UsedEye.objects.all().order_by('id')
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
class UsedEyeView(ListView):
def get_queryset(self, **kwargs):
queryset = UsedEye.objects.filter(id = self.request.session.get('user'))
return queryset
class EyeListView(generics.GenericAPIView, mixins.ListModelMixin):
serializer_class = EyeSerializer
def get_queryset(self):
return Eye.objects.all().order_by('id')
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
class EyeView(ListView):
def get_queryset(self, **kwargs):
queryset = Eye.objects.filter(id = self.request.session.get('user'))
return queryset
서버상으로 다 돌아가서 배포까지 완료했는데
프론트와 연동하는 과정에서 세션ID가 발급되지 않는 문제가 발생했다
신기하게 회원가입은 다 되는데 로그인이 안되는...ㅎㅎㅎ
cors 도 허용하구,, 다 했는데도 해결이 안돼서 결국 token 로그인 방법으로 바꾸기로 했다
models.py
from django.db import models
from django.contrib.auth.models import AbstractUser, BaseUserManager
from django.core.validators import MinValueValidator, MaxValueValidator
# Create your models here.
class CustomUserManager(BaseUserManager):
def create_user(self, email, password, **extra_fields):
if not email:
raise ValueError('Users must have an email address')
user = self.model(email=self.normalize_email(email), **extra_fields)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_active', True)
if extra_fields.get('is_staff') is not True:
raise ValueError('Superuser must have is_staff=True.')
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True.')
return self.create_user(email=self.normalize_email(email), password=password, **extra_fields)
class User(AbstractUser):
email = models.EmailField(max_length=20, unique=True)
username = models.CharField(max_length=40, unique=False, default='')
eyes = models.CharField(max_length=40, default='')
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = CustomUserManager()
class Profile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
class Train(models.Model):
train_id = models.IntegerField()
class Seat(models.Model):
train = models.ForeignKey(Train, on_delete=models.CASCADE, related_name='seat')
user = models.ForeignKey(User, on_delete=models.CASCADE)
seat_num = models.IntegerField(validators=[MinValueValidator(1), MaxValueValidator(36)])
is_seated = models.BooleanField(default=False)
station = models.IntegerField(null=True, blank=True, validators=[MinValueValidator(1), MaxValueValidator(63)])
class UsedEye(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, related_name='usedeye')
created_at = models.DateTimeField(null = True, blank = True)
amount = models.IntegerField()
class Eye(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, related_name='eye')
created_at = models.DateTimeField(null = True, blank = True)
amount = models.IntegerField()
class Warning(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, related_name='warning')
created_at = models.DateTimeField(null = True, blank = True)
station = models.IntegerField(null=True, blank=True, validators=[MinValueValidator(1), MaxValueValidator(63)])
serializers.py
from rest_framework import serializers
from .models import *
from django.contrib.auth import login
from rest_framework.response import Response
from django.contrib.auth.hashers import make_password
from rest_framework_simplejwt.tokens import RefreshToken
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'email', 'password', 'username']
def create(self, validated_data):
user = User.objects.create(
email=validated_data['email'])
user.set_password(validated_data['password'])
user.save()
login(self.context['request'], user)
return user
class UserLoginSerializer(serializers.Serializer):
email = serializers.EmailField(max_length=64)
password = serializers.CharField(max_length=128, write_only=True)
def validate(self, data):
email = data.get("email", None)
password = data.get("password", None)
if User.objects.filter(email=email).exists():
user = User.objects.get(email=email)
if not user.check_password(password):
raise serializers.ValidationError('잘못된 비밀번호')
else:
token = RefreshToken.for_user(user)
refresh = str(token)
access = str(token.access_token)
data = {
'user': user.email,
'access_token': access,
'username': user.username
}
return data
else:
raise serializers.ValidationError('존재하지 않는 유저')
class Profileserialzier(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'username', 'password', 'eyes']
class PasswordChangeSerializer(serializers.Serializer):
password = serializers.CharField(max_length=128, write_only=True)
def update(self, instance : User, validated_data):
instance.password = make_password(validated_data['password'])
instance.save()
return Response()
def create(self, validated_data):
pass
class SeatSerializer(serializers.ModelSerializer):
class Meta:
model = Seat
fields = ['id', 'user', 'train', 'seat_num', 'is_seated', 'station']
class TrainSerializer(serializers.ModelSerializer):
seat = SeatSerializer(many=True, read_only=True)
class Meta:
model = Train
fields = ['id', 'train_id', 'seat']
class UsedEyeSerializer(serializers.ModelSerializer):
class Meta:
model = UsedEye
fields = ['user', 'created_at', 'amount']
class EyeSerializer(serializers.ModelSerializer):
class Meta:
model = Eye
fields = ['user', 'created_at', 'amount']
class WarningSerializer(serializers.ModelSerializer):
class Meta:
model = Warning
fields = ['user', 'created_at', 'station']
views.py
from django.shortcuts import get_object_or_404
from .serializers import *
from .models import *
from rest_framework import views
from rest_framework.response import Response
from rest_framework.status import *
from django.contrib.auth import login, logout
# Create your views here.
class SignUpView(views.APIView):
def post(self, request, format=None):
serializer = UserSerializer(
context={'request': request}, data=request.data)
if serializer.is_valid():
serializer.save()
return Response({'message': '회원가입 성공', 'data': serializer.data})
return Response({'message': '회원가입 실패', 'data': serializer.errors})
def get(self, request):
users = User.objects.all()
serializer = UserSerializer(users, many=True)
return Response({'message': '유저 목록 조회 성공', 'data': serializer.data}, status=HTTP_200_OK)
def patch(self, request):
user = User.objects.get(id=request.user.id)
serializer = UserSerializer(user, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
return Response({'message': 'username 입력 성공', 'data': serializer.data}, status=HTTP_200_OK)
return Response({'message': 'username 입력 실패', 'data': serializer.errors}, status=HTTP_400_BAD_REQUEST)
class LoginView(views.APIView):
def post(self, request):
serializer = UserLoginSerializer(data=request.data)
if serializer.is_valid():
return Response({'message': "로그인 성공", 'data': serializer.validated_data}, status=HTTP_200_OK)
return Response({'message': "로그인 실패", 'data': serializer.errors}, status=HTTP_400_BAD_REQUEST)
class LogoutView(views.APIView):
def get(self, request, format=None):
logout(request)
return Response({'message': "로그아웃 성공"}, status=HTTP_200_OK)
class ProfileView(views.APIView):
def get(self, request):
user = User.objects.get(id = request.user.id)
serializer = Profileserialzier(user)
return Response({'data': serializer.data}, status=HTTP_200_OK)
def patch(self, request):
user = User.objects.get(id = request.user.id)
serializer = Profileserialzier(user, data=request.data, partial = True)
if serializer.is_valid():
serializer.save(user=request.user)
return Response({'message': 'eye 성공', 'data': serializer.data}, status=HTTP_200_OK)
return Response({'message': 'eye 실패', 'data': serializer.errors}, status=HTTP_400_BAD_REQUEST)
class PasswordChangeView(views.APIView):
serializer_class = PasswordChangeSerializer
def post(self, request):
user = User.objects.filter(user=request.user)
user.set_password(request.data.get('password'))
print(request.data.get('password'))
print(request.data)
user.save()
return Response({'message': "비밀번호 변경 성공"}, status=HTTP_200_OK)
class TrainListView(views.APIView):
def get(self, request, format=None):
trains=Train.objects.all()
serializer=TrainSerializer(trains, many=True)
return Response(serializer.data)
class TrainDetailView(views.APIView):
def get(self, request, pk, format=None):
train = get_object_or_404(Train, pk=pk)
serializer = TrainSerializer(train)
return Response(serializer.data)
class SeatListView(views.APIView):
def get(self, request, format=None):
seats=Seat.objects.all()
serializer=SeatSerializer(seats, many=True)
return Response(serializer.data)
class SeatDetailView(views.APIView):
def get(self, request, pk, format=None):
seat = get_object_or_404(Seat, pk=pk)
serializer = SeatSerializer(seat)
return Response(serializer.data)
def get_object(self, pk):
return Seat.objects.get(pk=pk)
def patch(self, request, *args, **kwargs):
pk = self.kwargs.get('pk')
seat_object = self.get_object(pk)
serializer = SeatSerializer(seat_object, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
return Response({'message':'좌석 정보 기입 성공', 'data':serializer.data})
return Response({'message':'좌석 정보 기입 실패', 'error':serializer.errors})
class UsedEyeView(views.APIView):
def patch(self, request):
serializer = UsedEyeSerializer(data=request.data)
if serializer.is_valid():
serializer.save(user=request.user)
return Response({'message': 'Used Eye 생성 성공', 'data': serializer.data}, status=HTTP_200_OK)
return Response({'message': 'Used Eye 실패', 'data': serializer.errors}, status=HTTP_400_BAD_REQUEST)
def get(self, request):
usedeye = UsedEye.objects.filter(user = request.user.id)
serializer = UsedEyeSerializer(usedeye, many=True)
return Response({'message': 'Used Eye 조회 성공', 'data': serializer.data}, status=HTTP_200_OK)
class EyeView(views.APIView):
def patch(self, request):
serializer = EyeSerializer(data=request.data)
if serializer.is_valid():
serializer.save(user=request.user)
return Response({'message': 'EYE 생성 성공', 'data': serializer.data}, status=HTTP_200_OK)
return Response({'message': 'EYE 생성 실패', 'data': serializer.errors}, status=HTTP_400_BAD_REQUEST)
def get(self, request):
eye = Eye.objects.filter(user = request.user)
serializer = EyeSerializer(eye, many=True)
return Response({'message': 'EYE 조회 성공', 'data': serializer.data}, status=HTTP_200_OK)
class WarningView(views.APIView):
def patch(self, request):
serializer = WarningSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response({'message': '경고 생성 성공', 'data': serializer.data}, status=HTTP_200_OK)
return Response({'message': '경고 생성 실패', 'data': serializer.errors}, status=HTTP_400_BAD_REQUEST)
def get(self, request):
warning = Warning.objects.filter(user = request.user)
serializer = WarningSerializer(warning, many=True)
return Response({'message': '경고 조회 성공', 'data': serializer.data}, status=HTTP_200_OK)
결국 이렇게 바꿔서 배포하고 프론트와 무사히 연동해서 잘 굴러가는 웹사이트를 만들었다ㅠㅠ
중앙해커톤이 얼마 남지 않은 시점에 session로그인이 안되는 것을 알게되어서
token 로그인 방식으로 바꾸느라 좀 고생했던것 같고,, (session 로그인 안되는 오류를 언니들도 처음본다고하구 서버 상으로는 멀쩡히 돌아가니까 프론트 언니랑 화면공유하면서 엥ㅇㅇ??안돼??에ㅔ?? 서버돌아가??에?? 이게 어떻게이래??.. 를 반복해따..)
배포를 몇번이나 했는지 모르겠지만^^ 다행히 잘 끝났다
다 끝내긴 했지만 궁금한점들이
1. 대체 왜 세션 로그인이 안됐던걸까?..?
2. username을 바꾸는거랑 password change 하는걸 profile 만들어서 url 하나로 수정할수 있게하고 싶었는데,,
결국 방법을 찾지 못했다
-> 프론트에서도 합쳐줄수 있냐고 했었는데,, 일단 지금 코드로 돌아가니까 엎어버리지 말자는 결론이 나와서 기각
다행히 현재 eye 개수를 profile에 넣는거는 성공했다
3. 상식적으로 생각했을때 사용한 eye/ 충전한 eye/ 현재 eye 를 model 하나(eye model)로 관리할수 있어야하는거같은데
백엔드 운영진언니가 그렇게 하면 어려워질거라고 따로 분리하라구 해서 그렇게 했는데 내 실력으로는ㅋㅋㅋㅋ 그게 옳은 선택이었지만 아직도 궁금하긴하다..
세션 로그인 땜에&&==^^ 구글에다가 session login cors error token login drf 등등으로 검색해서 나오는 페이지를 거의 다 들어가본듯ㅋㅋㅋㅋㅋㅋㅋㅋㅋ아ㅠ
다음 글에다가 한번에 정리해보려구 한다!!
NNAERYEOK
NNAERYEOK has 3 repositories available. Follow their code on GitHub.
github.com
React App (nny-front-89dkx3f4w-nny.vercel.app)
React App
nny-front-89dkx3f4w-nny.vercel.app
'멋쟁이 사자처럼 10기 > 중앙해커톤' 카테고리의 다른 글
오류들// 그리고 참고한 자료들 총정리 (0) | 2022.08.26 |
---|