django 외래키 질문입니다.

조회수 433회

django 외래키를 통해 파일을 저장하려고 합니다.

일단 view.py를 통해 들어온 url에서 파일을 뽑아내어

파일을 외래키에 저장하는 과정입니다.

#models.py

class UploadModel(models.Model):
    uploadedFiles = models.FileField(blank=True,)

    def __str__(self):
        return self.uploadedFiles.name


class UploadURLmodel(models.Model):
    uploadURL = models.TextField(blank=False)
    # 위의 UploadModel과 연결되어 있는 외래키
    fileFromURL = models.ForeignKey(UploadModel, on_delete=models.CASCADE, blank=True, null=True)

    def save(self, *args, **kwargs):
        # 파일 url view로 부터 받기
        if self.uploadURL and not self.fileFromURL:
            file_url = self.uploadURL
            for_file = UploadModel.objects.create() # 위 UploadModel을 
                                                    # 불러오는 부분

            file_name = file_url.split('/')[-1]

            response = get(file_url) # url에서 파일을 뽑는 과정
            binary_data = response.content
            temp_file = BytesIO()
            temp_file.write(binary_data)
            temp_file.seek(0)
            # 외래키에 어떻게 data를 집어 넣을지 모르겠어서 외래키가 가리키는 
            # UploadModel인스턴스에 파일을 집어 넣고 외래키에 대입하였습니다.
            for_file.uploadedFiles = temp_file
            for_file.save()
            self.fileFromURL = for_file # 외래키에 인스턴스 대입

            print("wow")
            print(type(self.fileFromURL))

            self.fileFromURL.save(
                file_name,
                File(temp_file) # 이곳에서 오류가 발생합니다. 오류내용은 아래에 있습니다.
            )
        super(UploadURLmodel, self).save()
        return self.fileFromURL.name

    def __str__(self):
        return self.fileFromURL.name
File "/Users/minhyeokjang/Desktop/github/fileConverter/fileconverter/models.py", line 43, in save
    File(temp_file)
  File "/Users/minhyeokjang/venv/lib/python3.7/site-packages/django/db/models/base.py", line 746, in save
    force_update=force_update, update_fields=update_fields)
  File "/Users/minhyeokjang/venv/lib/python3.7/site-packages/django/db/models/base.py", line 784, in save_base
    force_update, using, update_fields,
  File "/Users/minhyeokjang/venv/lib/python3.7/site-packages/django/db/models/base.py", line 887, in _save_table
    results = self._do_insert(cls._base_manager, using, fields, returning_fields, raw)
  File "/Users/minhyeokjang/venv/lib/python3.7/site-packages/django/db/models/base.py", line 926, in _do_insert
    using=using, raw=raw,
  File "/Users/minhyeokjang/venv/lib/python3.7/site-packages/django/db/models/manager.py", line 82, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/Users/minhyeokjang/venv/lib/python3.7/site-packages/django/db/models/query.py", line 1204, in _insert
    return query.get_compiler(using=using).execute_sql(returning_fields)
  File "/Users/minhyeokjang/venv/lib/python3.7/site-packages/django/db/models/sql/compiler.py", line 1390, in execute_sql
    for sql, params in self.as_sql():
  File "/Users/minhyeokjang/venv/lib/python3.7/site-packages/django/db/models/sql/compiler.py", line 1335, in as_sql
    for obj in self.query.objs
  File "/Users/minhyeokjang/venv/lib/python3.7/site-packages/django/db/models/sql/compiler.py", line 1335, in <listcomp>
    for obj in self.query.objs
  File "/Users/minhyeokjang/venv/lib/python3.7/site-packages/django/db/models/sql/compiler.py", line 1334, in <listcomp>
    [self.prepare_value(field, self.pre_save_val(field, obj)) for field in fields]
  File "/Users/minhyeokjang/venv/lib/python3.7/site-packages/django/db/models/sql/compiler.py", line 1285, in pre_save_val
    return field.pre_save(obj, add=True)
  File "/Users/minhyeokjang/venv/lib/python3.7/site-packages/django/db/models/fields/files.py", line 286, in pre_save
    if file and not file._committed:
AttributeError: '_io.BytesIO' object has no attribute '_committed'

오류내용 입니다.

어떻게 하면 url에서 가져온 파일을 외래키에 저장할 수 있을까요?

