PrimaryKey(PK) & ForeignKey(FK)

cdspacenoob·2022년 1월 2일
0

장고 프로젝트

목록 보기
11/15
post-thumbnail

django의 permission 기능에 대해 찾아보던 중 유익해보는 포스트를 발견했다. 그런데 거기서 아래와 같은 model 설정을 보게 되었다.출처: [Django] Authentication 과 Permissions

눈이 번뜩 뜨였다. FK를 사용하여 테이블을 연결하면 운동 기록들을 사용자에 직접 연결해놓을 수 있지 않을까?

지금까지는 각 테이블마다 username이라는 필드를 생성하고 CharField로 받았다.

ABC라는 username을 가진 사용자가 로그인하고 운동을 수행한 뒤 저장 버튼을 누르면, Unity앱에서는 playerprefs에 보관하고 있던 ABC라는 username과 함께 count / day / time 등의 값을 보낸다.

서버에서는 받은 데이터를 데이터베이스에 저장한다.

그 후 앱이나 웹에서 특정 username을 포함하여 원하는 자원에 연결된 url로 요청을 보내면, 각 기록을 받아갈 수 있도록 하였다.

이렇게 해도 큰 문제는 없었다. 하지만 FK를 한번 써보고싶단 생각이 있었기 때문에 바로 해볼 것이다.

from django.db import models
from django.contrib.auth.models import AbstractUser, PermissionsMixin

# 계정 정보
class User(AbstractUser, PermissionsMixin):
    class Meta:
        ordering = ['date_joined']

  
# 이두 운동 관련된 모델
class BicepsCurl(models.Model):
    username = models.CharField(max_length=25)

    count = models.IntegerField()
    count1 = models.IntegerField()
    count2 = models.IntegerField()

    sum_times = models.IntegerField(null=True)
    sum_count = models.IntegerField(null=True)

    times = models.FloatField(max_length=255)
    title = models.CharField(max_length=255, null=True)
    day = models.CharField(max_length=255, null=True)
    created = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return ("TotalCount:"+str(self.count)+" LCount:"+str(self.count1)+
                " RCount:"+str(self.count2)+" time:"+str(self.times)+" day:"+self.day)

    class Meta:
        ordering = ['created']


# 스쿼트 운동 관련 모델
class Squat(models.Model):
    username = models.CharField(max_length=25)

    count = models.FloatField(max_length=255)

    sum_times = models.IntegerField(null=True)
    sum_count = models.IntegerField(null=True)

    times = models.FloatField(max_length=255)
    title = models.CharField(max_length=255, null=True)
    day = models.CharField(max_length=255, null=True)
    created = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return "Count:"+str(self.count)+" Time:"+str(self.times)+" Date:"+self.day

    class Meta:
        ordering = ['created']


# 푸쉬업 운동 관련 모델
class PushUp(models.Model):
    username = models.CharField(max_length=25)

    count = models.FloatField(max_length=255)

    sum_times = models.IntegerField(null=True)
    sum_count = models.IntegerField(null=True)

    times = models.FloatField(max_length=255)
    title = models.CharField(max_length=255, null=True)
    day = models.CharField(max_length=255, null=True)
    created = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return "Count:"+str(self.count)+" Time:"+str(self.times)+" Date:"+self.day

    class Meta:
        ordering = ['created']

username이 공통적으로 들어가 있는 것을 볼 수 있다.
username을 단서로 하여 다른 값들을 특정하는 방법을 사용했었다.

이제 이걸 ForeignKey로 설정해볼 것임!

다른 건 특별할 것이 없고

# 이두 운동 관련된 모델
class BicepsCurl(models.Model):
    username = models.ForeignKey(User, on_delete=models.CASCADE)
    ...


# 스쿼트 운동 관련 모델
class Squat(models.Model):
    username = models.ForeignKey(User, on_delete=models.CASCADE)
    ...
    
    
# 푸쉬업 운동 관련 모델
class PushUp(models.Model):
    username = models.ForeignKey(User, on_delete=models.CASCADE)

models.CharField()models.ForeignKey(User, on_delete=models.CASCADE)로 바꿔주기만 했다.

이렇게 한 후 $ makemigrations$ migrate를 진행
DB를 밀고 실행했으므로 오류없이 잘 끝났다.
회원등록부터 해봤다.
굳굳 됩니다 돼요!
그 다음은 운동 기록을 저장해볼 것이다.
응 안됨.
PK 대신 Str값을 입력받았습니다

그렇다. 이제 알겠다! 특정 테이블의 PK가 다른 테이블에서의 FK가 되는 거구나!
그렇다면 User테이블의 username을 PK로 설정해주면 되겠다.

class User(AbstractUser, PermissionsMixin):
    username = models.CharField(uique=True, primary_key=True, max_length=30)
    
    class Meta:
        ordering = ['date_joined']

username을 끌고 잡아와서 unique=True, primary_key=True를 설정해줬다.

DB를 다시 밀고 $ makemigrations$ migrate 를 했다.
당연히 될 줄 알았는데..django.db.utils.OperationalError: (1553, "Cannot drop index 'PRIMARY': needed in a foreign key constraint")
난리가 나버렸다..

/migrations에 남은 파일들 때문일 수도 있겠단 생각이 든다.
지우고 실행해봤다.

됐다.. 😮
그럼 내부는 어떻게 된 거지?

원래 있어야할 'id'라는 pk가 사라졌다.
PyCharm에서 데이터베이스를 확인해봐도 pk가 없다.
다만 username에 pk를 의미하는 열쇠모양도 보이지 않는다.

일단 다른 테이블의 username필드가 FK역할을 할 수 있는지 확인해야겠다.

how라는 username으로 등록하고 biceps-list에 이두운동 결과를 등록해봤더니 잘 작동한다.

그렇다면 조회는?

정상적으로 잘 작동한다. 🙆‍♂️
휴 아주아주 다행이다.

username과 password를 줘서 탈퇴까지 하고 싶었는데 이 기능을 web쪽에만 넣어두고 app엔 구현해두지 않았다.😓

이렇게 pk와 FK를 설정하는 것까진 했지만 실제로 데이터베이스에서 어떤 식으로 사용해야할지는 좀 더 많은 양의 데이터를 다뤄봐야 알 것 같은데, 이건 공공데이터 포털이나 빅데이터 파일 중 쓸 만한 것을 찾아봐야겠다.

permission에 대해 찾아다니다보니 UserManager나 custom-permission을 쓰는 것을 많이 보게 되었다. 꽤 길고 따라해보려면 시간이 좀 더 들 것 같다.

model을 초반에 설계하는 게 정말 중요하단 생각이 든다.


[해설과 함께 읽는 Django 문서] Models - Automatic primary key 필드
기본키, 후보키, 외래키, 복합키 공부하기
[Django] Authentication 과 Permissions
[Mysql, MariaDB] PrimaryKey, Autoincrement 설정방법
model(1:N - 댓글, 글-유저연동) 과 User 커스텀, humanize

profile
Can do this all day

0개의 댓글