SSAFY/Django

Static 정적파일 & Media 파일 추가하기

황성안 2021. 3. 18. 13:00
728x90

Static 정적 파일

원본 그대로 보여주는 파일

요청한 것을 그대로 응답하는 되는 파일

기본 경로 > app_name/static

{% load static %}
<img src = "{%static ''%}"

 

실제 배포 환경에서 필요합니다.

 

 

The Staticfiles app

STATIC_URL

  • static_root에 있는 정적 파일을 참조 할 때 사용할 URL
    • 실제 파일이나 디렉토리가 아니며, URL로만 존재

 

 

 

실습하기

image-20210318091117538

이 오류가 발생하게된다. 왼쪽에 보면 requirements 를보고 설치를하여라.

image-20210318091214130

가상환경을 만들어 설치하자

image-20210318091207119

source venv/Scripts/activate

으로 가상 환경을 활성화 시켜주자. 그리고 만약 왼쪽아래에 "Select python ..."이 뜬다면 클릭해서 ('venv')가 붙은녀석을 클릭해주자.

image-20210318091618382

 

다음 리콰이먼트를 이용하여 설치하자

pip install -r requements.txt

tip = 중간까지 단어를치다 tap 을 눌러주면 자동완성

image-20210318091724981

설치가 완료됐다. 한번 서버를 다시 실행시켜보자.

image-20210318091757450

정상 실행이 된다!

하지만 사이트에 들어가보면?

 

http://127.0.0.1:8000/articles/index

image-20210318092036529

오류가 뜬다.

image-20210318092234930

아래로 내려보면 테이블이 검색이안된다고 뜬다. 즉, migrate 시켜줘야한다!

python manage.py migrate

후에 다시 서버를 실행시켜보자

image-20210318092353172

하지만 이렇게하면 실제 데이터는 없다 ㅠㅠ 만약 실제 데이터가 있다면! 우리는 덤프 데이터를 하여야한다.

 

 

STATIC FILE 배워보자

개발자 길을 걸을땐 검색을 생활하합시다..

django 를 검색해봅시다. "django static files"

image-20210318092718611

 

 

정적 파일을 구성하는 중입니다.

  1. 《django.contrib.static files》가 다음 설정에 포함되도록 하십시오. INSTALLED_APPS.
  2.  
  3. 설정 파일에서 다음을 정의합니다.:setting:STATIC_URL, 예를 들어:
  4. STATIC_URL = '/static/'
  5. 템플릿에서 :ttag:〉static〉 템플릿 태그를 사용하여 구성된 를 사용하여 지정된:setting:STATICFILES_STORAGE.에 대한 URL을 빌드합니다.
  6. {% load static %} <img src="{% static 'my_app/example.jpg' %}" alt="My image">
  7. 정적 파일을 앱의 《static》 폴더에 저장합니다. 예를 들어 다음과 같습니다.my_app/static/my_app/example.jpg.

우리는 위의 내용을 검토해보자

  1. crud > settings.py 에 설정돼있다.
  2. URL 또한 포함돼있다.
  3. URL도 빌드돼있다

 

특정 앱에서만 쓰지않는 파일이있을 텐데 우린 아래를 읽어보자.

프로젝트에 특정 앱에 연결되지 않은 정적 자산도 있을 수 있습니다. 앱 내에서 《static/》 디렉토리를 사용하는 것 외에도 디렉토리 목록(:seting:》)을 정의할 수 있습니다.Django가 정적 파일도 찾을 수 있는 설정 파일의 STATICFILES_DIRS)입니다. 예를 들어 다음과 같습니다.

STATICFILES_DIRS = [
    BASE_DIR / "static",
    '/var/www/static/',
]

image-20210318093016048

이 부분이다.

 

개발하는 부분에서는 장고가 자동으로 수행해준다. 하지만 이 방법들은 비효율적이다. 실제로는 우리가 다른 방식으로 사용하자

 

 