1 답변

  • 좋아요

    2

    싫어요
    채택 취소하기

    일단 주신 질문 자체에 대해서는 제가 파이썬에 무지해서 답을 못 드릴 거 같고 오히려 역으로 질문드리고 싶은 것은 하나 있습니다. 왜 "파일"을 DB에 (심지어 인덱싱될 값으로) 저장하려고 하시나요?

    그간의 질문들을 보건대 그건 아마도 움짤 생성기를 만들어야 하기 때문일 거 같습니다만... "움짤 생성기"라는 게 만약

    1. 사용자는, 동영상 URL이나 파일을 제공한다.
    2. 서버는, 동영상 파일을 일단 확보한다. URL이 제공되었으면 그 URL로부터 파일을 획득한다.
    3. 서버는, 그 파일을 가지고 GIF 움짤을 찐다.
    4. 서버는, 그 GIF 파일을 사용자에게 반환한다.
    5. 사용자는, 그 GIF 파일을 다운받아 사용한다.

    의 일련을 제공하는 애플리케이션이라면... 그런 건 애초에 DB가 필요 없기 때문이지요.

    카드 안 되는 구식 자판기를 생각하시면 좋을것 같네요. 자판기는 사용자 정보를 아무것도 저장하지 않아요. 그냥 들어온 돈 확인한 다음 별문제 없으면 달라는 음료를 뽑아줄 뿐이니까요. (항간에 나와 있는 "유튜브 다운로더"들이 이렇게 동작합니다.)


    이쯤에서 '어.. 아닌데.. DB 필요한데..'라고 생각하신다면 그건 아마도 구현 중이신 애플리케이션의 실제 시나리오가 대충

    1. 사용자는, 회원가입을 한다.
    2. 로그인한 사용자가, 동영상 URL이나 파일을 제공한다.
    3. (생략)
    4. 서버는, 그 GIF 파일을 나중에 사용자가 언제든지 받아갈 수 있도록 어딘가에 저장해 놓는다.
    5. 사용자는, 그 GIF 파일을 다운받아 사용한다.

    와 같을 것이기 때문일 겁니다. 그런데 실은, 이 경우에도 DB에 파일을 저장할 필요는 전혀 없어요. 왜냐하면 잘 보세요, 이 시나리오는 세탁소 시나리오와 흡사하거든요.

    1. 손님이 세탁소에 들어옵니다.
    2. 세탁소는 "처음 오셨어요?"라고 물어봅니다. 처음 왔다면 일단 전화번호부터 레지에 입력하고, 아니면 누구인지 확인합니다.
    3. 세탁소는 세탁물을 받아 확인합니다.
    4. 세탁소는 세탁물 하나하나에 별 의미 없는 난수가 붙은 태그를 발급합니다.
    5. 세탁소는 다시 레지를 켜서 그 난수 하나하나를 각각 그 손님에게 할당합니다.
    6. 세탁소는 "며칠날 다시 오세요"라고 알려준 다음 그 세탁물들을 통째로 세탁기에 넣고 돌립니다.
    7. 세탁기가 태그 붙은 세탁물들을 힘차게 빨래합니다.
    8. 손님이 다시 세탁소에 찾아옵니다.
    9. 세탁소는, 그 손님에게 등록해 놓은 태그 난수들을 확인한 다음, 그 난수의 그 태그가 붙은 그 빨래들만 손님에게 돌려줍니다.

    눈치채셨나요? 세탁소 주인은 빨랫감들을 들고 있지 않아요. 세탁소 주인이 레지를 통해 갖고 있는 것은 오직 태그뿐이지요. 어떤 세탁소 주인도 "아.. 이 손님은 총 3가지 물품을 맡겼는데 하나는 흰색 원단을 무슨 기법으로 마감해서 처리한 무슨 코트이고..."를 기억하지 않는단 말입니다. 빨랫감들을 레지에 밀어넣는 일은 더더욱 없구요.


    정리하면, 움짤 생성기 시나리오에서 저장해두고 계셔야 할 정보가 있다면, 그건 원본 영상에 고유하게 할당 가능한 정보일 겁니다. "그 정보만 있으면 그 영상/gif를 확보할 수 있는" 그런 세탁물 태그 같은 정보 말입니다. 그 영상/gif를 저장해 둔 로컬 경로를 쓰면 가장 편리하겠지요. 그리고 그런 일반적인 경우에 있어서 외래키는 질문자님이 예상하시는 그대로 잘 동작할 겁니다.

    그리고 그 움짤 자체는 그 '태그 정보'로 특정 스토리지에서 찾아야 할 대상이지, DB에 저장할 정보가 아닙니다. 애초에 response.content 결과값 전체를 DB에 저장하는 것은 보안적으로도 나쁜 아이디어입니다. 그 값을 SELECT했더니 *; DROP TABLE;이라는게 나오면 어떡하시려구요. (과장해서 하는 말이 아닙니다.)

    이제 다시 처음으로 돌아오겠습니다. 왜 "파일"을 DB에 (심지어 인덱싱될 값으로) 저장하려고 하시죠? 제가 뭔가 오해했거나 놓치고 있는 게 있다면 알려주시면 감사하겠습니다.

    • 제가 지금 까지 static file과 db의 차이점을 혼동하고 있었던것 같습니다. 개념을 이상하게 혼동 하고 있어서 지금까지 매우 비효율적인 싸움을 저 혼자 했던것 같습니다.. ㅜ 큰 깨달음을 주신것 같아서 정말 감사 드린다는 말 드리고 싶습니다. poffsle 2020.3.18 11:35
    • 이걸로 해결이라면 다행입니다. 엽토군 2020.3.18 11:39
    • django 파일 시스템에 대해서 찾아 보았는데 model에서 filefield나 imagefield로 비디오나 이미지를 저장하면 db에 직접 파일이 쓰이는 것이 아니라 db에는 char형식으로 파일 경로만 쓰이고 실제 파일은 설정한 경로에 저장이 됩니다. 그래서 aws경우에 rds가 아닌 s3에 저장됩니다. https://www.caktusgroup.com/blog/2017/08/28/advanced-django-file-handling/ poffsle 2020.3.18 16:07
    • 혹시나 오해가 있을까 싶어 글 남깁니다. poffsle 2020.3.18 16:08
    • 👍 엽토군 2020.3.18 16:19

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)