[Django] Pinterest 만들기 (8)

33587 단어 djangodjango

Projectapp 구현

지금까지 account, profile, article 앱을 만들었다. 이번 강의에서는 지금까지 배운 내용을 기반으로 projectapp을 스스로 만들어보았다. 코드는 지금까지 만들었던 앱들과 다를게 거의 없었기에 어려움이 없었다. 완성된 코드들을 작성한 순서대로 넣어보려한다.

우선 projectapp을 만든다

python mamage.py startapp projectapp

pinterest url에 projectapp에 대한 url을 추가해준다. 그리고 projectapp에 url을 만들어 다음과 같이 작성해준다. articleapp에서 만들었던 과정과 거의 같다. create와 detail url을 만들고 project의 리스트들을 보여주는 list 링크를 만들어준다.

from django.urls import path

from commentapp.views import CommentCreateView, CommentDeleteView

from projectapp.views import ProjectCreateView, ProjectDetailView, ProjectListView

app_name = 'projectapp'

urlpatterns = [
    path('list/', ProjectListView.as_view(), name='list'),

    path('create/', ProjectCreateView.as_view(), name='create'),
    path('detail/<int:pk>', ProjectDetailView.as_view(), name='detail')
]

Project model을 만들어준다. 다음과 같이 4가지 field를 정의해준다.

from django.db import models

# Create your models here.


class Project(models.Model):
    image = models.ImageField(upload_to='project/', null=False)
    title = models.CharField(max_length=30, null=False)
    description = models.CharField(max_length=100, null=True)

    created_at = models.DateTimeField(auto_now=True)

model을 만들었으니 form도 작성해준다.

from django.forms import ModelForm

from projectapp.models import Project


class ProjectCreationForm(ModelForm):
    class Meta:
        model = Project
        fields = ['image', 'title', 'description']

잊지말자 migrate!

python manage.py makemigrations
python manage.py migrate

그리고 views.py를 작성한다. urls.py에서 봤듯이, create,detail,list View를 만들어준다.

from django.shortcuts import render

from django.views.generic import CreateView, DetailView, ListView

from django.urls import reverse

from projectapp.models import Project
from projectapp.forms import ProjectCreationForm

# Create your views here.


class ProjectCreateView(CreateView):
    model = Project
    form_class = ProjectCreationForm
    template_name = 'projectapp/create.html'

    def get_success_url(self):
        return reverse('projectapp:detail', kwargs={'pk': self.object.pk})


class ProjectDetailView(DetailView):
    model = Project
    context_object_name = 'target_project'
    template_name = 'projectapp/detail.html'


class ProjectListView(ListView):
    model = Project
    context_object_name = 'project_list'
    template_name = 'projectapp/list.html'
    paginate_by = 25

template 파일을 만들어 3개의 html 파일을 작성한다.

create.html

{% load bootstrap4 %}

{% block content %}
    <div style="text-align: center; max-width: 500px; margin: 4rem auto;">
        <div class="mb-4">
            <h4>Project Create</h4>
        </div>
        <form action="{% url 'projectapp:create' %}" method="POST" enctype="multipart/form-data">
            {% csrf_token %}
            {% bootstrap_form form %}
            <input type="submit" class="btn btn-primary" name="" id="">
        </form>
    </div>
{% endblock %}

detail.html

{% extends 'base.html' %}

{% block content %}

    <div>
        <div style="text-align: center; max-width: 500px; margin: 4rem auto;">
            <img src="{{ target_project.image.url }}" alt="" style="height: 12rem; width: 12rem; border-radius: 20rem; margin-bottom: 2rem;">
            <h2>
                {{ target_project.title }}
            </h2>
            <h5 style="margin-bottom: 3rem;">
                {{ target_project.description }}
            </h5>
        </div>
    </div>
{% endblock %}

list.html

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

{% block content %}

<style>
    .container div {
  width: 250px;
  background-color: antiquewhite;
  display: flex;
  justify-content: center;
  align-items: center;
  border-radius: 1rem;
}