STATIC 폴더만들기

안에 또 articles 를 만들어주고

css, javascript.jpg 를 저장하는 공간이된다.

image-20210318093223020

이제 보여주자

templates > index.html 로가자

다음 load staitc을 적어주고 img 태그를 적어주자

image-20210318093719334

이미지는 이제 서버 껏다켜줍시다.

image-20210318093836091

늠름한.. 이재용님....

그리고 개발자 도구 > network 탭을 누르고 all로 바꿔보자

그럼 장고 서버로부터 받은 모든 것들을 볼수있다.

image-20210318094040610

여기서 마우스를 가져다되면 url이 뜬다.

저부분을 담당하는 부분이 바로 settings.py 안에 있는 아래 녀석이다.

STATIC_URL = '/static/'

 

이제 크롬에서 강력 새로고침을해보자

image-20210318094248197

저기 오른쪽 마우스 클릭하면나옴

image-20210318094330395

위와 같이 뜨게된다.

이상태에서 그냥 새로고침을하면!?

image-20210318094448915

이런식으로 메모리 캐싱이라고 뜹니다. 이는 나중에 배울 메모리제이싱 , 일종의 캐싱이라 보면됩니다.

저장해놓고 빠르게 보기? 라 생각해보면됩니다.

 

settings.py에서 다른 곳으로 저장해보자

image-20210318094617054

STATICFILES_DIR = [
    #crud/static/stylesheets/style.css
    BASE_DIR / 'crud' / 'static',
]

이걸 추가시켜주자.

image-20210318094757857

후에 폴더를 만들어주자 static/ stylesheets / 스타일.css 파일

image-20210318094838921

style.css

h1 {
    color: tomato;
}

적용하기

base.html 찾기

css block 시키기 > 타이틀 위에다가

image-20210318095035925

그리고 이놈을 index.html에서 불러와보자.

image-20210318095110109

그리고 사이에 link 를 입력해주고 경로 설정을해주자.

image-20210318095230557

 

 

개발자도구를 이용해보자

image-20210318100907905

여기서 저주소를 들어가보자

image-20210318100939748

짜란 코드가 바로뜨게된다.

이미지 파일을 같은 방식으로가게되면 이미지파일만뜨게된다. 즉, 우린 프론트엔드 파츠는 이걸로 볼수있는 것

백엔드말고!

 

 

 

settings.py 로가보자 (배포)

image-20210318101133866

다음 서버를 끄고 아래 명령어를 처주자

python manage.py collectstatic

그려머는 옆에 폴더가 staticfiles가 추가됩니다.

image-20210318101619459

 

여기까지가 static에 오늘 배움에 대한 전부이다

 

 

 

 

 

Media 파일 추가하기 시작

 

 

 

 

media 파일

settings.py > MEDIA_ROOT, URL 추가 해주기

upload_to 라는 녀석을 통해

이번에도 "django media files" 라고 검색해보자

Managing files

This document describes Django’s file access APIs for files such as those uploaded by a user.

기본적으로 장고는 로컬에 저장한다, media_root와 url 을 사용한다.

Using files in models

When you use a FileField or ImageField, Django provides a set of APIs you can use to deal with that file.

모델에서는 filefield와 imagefield를 추가한다.

 

models.py

image 를 추가시켜주자

image-20210318102227898

이렇게하면 기존에 있던 파일이 이미지가 없기떄문에 다른 뭔가 뜰것임..

image-20210318102232135

그래서 우리는 저중간에 blank=True 를 넣어준다.

from django.db import models

# Create your models here.
class Article(models.Model):
    title = models.CharField(max_length=10)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    image = models.ImageField(blank=True)

이제 저장하고 makemigrations 와 migrate를 해주자

image-20210318102432786

에러뜨쥬? 근데 Pillow 가 설치안돼있다고 설치하래요

pip install Pillow

항상 다른 사람을위해서 리콰이어먼트에 추가해주자

