My Profile Photo

DongChanS's blog


수학과 학생의 개발일지


인스타 클론코딩 1, Posts앱 (1) Media Files

1) Posts App

포스트와 관련된 기능들을 구현할 어플리케이션

1-1. OverView

  1. Post 모델 작성

    • 1:N relation - 유저 <-> Post
    • M:N relation - 좋아요 클릭한 유저 <-> Post
  2. Media file을 업로드하기 위한 장치들 마련

    • ImageField를 통해 Image의 url을 저장할 column 만들기

    • 사용자가 제공한 파일(binary code)를 인코딩하는 작업 수행

      enctype = “multipart/form-data”

    • 인코딩한 파일을 서버에 저장하기

      • MEDIA_ROOT, MEDIA_URL
      • request.FILES
    • 저장된 파일을 사용자가 조회할 수 있게 url 안내하기

      • static

1-2. Post Model

  1. Post 모델

    Column Description
    Content 내용, charfield
    Image 이미지 url을 정의, imagefield
    User 작성자, Foreignkey
    Like_users 좋아요를 클릭한 유저들, ManyToManyField
       
       
    from django.db import models
    from django.conf import settings
    from django.contrib.auth import get_user_model
       
    # Create your models here.
    class Post(models.Model):
        content = models.CharField(max_length=150)
        image = models.ImageField(blank=True)
        user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
        like_users = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="like_posts", blank=True)
    

    좋아요기능과 작성자<->포스트 기능을 위해서는 1:N, M:N relation이 필요한데 다음 포스트에서 설명하도록 하겠습니다. 일단 이번에는 이미지 업로드 기능만 구현하도록 하겠습니다.

1-3. Image Upload

  1. 이미지를 관리할 Column

    ImageField(upload_to=None, height_field=None, width_field=None, max_length=100, **options)

    테이블에 Image 그자체를 저장하지는 않고, Image가 저장된 곳의 url을 저장하는 Column

    • Pillow 라이브러리를 필요로 함.

      Python Imaging Library

    • 매개변수들

      1. upload_to : 어디에 저장될지를 정해줌.

        class MyModel(models.Model):
            # file will be uploaded to MEDIA_ROOT/uploads
            upload = models.FileField(upload_to='uploads/')
            # or...
            # file will be saved to MEDIA_ROOT/uploads/2015/01/30
            upload = models.FileField(upload_to='uploads/%Y/%d/')
        
      2. Image Processing을 위하여 height와 width를 정의하기 위한 field도 필요하지만,

        나중에 다루도록 하겠습니다.

  2. 파일이 전송되는 방식

    • 파일을 업로드
      • 업로드된 파일을 인코딩
    • 특정 주소에 파일을 저장함
    • 디비에는 저장된 주소를 저장함.
  3. 사용자가 보낸 파일을 인코딩하는 작업을 수행

    request.FILES

    HttpRequest.FILES

    A dictionary-like object containing all uploaded files. Each key in FILES is the name from the <input type="file" name="">. Each value in FILES is an UploadedFile.

    See Managing files for more information.

    FILES will only contain data if the request method was POST and the<form> that posted to the request had enctype="multipart/form-data". Otherwise, FILES will be a blank dictionary-like object.

    아무튼 POST 메서드로 파일을 받을거면, 인코딩을 선언해줘야한다고 합니다.

       
    <form method="POST" enctype="multipart/form-data">
        {% csrf_token %}
        {{form.as_p}} <!-- ModelForm을 통하여 form을 제작 -->
        <button type="submit">
            제출
        </button>
    </form>
       
    
  4. 인코딩된 파일을 서버에 저장하기

    이 부분은 Django reference에 잘 설명되어 있습니다.

    Using a FileField or an ImageField (see below) in a model takes a few steps:

    1. In your settings file, you’ll need to define MEDIA_ROOT as the full path to a directory where you’d like Django to store uploaded files. (For performance, these files are not stored in the database.) DefineMEDIA_URL as the base public URL of that directory. Make sure that this directory is writable by the Web server’s user account.
    2. Add the FileField or ImageField to your model, defining the upload_to option to specify a subdirectory of MEDIA_ROOT to use for uploaded files.
    3. All that will be stored in your database is a path to the file (relative to MEDIA_ROOT). You’ll most likely want to use the convenience urlattribute provided by Django. For example, if your ImageField is calledmug_shot, you can get the absolute path to your image in a template with ``.

    For example, say your MEDIA_ROOT is set to '/home/media', andupload_to is set to 'photos/%Y/%m/%d'. The '%Y/%m/%d' part of upload_to is strftime() formatting; '%Y' is the four-digit year, '%m' is the two-digit month and '%d' is the two-digit day. If you upload a file on Jan. 15, 2007, it will be saved in the directory /home/media/photos/2007/01/15.

    내용을 요약하면,

    1. MEDIA_ROOT : 쟝고가 업로드된 파일을 저장할 full path
      • upload_to 옵션을 통해서 subdirectory를 특정할 수 있음.
        • 보통은 작업속도를 빠르게 하기 위해서 날짜/시간과 같이 변하는 값으로 디렉토리를 구분해서 저장하는경우가 많음.
    2. MEDIA_URL : 그 디렉토리의 base public URL로 지정하여라.
    3. 그렇게 저장된 image에서 object.이미지필드명.url 을 입력하면 절대경로를 얻을 수 있음.


    그래서,

    먼저 MEDIA_ROOT와 MEDIA_URL을 지정합니다.

    # settings.py
    MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # full path
    MEDIA_URL = '/media/' # base public URL
    

    두번째로는 view에서 ModelForm을 통해서 File을 받겠다는 것을 명시해줘야 합니다.

    # views.py
    def Upload(request, post_id):
        post = get_object_or_404(Post, id=post_id)
        if request.method == "POST":
            ###############이 부분이 핵심
            post_form = PostModelForm(request.POST, request.FILES)
               
            # 유효성 검사 후 저장
        else:
            # ...
            # 빈 FORM을 보여주는 페이지 렌더링
    
  5. 지정한 파일을 사용자가 볼 수 있게 URL을 안내하기

    MEDIA_URL / 이미지파일 이름.jpg 의 형식으로 파일에 접근할 수 있습니다.

    하지만, url_dispatcher의 허락을 받아야 하기 때문에 다음과 같은 설정을 필요로 합니다.

    Serving files uploaded by a user during development

    이 링크에서는 static() 함수를 사용하는데, 이 함수는 디버그모드에서 파일을 serve할 url들을 리턴하는 함수입니다.

    from django.conf import settings
    from django.conf.urls.static import static
       
    urlpatterns = [
        # ... the rest of your URLconf goes here ...
    ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
    
comments powered by Disqus