작성
·
771
0
안녕하세요, 강사님.
제가 개인적으로 진행하고 있는 프로젝트의 models.py를 일부 수정하고 migration 이후 migrate를 진행할 때 오류가 나고 있어 질문드립니다.
위의 코드들은 models.py인데, 제가 여기서 Customer 모델 클래스의 user와 name 필드의 속성을 수정했습니다. 기존에는 null과 blank가 True로 되어있어 False로 수정을 하고 migration을 진행했는데, name과 user 필드 모두 non-nullable로 바꾸는데 default를 주지 않았다고 나왔습니다.
그래서,
name = models.CharField(max_length=100, null=False, default='미지정')
user = models.OneToOneField(User, null=False, blank=False, on_delete=models.CASCADE, default='미지정')
이렇게 수정하고 migrations를 진행하니까 넘어가고 migrate를 진행하니까
(env) kimsangbaek@gimsangbaeg-ui-MacBookAir impactmuseum % python manage.py makemigrations posts
Migrations for 'posts':
posts/migrations/0004_auto_20220206_0259.py
- Alter field name on customer
- Alter field user on customer
(env) kimsangbaek@gimsangbaeg-ui-MacBookAir impactmuseum % python manage.py migrate posts
Operations to perform:
Apply all migrations: posts
Running migrations:
Applying posts.0003_auto_20220206_0249...Traceback (most recent call last):
File "/Users/kimsangbaek/Desktop/likelion/env/lib/python3.9/site-packages/django/db/models/fields/__init__.py", line 1823, in get_prep_value
return int(value)
ValueError: invalid literal for int() with base 10: '미지정'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/kimsangbaek/Desktop/likelion/env/impactmuseum/manage.py", line 22, in <module>
main()
File "/Users/kimsangbaek/Desktop/likelion/env/impactmuseum/manage.py", line 18, in main
execute_from_command_line(sys.argv)
File "/Users/kimsangbaek/Desktop/likelion/env/lib/python3.9/site-packages/django/core/management/__init__.py", line 419, in execute_from_command_line
utility.execute()
File "/Users/kimsangbaek/Desktop/likelion/env/lib/python3.9/site-packages/django/core/management/__init__.py", line 413, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/Users/kimsangbaek/Desktop/likelion/env/lib/python3.9/site-packages/django/core/management/base.py", line 354, in run_from_argv
self.execute(*args, **cmd_options)
File "/Users/kimsangbaek/Desktop/likelion/env/lib/python3.9/site-packages/django/core/management/base.py", line 398, in execute
output = self.handle(*args, **options)
File "/Users/kimsangbaek/Desktop/likelion/env/lib/python3.9/site-packages/django/core/management/base.py", line 89, in wrapped
res = handle_func(*args, **kwargs)
File "/Users/kimsangbaek/Desktop/likelion/env/lib/python3.9/site-packages/django/core/management/commands/migrate.py", line 244, in handle
post_migrate_state = executor.migrate(
File "/Users/kimsangbaek/Desktop/likelion/env/lib/python3.9/site-packages/django/db/migrations/executor.py", line 117, in migrate
state = self._migrate_all_forwards(state, plan, full_plan, fake=fake, fake_initial=fake_initial)
File "/Users/kimsangbaek/Desktop/likelion/env/lib/python3.9/site-packages/django/db/migrations/executor.py", line 147, in _migrate_all_forwards
state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial)
File "/Users/kimsangbaek/Desktop/likelion/env/lib/python3.9/site-packages/django/db/migrations/executor.py", line 227, in apply_migration
state = migration.apply(state, schema_editor)
File "/Users/kimsangbaek/Desktop/likelion/env/lib/python3.9/site-packages/django/db/migrations/migration.py", line 126, in apply
operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
File "/Users/kimsangbaek/Desktop/likelion/env/lib/python3.9/site-packages/django/db/migrations/operations/fields.py", line 244, in database_forwards
schema_editor.alter_field(from_model, from_field, to_field)
File "/Users/kimsangbaek/Desktop/likelion/env/lib/python3.9/site-packages/django/db/backends/sqlite3/schema.py", line 140, in alter_field
super().alter_field(model, old_field, new_field, strict=strict)
File "/Users/kimsangbaek/Desktop/likelion/env/lib/python3.9/site-packages/django/db/backends/base/schema.py", line 608, in alter_field
self._alter_field(model, old_field, new_field, old_type, new_type,
File "/Users/kimsangbaek/Desktop/likelion/env/lib/python3.9/site-packages/django/db/backends/sqlite3/schema.py", line 362, in _alter_field
self._remake_table(model, alter_field=(old_field, new_field))
File "/Users/kimsangbaek/Desktop/likelion/env/lib/python3.9/site-packages/django/db/backends/sqlite3/schema.py", line 202, in _remake_table
'default': self.quote_value(self.effective_default(new_field))
File "/Users/kimsangbaek/Desktop/likelion/env/lib/python3.9/site-packages/django/db/backends/base/schema.py", line 324, in effective_default
return field.get_db_prep_save(self._effective_default(field), self.connection)
File "/Users/kimsangbaek/Desktop/likelion/env/lib/python3.9/site-packages/django/db/models/fields/related.py", line 971, in get_db_prep_save
return self.target_field.get_db_prep_save(value, connection=connection)
File "/Users/kimsangbaek/Desktop/likelion/env/lib/python3.9/site-packages/django/db/models/fields/__init__.py", line 842, in get_db_prep_save
return self.get_db_prep_value(value, connection=connection, prepared=False)
File "/Users/kimsangbaek/Desktop/likelion/env/lib/python3.9/site-packages/django/db/models/fields/__init__.py", line 2486, in get_db_prep_value
value = self.get_prep_value(value)
File "/Users/kimsangbaek/Desktop/likelion/env/lib/python3.9/site-packages/django/db/models/fields/__init__.py", line 1825, in get_prep_value
raise e.__class__(
ValueError: Field 'id' expected a number but got '미지정'.
다음과 같이 id 필드에 숫자가 필요하다고 나오더라구요.. 그래서 최종적으로 위의 코드와 같이 user와 name의 default=0 이렇게 설정하고 다시 migration, migrate를 진행해도 위와 같이 오류가 해결되지 않고 있습니다.
구글링 해봤을 때 아예 migrations 파일을 지우라고 하는 경우도 있던데 확실하지가 않아 이렇게 질문을 드리게 되었습니다. 천천히 답변주시면 감사하겠습니다!
답변 2
2
안녕하세요.
장고에서 지원하는 관계필드(models.ForengiKey, models.OneToOneField, models.ManyToManyField)들은 데이터베이스에서 기본키(primary key)/외래키(foreign key) 관계로서 표현이 됩니다.
장고 모델에서는 필드 정의 시에 primary_key=True 속성 지정을 통해 기본키 필드를 지정하지 않는 한, 디폴트로 id = models.AutoField 로서 정의가 됩니다. 이는 1부터 1씩 자동증가(auto increment)하는 필드입니다.
그러니, 관계필드에 대해서 값을 지정하실 때에는 1 이상의 자연수를 지정하셔야 하며, 지정된 값은 외래키로서 활용되기에, 외래키에 해당되는 Row가 필히 데이터베이스에 테이블에 있어야 합니다.
Customer 모델에 user 필드를 추가했을 때 값으로 0을 지정했다면, User 모델에 필히 pk가 0인 Row가 있어야 합니다. 그렇지 않다면, 외래키 제약사항에 걸려 마이그레이션에 실패하게 됩니다. pk는 1부터 시작하기에 절대 pk=0인 데이터는 존재할 수 없습니다.
Customer 모델에 user 필드를 추가했을 때 값으로 "미지정" 문자열을 지정했다면, User 모델의 pk은 자연수이기에 자연수 변환을 시도하게 되는 데, "미지정" 문자열은 int("미지정") 로직에서 ValueError가 발생하게 되어, 마이그레이션에 실패하게 됩니다.
모델 필드의 디폴트 값이나 makemigrations 시의 값 지정에서는 그 타입에 맞게 적절히 값을 잘 지정해주셔야 합니다. 마이그레이션 툴은 손쉬운 마이그레이션을 도와주지만, 어떤 값을 지정하는 지에 대해서는 개발자가 필드타입 및 데이터베이스 데이터 상황을 잘 파악하여 적절히 지정해주셔야만 합니다.
아마 아래의 모델 필드 정의를 하신 후에, makemigrations을 하셨기에 관계필드에 "미지정" 값을 지정하는 마이그레이션 파일이 생성이 되었을 것입니다. 그러니 migrate 시에 잘못된 "외래키" 값으로 인해 마이그레이션이 실패하게 되셨을 것이구요.
user = models.OneToOneField(User, null=False, blank=False, on_delete=models.CASCADE, default='미지정')
user 필드의 디폴트 값을 0으로 변경하셔서, 다시 makemigrations을 하셔서 새로운 마이그레이션 파일을 생성하셨더라도, 앞서 생성된 "미지정" 값이 지정된 마이그레이션 파일이 있기에 - 그럼 현재 2개의 마이그레이션 파일이 생성된 상황 - migrate 명령이 실패하게 됩니다.
python manage.py showmigrations 명령을 통해 마이그레이션 적용 현황을 확인하실 수 있습니다. 미적용된 마이그레이션 파일은 삭제하시고, 모델 내역은 그대로 있으니 다시 makemigrations 명령을 수행해보실 수 있습니다. 절대 적용된 마이그레이션은 삭제하시면 안 됩니다.
1
강사님 덕분에 오류 해결하고 정상적으로 migrations - migrate 완료했습니다, 정말 감사합니다!
단순히 포기하지 않고 구글링 하면 해결할 수 있을것이라 생각했는데, django의 기본원리와 데이터베이스 구성을 먼저 아는 것이 중요하다는 것을 느낄 수 있었습니다ㅎㅎ
강사님 강의 듣고 제가 맘대로 만들고 있는 프로젝트에 연습을 하고 있었는데, 얼른 데이터베이스 강의를 다 듣고 다시 해봐야겠습니다.
정말 감사합니다:)