pip freeze > requirements.txt

그리고 migrate도 꼭 해주기!

이제 서버를 켜보아요.

 

create.html 가자

이미지를 띄워봅시다

image-20210318103206098

인크 타입이무엇일까? 참고하러가봅시다. 검색어 " mdn form enctype"

enctype

method 특성이 post인 경우, enctype은 양식 제출 시 데이터의 MIME 유형을 나타냅니다.

  • application/x-www-form-urlencoded: 기본값.
  • multipart/form-data: <input type="file">이 존재하는 경우 사용하세요.
  • text/plain: HTML 5에서 디버깅 용으로 추가된 값.

`](https://developer.mozilla.org/ko/docs/Web/HTML/Element/button), (en-US), (en-US)요소의 [formenctype` 특성으로 재정의할 수 있습니다.

 

라고 합니다.

views.py

def create(request):
    # POST일 때
    if request.method == 'POST':
        form = ArticleForm(request.POST, request.FILES)<<<<<<< 파일요청을 추가해주셔야해요
        if form.is_valid():
            article = form.save()
            return redirect('articles:detail', article.pk)
    # GET일 때
    else:
        form = ArticleForm()
    context = {
        # 상황에 따른 2가지 모습
        # 1. is_valid에서 내려온 form : 에러메세지를 포함한 form
        # 2. else에서 내려온 form : 빈 form
        'form': form,
    }
    return render(request, 'articles/create.html', context)

 

settings.py

#미디어 url
#STATIC_ROOT와 유사. 업로드된 파일의 주소를 만들어줌.
MEDIA_URL= '/media/'
#미디어 루트
# 실제 업로드뒤는 파일이 저장되는 경로를 지정
MEDIA_ROOT = BASE_DIR / 'media'

image-20210318104103645

근데 만약에 사용자가 같은 이름으로 저장을한다묜 어떻게할까요?

models.py 에서 구분시키는 코드를 추가시켜줍니다.

from django.db import models

# Create your models here.
class Article(models.Model):
    title = models.CharField(max_length=10)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    image = models.ImageField(upload_to ="uploads/%Y/%m/%d",blank=True) #<<< 구분지어주기

장고가 알아서 뒤에 무엇을 붙여줍니다.

 

templats> detail.html

공식문서에서 name, path, url 을 추가시켜라합니다.

{% extends 'base.html' %}

{% block content %}
  <h2>DETAIL</h2>
  <h3>{{ article.pk }} 번째 글</h3>
  <hr>
  <p>제목 : {{ article.title }}</p>
  <p>내용 : {{ article.content }}</p>
  <img src="{{ article.image.url }}" alt="{{ article.image.name }}">#<<< 이녀석 추가
  <p>작성시각 : {{ article.created_at }}</p>
  <p>수정시각 : {{ article.updated_at }}</p>
  <hr>
  <a href="{% url 'articles:update' article.pk %}" class="btn btn-primary">[UPDATE]</a>
  <form action="{% url 'articles:delete' article.pk %}" method="POST">
    {% csrf_token %}
    <button class="btn btn-danger">DELETE</button>
  </form>
  <a href="{% url 'articles:index' %}">[back]</a>
{% endblock %}

여기까지하면 이렇게뜸 ㅎㅎ;

image-20210318104711956

우리 root urls py로 가보자.

https://docs.djangoproject.com/en/3.1/howto/static-files/여기들어가보면 개발단계에서 유저가 올린것을 보기 탭이있습니다.

image-20210318105336292

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)

이것들은 장고가 미디어파일을 관리하는 방식이다. 그냥 따라주시면됩니다.

 

