작성
·
194
0
mysql 에 테이블을 기존에 만들어 둔게 있습니다.
다른 서비스가 데이터를 쌓아 놓는 테이블인데 여기를 ORM으로 조회를 한번 해보고 싶습니다.
로그성 테이블이라 pk가 없습니다.
python manage.py inspectdb 로 모델 코드를 만들어 내긴 했습니다.
python shell로 조회를 하려고 하는데 id 필드를 찾으려는 시도를 계속 합니다.
기존에 만들어진 DB 스키마를 ORM으로 사용려고 만든 것이 inspectdb 일것 같은데
장고 ORM 구조가 PK를 필수로 가져야 하는 구조인지 궁금합니다.
(구글링 해보면 PK가 필수라는 이야기도 있고, CHATGPT에게 물어보면 Meta클래스에 managed가 False이면 괜찮다는 답변이 나오네요)
inspectdb로 만들어진 코드에는 Meta 클래스가 아래와 같이 있습니다.
class MacLog(models.Model):
timestamp = models.DateTimeField()
sw_ip = models.CharField(max_length=20)
mac = models.CharField(max_length=255)
port = models.CharField(max_length=20)
class Meta:
managed = False
db_table = 'mac_log'
다음은 에러가 나는 내용 입니다.
>>> from django.db.models import QuerySet
>>> from maccol.models import MacLog
>>>
>>> qs = QuerySet(MacLog)
>>> for item in qs:
... print(item)
...
None
Execution time: 0.019902s [Database: default]
Traceback (most recent call last):
File "/Users/dcu/workspace/maccol/venv/lib/python3.11/site-packages/django/db/backends/utils.py", line 89, in _execute
return self.cursor.execute(sql, params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/dcu/workspace/maccol/venv/lib/python3.11/site-packages/django/db/backends/mysql/base.py", line 75, in execute
return self.cursor.execute(query, args)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/dcu/workspace/maccol/venv/lib/python3.11/site-packages/MySQLdb/cursors.py", line 179, in execute
res = self._query(mogrified_query)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/dcu/workspace/maccol/venv/lib/python3.11/site-packages/MySQLdb/cursors.py", line 330, in _query
db.query(q)
File "/Users/dcu/workspace/maccol/venv/lib/python3.11/site-packages/MySQLdb/connections.py", line 261, in query
_mysql.connection.query(self, query)
MySQLdb.OperationalError: (1054, "Unknown column 'mac_log.id' in 'field list'")
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Users/dcu/workspace/maccol/venv/lib/python3.11/site-packages/django/db/models/query.py", line 398, in __iter__
self._fetch_all()
File "/Users/dcu/workspace/maccol/venv/lib/python3.11/site-packages/django/db/models/query.py", line 1881, in _fetch_all
self._result_cache = list(self._iterable_class(self))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/dcu/workspace/maccol/venv/lib/python3.11/site-packages/django/db/models/query.py", line 91, in __iter__
results = compiler.execute_sql(
^^^^^^^^^^^^^^^^^^^^^
File "/Users/dcu/workspace/maccol/venv/lib/python3.11/site-packages/django/db/models/sql/compiler.py", line 1562, in execute_sql
cursor.execute(sql, params)
File "/Users/dcu/workspace/maccol/venv/lib/python3.11/site-packages/django_extensions/management/debug_cursor.py", line 49, in execute
return utils.CursorWrapper.execute(self, sql, params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/dcu/workspace/maccol/venv/lib/python3.11/site-packages/django/db/backends/utils.py", line 67, in execute
return self._execute_with_wrappers(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/dcu/workspace/maccol/venv/lib/python3.11/site-packages/django/db/backends/utils.py", line 80, in _execute_with_wrappers
return executor(sql, params, many, context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/dcu/workspace/maccol/venv/lib/python3.11/site-packages/django/db/backends/utils.py", line 84, in _execute
with self.db.wrap_database_errors:
File "/Users/dcu/workspace/maccol/venv/lib/python3.11/site-packages/django/db/utils.py", line 91, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/Users/dcu/workspace/maccol/venv/lib/python3.11/site-packages/django/db/backends/utils.py", line 89, in _execute
return self.cursor.execute(sql, params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/dcu/workspace/maccol/venv/lib/python3.11/site-packages/django/db/backends/mysql/base.py", line 75, in execute
return self.cursor.execute(query, args)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/dcu/workspace/maccol/venv/lib/python3.11/site-packages/MySQLdb/cursors.py", line 179, in execute
res = self._query(mogrified_query)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/dcu/workspace/maccol/venv/lib/python3.11/site-packages/MySQLdb/cursors.py", line 330, in _query
db.query(q)
File "/Users/dcu/workspace/maccol/venv/lib/python3.11/site-packages/MySQLdb/connections.py", line 261, in query
_mysql.connection.query(self, query)
django.db.utils.OperationalError: (1054, "Unknown column 'mac_log.id' in 'field list'")
답변 3
0
혹은 timestamp 필드에 primary_key=True 설정을 추가하시어, MacLog 모델 클래스에서는 timestamp 필드를 MacLog 모델에서는 기본키로서 인지토록 하실 수도 있습니다. 그럼 별도로 쿼리셋을 변경하실 필요는 없게 되겠죠.
Meta.managed = False 설정에서 장고 모델 클래스 입장에서 기본키로서 활용하라는 것일 뿐, 해당 키가 반드시 데이터베이스에서 기본키여야하는 것은 아닙니다. 모델 클래스를 통해 생성되는 SQL 쿼리가 해당 데이터베이스에서 호환되어 동작토록만 맞춰주시면, 어느 정도의 변화를 주실 수 있습니다.
단, timestamp를 통한 MacLog 레코드 조회를 수행하신다면, timestamp 필드값이 유일하지 않을 경우 쿼리셋 코드에 따라 Multiple Object Returned 예외가 발생할 수 있습니다.
0
안녕하세요.
장고 모델에서는 기본 키는 단일 키로서 대개의 경우 요구되어집니다. 장고 모델 클래스에서는 primary_key=True 속성의 모델 필드가 없다면, 디폴트로 id 이름의 모델 필드를 자동으로 추가하여 기본키 필드로 사용합니다. Meta.managed = False 설정은 makemigrations 명령 시에 마이그레이션 대상여부를 판단하는 설정일 뿐, 위 기본키 설정과는 무관합니다.
장고 모델로부터 자동으로 생성되는 쿼리셋에서는 기본키 필드까지 모두 조회를 시도합니다. 그러니 Unknown column 'mac_log.id' 오류가 발생하는 것이구요.
즉 QuerySet(MacLog) 는 id 필드를 포함한 timestamp, sw_ip, mac, port 필드까지 모두 select 조회를 하려 시도합니다. id 필드를 조회하지 않도록 하고 다른 4개 필드만 조회하려 하신다면 다음과 같이 쿼리셋의 values 메서드를 활용하시면 됩니다.
qs = QuerySet(MacLog).values("timetstamp", "sw_ip", "mac", "port")
대신 각 레코드의 반환값은 사전(dict)이 됩니다.
파이썬 코드 내에서는 아래처럼 key 참조를 하셔야 하구요.
for log in qs: print(log["timestamp"])
장고 템플릿에서는 사전 key 도 속성처럼 접근하니까, 아래와 같이 쓰실 수 있습니다.
log.timestamp
MacLog 모델에 커스텀 모델 매니저를 등록해서, 기본 쿼리셋에 values가 적용토록 수정하실 수도 있습니다.
살펴보시고, 댓글 남겨주세요.
화이팅입니다. :-)
0
안녕하세요, 인프런 AI 인턴입니다.
jungjw님의 질문과 유사한 문제를 해결한 기존 답변을 찾았습니다. 해당 문제는 Django에서 기존에 만들어진 데이터베이스의 테이블을 ORM으로 가져오고 사용하려 할 때 발생하는 문제로 보입니다.
Django ORM은 기본적으로 모델의 id
필드를 기본 키(PK)로 사용하려 합니다. 하지만 inspectdb
를 사용하여 생성된 모델이 PK를 지정하지 않았고, 기존 데이터베이스 테이블에 id
필드가 없을 경우 Django는 id
필드를 찾으려고 하다가 에러를 발생시킵니다.
해결 방법:
- 방법 1: 기존 테이블에 PK 역할을 할 수 있는 필드가 있다면, 해당 필드에 primary_key=True
옵션을 추가하여 명시해줍니다.
- 방법 2: 만약 PK로 사용할 수 있는 필드가 없고, Django가 자동으로 id
필드를 추가하지 못하게 하려면, 모델 내의 Meta
클래스에 managed = False
를 설정하고 있기 때문에, 데이터베이스 테이블에 id
필드를 수동으로 추가하는 것을 고려해볼 수 있습니다.
jungjw님이 제공한 모델 코드에서는 이미 managed = False
와 함께 커스텀 테이블 이름을 지정하고 있습니다. 이 경우, Django ORM을 사용하여 쿼리를 수행할 때 기본 키가 없어 에러가 발생하는 것으로 보입니다.
예전에 비슷한 상황에 대해 답변한 내용이 있는데, 아쉽게도 직접적인 해결책을 제시하지는 못했습니다. 다만, 이 경우 Django 문서에서 제안하는 Inspectdb 사용법을 참고하여 해결할 수 있을 것 같습니다.
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.
알려주신 방법으로 조회를 해봤습니다. 정상적으로 잘 됩니다.
SELECT절에 id 필드가 들어가지 못하게 명시적으로 제한하면 되는군요 ^^
다른 서비스가 사용하는 DB의 데이터를 읽어 오는 것이라 스키마 변경을 할 수가 없었는데 알려주신 방법으로 해결할 수 있게 되었습니다.
감사합니다 ^^