프로젝트세팅 ~ 사진있는 게시판 만들기 실습

‍한승운·2021년 3월 18일
0

django

목록 보기
6/23
post-custom-banner

1. 기본 세팅 하기

프로젝트 이름은 crud, 앱 이름은 articles로 설정한다.

  • venv

    • python -m venv venv : venv 환경 만들기
    • source venv/Scripts/activate : 가상환경 켜기
    • pip install django
      • 만약 남에꺼를 받아와서 쓰는 것이면 pip install -r requirements.txt
    • pip install pillow
    • pip freeze > requirements.txt 환경 저장
  • gitignore 파일 만들기

  • cmd

    • django-admin startproject CRUD
    • 플젝 안으로 들어가서
      • python manage.py startapp articles : articles 어플만들기
  • articles

    • CRUD.settings.py 에서 INSTALLED_APPS 에서 articles 추가
  • 한글과 시간 설정

    • crud.settings.py 에서
      • LANGUAGE_CODE = 'ko-kr'
      • TIME_ZONE = 'Asia/Seoul'
  • BASE.HTML 만들기

    • CRUD.templates 내에 base.html 만들기

      • {% block content %}

        {% endblock %}

    • CRUD.settings.py 내에 TEMPLATES 내에 DIRS

      • 'DIRS': [BASE_DIR / 'crud' / 'templates'],
    • Bootstrap CDN 을 BASE.html에 넣기

      1. 파일 넣기

        • CRUD.static/stylesheets 경로 만들기
          • 부트스트랩 CSS 파일 넣기(bootstrap.css)
        • CRUD.static/javascript 경로 만들기
          • 부트스트랩 JS 파일 넣기(bootstrap.js)
      2. base.html 에 가서

        • 맨 위에 {% load static %}

        • <link rel="stylesheet" href="{% static 'stylesheets/bootstrap.css' %}">

        • <script src="{% static 'javascript/bootstrap.js' %}"></script>

      3. CRUD.settings.py

        • STATICFILES_DIRS= [ BASE_DIR / '프로젝트이름' / 'static'] 추가
  • bootstrap5 모듈 적용해보기 - update 페이지에서 사용해봄

    • pip install django-bootstrap-v5

    • 프로젝트.settings.py > INSTALLED_APPS

      • "bootstrap5" 추가하기

2. 모델 만들기

  1. articles.models.py

    • 제목, 내용, 사진, 작성일, 수정일
    from django.db import models
    
    # Create your models here.
    class Article(models.Model) :
        title = models.CharField(max_length=10)  # charField : 길이에 제한이 있는 textfield에 대해서 사용
        content = models.TextField()
        image = models.ImageField(blank=True)
        created_at = models.DateTimeField(auto_now_add=True) # auto_now_add = 작성일
        updated_at = models.DateTimeField(auto_now=True) # auto_now = 수정일
  2. 데이터 베이스에 등록

    • python manage.py makemigrations
    • python manage.py migrate

3. 글목록 출력

  1. articles.urls.py 만들기

    from django.urls import path
    from . import views
    
    app_name = 'articles'
    urlpatterns = [
        path('', views.index, name = 'index'),  
        
    ]
  2. crud.urls.pyarticles.urls.py랑 연결시키기

    from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('articles/', include('articles.urls')),
    ]
  3. articles.views.py

    from django.shortcuts import render
    from .models import Article
    
    # Create your views here.
    def index(request) :
        articles = Article.objects.order_by('-pk') # pk 역순 출력
        context = {
            'articles': articles,
        }
        return render(request, 'articles/index.html', context)
  4. articles.templates/articles/index.html 만들기

    {% extends 'base.html' %}
    
    {% block content %}
      <h1>Articles</h1>
      <a href="{% url 'articles:create' %}">[CREATE]</a>
      <hr>
      {% for article in articles %}
        <p>글 번호 : {{ article.pk }}</p>
        <p>글 제목 : {{ article.title }}</p>
        <a href="{% url 'articles:detail' article.pk %}">[DETAIL]</a>
        <hr>
      {% endfor %}
    {% endblock %}
    