이미지 없을때 안 띄우는 방법!

  1. if문
  2. {% extends 'base.html' %} {% block content %} <h2>DETAIL</h2> <h3>{{ article.pk }} 번째 글</h3> <hr> <p>제목 : {{ article.title }}</p> <p>내용 : {{ article.content }}</p> {% if article.image %}#<<<<<<<<<<<<<<<<<<<<< <img src="{{ article.image.url }}" alt="{{ article.image.name }}"> {% endif %}#<<<<<<<<<<<<<<<<<<<<<<<< <p>작성시각 : {{ article.created_at }}</p> <p>수정시각 : {{ article.updated_at }}</p> <hr> <a href="{% url 'articles:update' article.pk %}" class="btn btn-primary">[UPDATE]</a> <form action="{% url 'articles:delete' article.pk %}" method="POST"> {% csrf_token %} <button class="btn btn-danger">DELETE</button> </form> <a href="{% url 'articles:index' %}">[back]</a> {% endblock %}
  3. 기본적 이미지 생성
  4. {% extends 'base.html' %} {% block content %} <h2>DETAIL</h2> <h3>{{ article.pk }} 번째 글</h3> <hr> <p>제목 : {{ article.title }}</p> <p>내용 : {{ article.content }}</p> {% if article.image %} <img src="{{ article.image.url }}" alt="{{ article.image.name }}"> {% elif %} <img src="기본 이미지" alt="{{ article.image.name }}"> #<<<<<<<<<<<<<<<<<<< {% endif %} <p>작성시각 : {{ article.created_at }}</p> <p>수정시각 : {{ article.updated_at }}</p> <hr> <a href="{% url 'articles:update' article.pk %}" class="btn btn-primary">[UPDATE]</a> <form action="{% url 'articles:delete' article.pk %}" method="POST"> {% csrf_token %} <button class="btn btn-danger">DELETE</button> </form> <a href="{% url 'articles:index' %}">[back]</a> {% endblock %}

그리고 같은 파일을 올리면 MD5, Hash 알고리즘 이라하여 희안한 이름을 붙여줍니다.

 

views.py

update 함수에 enctype="multipart/form-data" 과, requestFILES, 추가시켜주기

@require_http_methods(['GET', 'POST'])
def update(request, pk):
    article = Article.objects.get(pk=pk)
    # update
    if request.method == 'POST':
        form = ArticleForm(request.POST,  request.FILES, instance=article)
        if form.is_valid():
            form.save()
            return redirect('articles:detail', article.pk)
    # edit
    else:
        form = ArticleForm(instance=article)
    context = {
        'form': form,
        'article': article,
    }
    return render(request, 'articles/update.html', context)
        

 

하지만 장고 미디어파일에는 사진과 글이있는 글을 삭제해도 파일은 남게된다.

image-20210318112245568

기존 이미지 삭제하는 알고리즘을 적어두면된다.

 

 

문제

용량제한을 걸어둬야 서버 문제가 줄어든다. 용량 제한을 알아두자.

 

 

아이콘 바꾸기

image-20210318112825789

이녀석을 바꿔보자

다운받은 아이콘을 올리자

https://www.favicon-generator.org/ (파일 선택 > create Favicon > 다운로드)

그러면 종류별로 icon 이 생성된 알집이 나오는데 압축을 풀어주고 32*32을 찾아주자

다음 crud > static 안에 넣어주자

image-20210318113236489

 

base. html 로가자

{% load static %} 맨위에추가

헤드 안 meta 가장 아래에 link 테그를 넣어주자

rel 은"" icon" 으로 변경 주소는"{% static 'favicon-32x32.png' %}"

image-20210318113544361

 

media 폴더 내 파일도 지우는방법

article.image.delete() 이친구를 views.py 의 딜리트 함수에 추가시켜주면됩니다.

@require_POST
def delete(request, pk):
    # 삭제할 게시글 조회
    article = Article.objects.get(pk=pk)
    # 삭제 요청이 POST면 삭제, POST가 아니라면 DETAIL 페이지로 redirect
    article.image.delete() #ArticleCkass.ImageField.method()
    article.delete()
    return redirect('articles:index')

 