.container img {
    width: 100%;
    border-radius: 1rem;
}

</style>
{% if project_list %}
<div class="container">
    {% for project in project_list %}
    <a href="{% url 'projectapp:detail' pk=project.pk%}">
        {% include 'snippets/card_project.html' with project=project %}
    </a>
    {% endfor %}
  </div>
  <script src="{% static 'js/magicgrid.js' %}"></script>
{% else %}
<div style="text-align: center;">
    <h1>No Projects YET!</h1>
</div>
{% endif%}

{% include 'snippets/pagination.html' with page_obj=page_obj %}
  
  <div style="text-align: center;">
      <a href="{% url 'projectapp:create' %}" class="btn btn-dark rounded-pill col-3 mt-3 mb-3">
          Create Project
      </a>
  </div>



{% endblock %}

그리고 snippets/card_project.html도 작성해준다.

<div>
    <img src="{{ project.image.url }} " alt="">
</div>

기존의 pagination.html은 url이 articel로 고정되어 있었으므로 그 부분을 없애준다.

<div style="text-align: center; margin: 1rem 0;">
    {% if page_obj.has_previous %}
    <a href="?page={{ page_obj.previous_page_number }} " class="btn btn-secondary rounded-pill">
        {{ page_obj.previous_page_number }}
    </a>
    {% endif %}
    <a href="?page={{ page_obj.number }}" class="btn btn-secondary rounded-pill activate">
        {{ page_obj.number}}
    </a>
    {% if page_obj.has_next %}
    <a href="?page={{ page_obj.next_page_number }}" class="btn btn-secondary rounded-pill">
        {{ page_obj.next_page_number }}
    </a>
    {% endif %}
</div>

header.html에 project 링크를 추가해준다

<span>
  <a href="{% url 'projectapp:list' %}">
      <span>Projects</span>
  </a>
</span>

이제 실행화면들을 살펴보자

만들려고 했던 3가지 기능들 모두 정상적으로 작동하는 것을 볼 수 있다. 기능만 테스트해봤고 디자인을 다뤄서 예쁘게 다듬어 볼 것이다.

MultipleObjectMixin을 통한 Projectapp 마무리

우리가 만드는 projectapp은 article을 담기 위한 것이다.
따라서 articleapp/models.py에서 project라는 필드도 하나 넣어주고,

project = models.ForeignKey(
        Project, on_delete=models.SET_NULL, related_name='article', null=True)

forms.py에서 project라는 필드를 추가해준다.

그리고 테스트를 해보면 다음과 같이 project 목록이 잘 나오는 것을 볼 수 있다.

그러면 다음과 같이 게시물을 등록했을 때 project에서 article이 나오도록 해줘야한다. 그러기 위해 projectapp에서 detailview를 다음과 같이 수정한다

class ProjectDetailView(DetailView, MultipleObjectMixin):
    model = Project
    context_object_name = 'target_project'
    template_name = 'projectapp/detail.html'

    paginate_by = 25

    def get_context_data(self, **kwargs):
        object_list = Article.objects.filter(project=self.get_object())
        return super(ProjectDetailView, self).get_context_data(object_list=object_list, **kwargs)

MultipleObjectMixin이라는 것을 이용하여 해당하는 article object들을 모두 보여주도록 한다.

그리고 projectapp/detail.html 아래에 다음 코드를 추가한다. 게시글을 보여주는 부분이다

<div>
    {% include 'snippets/list_fragment.html' with article_list=object_list %}
</div>

그리고 게시글을 보여주는 것은 articleapp/list.html과 동일하다. 따라서 다음 사진과 같이 snippets에 또 다른 list를 만들어줘서 보여주도록 한다.

또한 마이페이지에도 똑같이 게시글을 보여주도록 해야한다. 위에서 했던것과 똑같이 작성해주면 된다.

좋은 웹페이지 즐겨찾기