4. 글쓰기 만들기

  1. modelform 만들기

    • articles.forms.py 만들기
    from django.shortcuts import render, redirect
    from django import forms
    from .models import Article
    
    class ArticleForm(forms.ModelForm):
        title = forms.CharField(
            label='제목',
            widget=forms.TextInput(
                attrs={
                    'class': 'my-title form-control',
                    'placeholder': 'Enter the Title',
                    'maxlength': 10,
                }
            )
        )
        content = forms.CharField(
            label='내용',
            widget=forms.Textarea(
                attrs={
                    'class': 'my-content form-control',
                    'placeholder': 'Enter the Content',
                    'rows': 5,
                    'cols': 30,
                }
            ),
            error_messages={
                'required': '데이터를 입력해줄래...?',
            }
        )
    
        class Meta:
            model = Article
            fields = '__all__'
            # exclude = ('title',)
  2. articles.urls.py 에 주소 추가

    • path('create/', views.create, name='create')
  3. articles.views.py 에 메서드 추가

    • form = ArticleForm(request.POST, request.FILES) 매개변수 request.FILES 주의
    from django.views.decorators.http import require_http_methods
    from .forms import ArticleForm
    
    # 하나의 view 함수가 request의 method에 따라서 2가지 역할을 하게 됨
    @require_http_methods(['GET', 'POST'])
    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)
  4. articles.templates/articles/create.html 만들기

    • enctype="multipart/form-data" 주의
    {% extends 'base.html' %}
    
    {% block content %}
      <h1>CREATE</h1>
      <form action="" method="POST" enctype="multipart/form-data">
        {% csrf_token %}
        {{ form.as_p }}
        <input type="submit">
      </form>
    
      <a href="{% url 'articles:index' %}">[back]</a>
    {% endblock %}
  5. 미디어 저장 장소 만들기

    • crud.settings.py

      • MEDIA_URL ='/media/' : 서버가 Media 파일을 요청할 때 사용할 가상의 URL
      • MEDIA_ROOT = BASE_DIR / 'media' : Media 파일이 실제로 위치할 경로
    • crud.urls.py

      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)
      # 이거는 static 파일들 경로가 추가되는것 - 자동으로 추가되어잇음
      # + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

5. 글 상세 만들기

  1. articles.urls.py 에 주소 추가

    • path('<int:pk>/', views.detail, name='detail'),
  2. articles.views.py 에 메서드 추가

    from django.views.decorators.http import require_safe
    # require_safe는 get방식으로만 동작
    @require_safe
    def detail(request, pk):
        # 몇번 글을 조회할건지 가져와야 함
        article = Article.objects.get(pk=pk)
        context = {
            'article': article,
        }
        return render(request, 'articles/detail.html', context)
  3. articles.templates/articles/detail.html 만들기

    • 미디어 이미지 불러오기 : {{ article.image.url }}
{% extends 'base.html' %}

{% block content %}
  <h2>DETAIL</h2>
  <h3>{{ article.pk }} 번째 글</h3>
  <hr>
  <p>제목 : {{ article.title }}</p>
  
  {% if article.image %}
    <img src = "{{ article.image.url }}" alt="{{ article.image }}">
  {% else %}
    <p>이미지가 없습니다</p>
  {% endif %}
  
  <p>내용 : {{ article.content }}</p>
  <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 %}

6. 글 수정 만들기

  1. articles.urls.py 에 주소 추가

    • path('<int:pk>/update/', views.update, name='update'),
  2. articles.views.py 에 메서드 추가

    @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)
  3. articles.templates/articles/update.html 만들기

{% extends 'base.html' %}
{% load bootstrap5 %}

{% block content %}
  <h1>UPDATE</h1>
  <form action="{% url 'articles:update' article.pk %}" method="POST" enctype="multipart/form-data" >
    {% csrf_token %}
    
    {% bootstrap_form form layout='horizontal' %}
    {% buttons submit='OK' reset="Cancel" %}{% endbuttons %}
  </form>
  <hr>
  <a href="{% url 'articles:index' %}">[back]</a>
{% endblock  %}

7. 글 삭제 만들기

  1. articles.urls.py 에 주소 추가

    • path('<int:pk>/delete/', views.delete, name='delete'),
  2. articles.views.py 에 메서드 추가

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

8. 관리자 페이지 만들기

  • cmd

    • python manage.py createsuperuser
  • articles.admin.py

    from django.contrib import admin
    from .models import Article # 현재 모델에서 article 테이블 가져오기
    # Register your models here.
    
    # Register your models here.
    class ArticleAdmin(admin.ModelAdmin) :
        list_display = ('pk', 'title', 'image','content', 'created_at', 'updated_at', ) # 현재 보일 column들을 tuple 혹은 list로 써주기
    
    
    # admin site에 Article과 ArticleAdmin 을 등록하겠다.
    admin.site.register(Article, ArticleAdmin) 
profile
함께 성장하고 싶은 백엔드 개발자
post-custom-banner

0개의 댓글