네비바에 검색어 입력하는방법

<nav class="navbar navbar-expand-lg navbar-light bg-light">
  <div class="container-fluid">
    <a class="navbar-brand" href="#">Navbar</a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav me-auto mb-2 mb-lg-0">
        <li class="nav-item">
          <a class="nav-link active" aria-current="page" href="#">Home</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="#">Link</a>
        </li>
        <li class="nav-item dropdown">
          <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
            Dropdown
          </a>
          <ul class="dropdown-menu" aria-labelledby="navbarDropdown">
            <li><a class="dropdown-item" href="#">Action</a></li>
            <li><a class="dropdown-item" href="#">Another action</a></li>
            <li><hr class="dropdown-divider"></li>
            <li><a class="dropdown-item" href="#">Something else here</a></li>
          </ul>
        </li>
        <li class="nav-item">
          <a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
        </li>
      </ul>
      <form class="d-flex">
        <input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
        <button class="btn btn-outline-success" type="submit">Search</button>
      </form>
    </div>
  </div>
</nav>

밑 form에 action="{% url 'articles:search' %}" method="GET">과 input 에 name = "keyword를 추가해줍니다."

를 추가해준다

<nav class="navbar navbar-expand-lg navbar-light bg-light">
  <div class="container-fluid">
    <a class="navbar-brand" href="#">Navbar</a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav me-auto mb-2 mb-lg-0">
        <li class="nav-item">
          <a class="nav-link active" aria-current="page" href="#">Home</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="#">Link</a>
        </li>
        <li class="nav-item dropdown">
          <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
            Dropdown
          </a>
          <ul class="dropdown-menu" aria-labelledby="navbarDropdown">
            <li><a class="dropdown-item" href="#">Action</a></li>
            <li><a class="dropdown-item" href="#">Another action</a></li>
            <li><hr class="dropdown-divider"></li>
            <li><a class="dropdown-item" href="#">Something else here</a></li>
          </ul>
        </li>
        <li class="nav-item">
          <a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
        </li>
      </ul>
      <form class="d-flex" action="{% url 'articles:search' %}" method="GET"> #<<< 여기랑
        <input name="keyword" class="form-control me-2" type="search" placeholder="Search" aria-label="Search">#<<여기용!
        <button class="btn btn-outline-success" type="submit">Search</button>
      </form>
    </div>
  </div>
</nav>

 

그다음 urls.py 에서 추가

from django.urls import path
from . import views


app_name = 'articles'
urlpatterns = [
    path('index/', views.index, name='index'),
    # path('new/', views.new, name='new'),
    path('create/', views.create, name='create'),
    path('<int:pk>/', views.detail, name='detail'),
    path('<int:pk>/delete/', views.delete, name='delete'),
    # path('<int:pk>/edit/', views.edit, name='edit'),
    path('<int:pk>/update/', views.update, name='update'),

    path('search/', views.search, name='search')
]

다음 views.py 에서 search 함수 추가

def search(request):
    # 1. 사용자가 입력한 검색어를 꺼냅니다.
    keyword = request.GET.get('keyword')

    # 2. 검색어에 해당하는 데이터를 DB에서 가져옵니다.
    articles = Article.objects.filter(title=keyword)
    context = {
        'articles':articles,
    }
    return render(request, 'articles/index.html', context)

필터를 해주고 옆의 () 안에는 title 또는 context 를 입력해주면 keyword값 검색이가능하다.

추가적으로 title__contains 를 하면 keyword를 가진 모든 값을 검색 가능하다.

728x90

'SSAFY > Django' 카테고리의 다른 글

[Django]Form  (0) 2021.03.21
[DJANGO] STATIC FILES  (0) 2021.03.19
현재까지 Django 요약  (0) 2021.03.17
가상환경 만들기부터 게시판 Form 을 사용하여 만들기  (0) 2021.03.16
Django 가상 환경 만들기 // 협업  (0) 2021.03.13