[TIL] 아직은 혼자 해결하기 어려운 에러들이 많다
오늘의 TIL은 하소연성 제목으로 적어보았다.
이번주가 너무 하드했기 때문..ㅠㅠ
어찌나 기를 빨렸는지 막판에는 앉아서 졸기까지 했다.....휴
어제 오후부터 개인 과제를 진행중이다.
파이썬에 기반해있지만 또 새로운 것을 배우는 것이고,
파이썬에 대해 완벽하게 이해하고 있는 것이 아니기 때문에 여러 가지 크고 작은 오류들이 생기고 있다^^;
이제는 차근차근 오류메세지를 읽고 원인이 된 코드를 찾아가 어떻게든 해결해보려 끙끙대어보고있는데,
그래도 쌓이는 오류들에는 아직 정확한 원인을 알 수 없는 오류들이 많다......
그래서 오늘은 혼자 해결하기 어려운 문제를 정리하여 경력자의 도움을 받아보았다^.^..
Today'sError 01
너무 긴 오류........ㅋㅋㅋ..에 멈춰버린 사고.
auth.User.groups: (fields.E304) Reverse accessor 'Group.user_set' for 'auth.User.groups' clashes with reverse accessor for 'user.UserModel.groups'.
HINT: Add or change a related_name argument to the definition for 'auth.User.groups' or 'user.UserModel.groups'.
auth.User.groups: (fields.E340) The field's intermediary table 'auth_user_groups' clashes with the table name of 'user.UserModel.groups'.
auth.User.user_permissions: (fields.E304) Reverse accessor 'Permission.user_set' for 'auth.User.user_permissions' clashes with reverse accessor for 'user.UserModel.user_permissions'.
HINT: Add or change a related_name argument to the definition for 'auth.User.user_permissions' or 'user.UserModel.user_permissions'.
auth.User.user_permissions: (fields.E340) The field's intermediary table 'auth_user_user_permissions' clashes with the table name of 'user.UserModel.user_permissions'.
auth_user: (models.E028) db_table 'auth_user' is used by multiple models: auth.User, user.UserModel.
user.UserModel.groups: (fields.E304) Reverse accessor 'Group.user_set' for 'user.UserModel.groups' clashes with reverse accessor for 'auth.User.groups'.
HINT: Add or change a related_name argument to the definition for 'user.UserModel.groups' or 'auth.User.groups'.
user.UserModel.groups: (fields.E340) The field's intermediary table 'auth_user_groups' clashes with the table name of 'auth.User.groups'.
user.UserModel.user_permissions: (fields.E304) Reverse accessor 'Permission.user_set' for 'user.UserModel.user_permissions' clashes with reverse accessor for 'auth.User.user_permissions'.
HINT: Add or change a related_name argument to the definition for 'user.UserModel.user_permissions' or 'auth.User.user_permissions'.
user.UserModel.user_permissions: (fields.E340) The field's intermediary table 'auth_user_user_permissions' clashes with the table name of 'auth.User.user_permissions'.
찾아보니 한 class 안에서 두 개 이상이 같은 외래키(foreignkey)를 참조했을 때 생기는 오류라고 한다.
따로 추가한 것이 없다보니 당황스러웠다...
class UserModel(AbstractUser):
class Meta:
db_table = "user_db"
# related_name을 추가해줍니다.
# related_name은 역참조할 때 사용하는 이름을 지정하는 것입니다.
# 이 이름으로 역참조에 사용할 수 있습니다.
groups = models.ManyToManyField('auth.Group', related_name='usermodel_set', blank=True)
user_permissions = models.ManyToManyField('auth.Permission', related_name='usermodel_set', blank=True)
gpt의 도움을 받아 manytomany로 바꿔주고, 역참조설정을 해주는 코드를 추가
어쩌다 이런 일이 생긴건지.... 해결방법을 알고 싶었다..
+++ 문제 해결 with 튜터님...
수준에 맞지도 않고 의미를 알 수 없는 gpt의 추가 라인을 지웠다
manytomany필드를 설정해 오류를 해결할 수는 있지만 이해도 없이 사용하는 것은 금물.
하지만 새벽에 발생한 문제라서 당장 도움을 받을 수 없었다구요..ㅠㅠ!!
AUTH_USER_MODEL = 'user.UserModel'
>> 유저모델을 settings에 세팅해줘야 오류가 날 확률을 줄일 수 있어서 먼저 설정해준다!
models를 고치고 새로운 model을 적용하기 위해서 makemigrations을 또 하면
약간의 오류가 생길 수 있는 듯하다..
편하게 해결하는 방법은
sqlitedb 삭제 /각 migrations폴더에 init을 남기고 지운 후 다시 makemigrations 명령어를 입력해주는 것이다.
그러니까 각각의 db저장내용을 없애 충돌확률을 줄여주는 것임.
대부분의 models.py를 수정해서 생기는 문제는 이 방법을 사용해볼 수 있다.
Today'sError? 02
product모델에 상품을 추가한 admin_name을 넣어보고 싶었다.
참고한 기본 모델 author = models.ForeignKey(UserModel, on_delete=models.CASCADE)를 수정하여
이러한 코드를 만들어보았다.
admin_name = models.ForeignKey(UserModel, on_delete=models.RESTRICT,
on_update=CASCADE, null=True, blank=True)
이후 서버를 실행하자 처음보는 오류(?) 메시지가 떴다.
1) Provide a one-off default now (will be set on all existing rows with a null value for this column).
2) Quit and manually define a default value in models.py.
오류메세지의 내용은 기존 데이터베이스에 존재하는 행들에 대해
어떤 값을 넣어줄지 지정하지 않으면 오류가 발생한다는 것이었다..
1, 2 둘 중 선택을 해야하는 상황, 열심히 찾아보았지만 그래서 어떤 값이 빠져있는 것인지 알 수가 없었다.
product 모델값에는.. 분명 만들고자 했던 모든 값들을 지정해주었기때문에
마찬가지로 문제에 대한 원인을 찾기가 쉽지 않았다.ㅠ
외래키 문제일까 싶어 소스코드를 타고 들어가보기도 했다..
Foreignkey 의 init
def __init__(
self,
to,
on_delete,
related_name=None,
related_query_name=None,
limit_choices_to=None,
parent_link=False,
to_field=None,
db_constraint=True,
**kwargs,
하지만 기본 값이 다 있는걸요,,?
+++ 오류메세지 해결 with 튜터님
이거 중에 어떤 것이 지정되지 않아서 위의 선택지가 뜬 것인지?
아니면 다른 문제인지 궁금했고..
아니면 참조한 부모테이블인 User모델에서의 값이 지정이 안된것인지에 대해 질문했다.
선택지 1은 시간 정보를 default값으로 now를 설정해주는 것인데,
그러면 매번 저장시마다 시간이 달라지는 문제가 있는 듯 하다.
선택지 2는 직접 빠진 값을 찾아서 넣어보라는 메세지였는데.. 혼자서는 불가능했고..
결국 1을 선택한채로 과제를 계속 진행을 하고자 했고 그와중에 오류가 쌓여 또 충돌이 난 것이었다.
해결방법은 결국 db지우기로 귀결..ㅠㅠ
그리고 나의 짧고 소중한 코드를 리뷰해주셨다
피드백을 받아 수정한 코드
user = models.ForeignKey(UserModel, on_delete=models.RESTRICT, null=True, blank=True)
>> ForeignKey는 user모델을 통째로 가져오는 것이라서 따로 이름을 지정해주거나 on_update를 넣어줄 필요가 없다.
>> 이게 곧 유저 모델이니까 admin_name보다는 보다 직관적인 이름인 user 로 변수이름을 변경
>> 필요한 기능 자체는 views.py 에서 def으로 기능을 정의할때 넣어주면 된다.
자세한 설명 덕에 ForeignKey의 기능과 모델 참조에 대한 이해도가 높아진 것 같다:)
+++ null & blank에 대한 공부.. 어렵지만 따온 설명을 첨부한다;
장고 모델 API는 null 과 blank 라는 2가지 비슷한 옵션을 제공한다.
* Null : DB와 관련되어 있다. (database-related) 주어진 데이터베이스 컬럼이 null 값을 가질 것인지 아닌지를 정의한다.
* Blank : 유효성과 관련되어 있다. (validation-related) form.is_valid()가 호출될 때 폼 유효성 검사에 사용된다.
개발자들이 가장 실수하는 부분은 CharField, TextField와 같은 문자열 기반 필드에 null=True를 정의하는 것이다.
=> 문자열 기반 필드에는 null=True를 하면 안되는군
이 같은 실수를 피해야한다. 그렇지 않으면 “데이터 없음”에 대해 두 가지 값, 즉 None 과 빈 문자열 을 갖게된다.
“데이터 없음”에 대해 두 가지 값을 갖는 것은 중복이다.
그리고 Null이 아닌 빈 문자열을 사용하는 것이 장고 컨벤션이다.
이 문서를 기반으로 새로이 추가하고자했던 코드를 해석해보았다..
user = models.ForeignKey(UserModel, on_delete=models.RESTRICT, null=True, blank=True)
내가 사용하고자하는 건 null = True 왜냐면 이미 db에 들어있는걸 가져올 거니까 여기선 따로 저장할게 없다..
Blank =true인 이유는 사용자가 required해야 요청되는 값이 아니기때문에 True를 넣는 것
이라고 어제 밤에 써뒀는데 다시 보니까 이해가 안된다.. 흑흑
그래서 결국 간결한 설명을 받고 이해했다!
Product 모델을 저장할때 해당 변수에 값이 안들어있어도 되는지에 대해 쓰는 것이었다!!
기본적으로 필드 옵션을 넣지 않으면 Not null이 기본값으로 정해진다.
null=True, blank=True : 값이비어도 괜찮다는 의미!
정보를 입력할 칸이 비어 오류날 수 있는 부분을 줄이기 위해 쓰는 것이다..
product모델 같은 경우, 이름, 정보 가격 등은 필수로 들어가야하는 부분이기 때문에 이 옵션을 넣지 않는다
옵션 null의 default값은 notnull상태이기때문에 무조건 정보가 들어가야한다고 되어있는것임.!
name = models.CharField(max_length=150)
description = models.CharField(max_length=150)
price = models.IntegerField(default=0)
Today'sError 03
오류 난 코드..
def __str__(self):
return self.code
def save():
pass
#pass를 넣어 오류방지, 프로그램을 돌리고자했으나 크나큰 실수였다!
기본적으로 주어진 예제 코드에 code를 리턴하는 __str__ 스페셜메서드가 있었다.
이건 무슨 코드일까, 하며 필요한 순간이 오겠지라는생각에 그대로 두었는데
product모델을 다 만들고 저장하며 오류가 생긴다.
첫 번째로, 이 부분이 문제인 건 알고 있었지만 어떻게 해결해야할지를 모르는게 가장 큰 문제였다;;
역시나 메서드에 대한 이해부족으로 인해 벌어진 일..ㅠㅠ... 공부하자 공부.
__str__은 문자열을 리턴해주는 스페셜 메서드로, 반환값을 문자열로 넣어주어야 한다.
그리고 아래와 같이 여러 반환값을 넣으면 반환값이 튜플형태가 되기 때문에 오류가 나게 된다! (동기님 감사합니다,,)
def __str__(self):
return self.code, self.name, self.size, self.price
그래서 self.name 을 반환하도록 바꾸어주었다.
그리고 두 번째. 이 함수가 있는 것 자체는 프로그램이 실행되는데에 있어 문제가 되지는 않는다.
하지만 pass 가 들어감으로써 장고 내장함수인 save()의 모든 기능을 시원하게 pass해버리는 기능을 만들어버린 것..
def save():
pass
그러니 veiws.py의 저장 기능을 아무리 들여다봐도 문제가 해결되지 않은 것이었다........
뼈가 아프니까 앞으로는 아무데나 pass 적지 말자..
def save():
raise NotImplementedError('Not Implemented')
이렇게 구현이 안됐다고 표시해두기로 하자
Today'sError 04 미해결
class ProductAdmin(admin.ModelAdmin):
list_display = ('code', 'name', 'size', 'crearted_at')
아직 해결하지 못한 오류,,,
이걸 설정하면 admin의 product model 페이지에서 입력한 상세 내용을 볼 수 있다고 들었는데,
어째선지 적용되지 않는다! 왜안돼!
느낀점:
역시 질문하길 잘했다..!
혼자 끙끙대다가 날려먹은 이번주가 아쉽고ㅠㅠ
앞으로는 찾아보다 너무 많은 시간이 걸리면 공유하고, 질문드리고 하는 자세를 가져야겠다...
Django 의 형식에 익숙해지기위해 form없이 만들어보고 있는데,
유예가 생겼으니 주말동안 남은 강의랑... 기능 구현 및 form기능에 대해 좀더 파볼 것. 끝