Projectapp 구현

jurin·2021년 11월 6일
0

Django Project - LeeBook

목록 보기
8/11

Projectapp은 Article을 카테고리별로 묶어주는 기능이다.

  • Create / Detail/ List View
  • Success_url to related Project
  • Login_required to CreateView
  • Model : title/ description/ image/ created_at

1. python manage.py startapp projectapp

2. LeeBook의 settings.py 에서 projectapp 추가 + urls.py에서 경로 추가

3. projectapp/urls.py에서 app_name 설정

4. projectapp/models.py

class Project(models.Model):
    image = models.ImageField(upload_to='project/', null=False)
    title = models.CharField(max_length=200, null=True)
    description = models.TextField(null=True)
    created_at = models.DateField(auto_now_add=True, null=True)

5. projectapp/forms.py

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

6. makemigrate와 migrate로 DB 연동

7. projectapp/views.py

  • CreateView
@method_decorator(login_required, 'get')
@method_decorator(login_required, 'post')
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})
  • DetailView
class ProjectDetailView(DetailView):
    model = Project
    context_object_name = 'target_project'
    template_name = 'projectapp/detail.html'
  • ListView
class ProjectListView(ListView):
    model = Project
    context_object_name = 'project_list'
    template_name = 'projectapp/list.html'
    paginate_by = 25

8. projectapp/templates.py

  • create.html
    이때까지와 같은 방식으로
  • detail.html
    DeatilView에서 context_object_name으로 지정한 target_project를 이용해 detail 페이지 완성

profileapp에서 사용했던 레이아웃 그대로 사용 (둥근 image, title, description)

{% extends 'base.html' %}

{% block content %}

    <div style="text-align: center; max-width: 700px; margin: 4rem auto;">
        <div>
            <img src="{{ target_project.image.url }}" alt=""
                style="heigth: 12rem; width: 12rem; border-radius: 20rem; margin-bottom: 2rem; object-fit: cover;">
            <h2 style="font-family: 'NanumGimYuICe'">
                {{ target_project.title }}
            </h2>
            <h5 style="margin-bottom: 3rem">
                {{ target_project.description }}
            </h5>


        </div>
    </div>

{% endblock %}
  • list.html
    - card_project.html
    - pagination articleapp뿐만 아니라 다른 app도 모두 적용할 수 있도록 수정

먼저 list.html

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

{% block content %}

<style>

    .container {
        padding: 0;
        margin: 0, auto;
    }

    .container div {
      display: flex;
      justify-content: center;
      align-items: center;
      border-radius: 1rem;
    }

    .container img {
        width: 7rem;
        height: 7rem;
        object-fit: cover;
        border-radius: 1rem;

    }
</style>

    {% if project_list %}
    <div class="container">
        {% for project in project_list %}
        <a href="{% url 'projectapp:detail' pk=project.pk%}">
            <!--            card의 레이아웃을 바꿀 때 card.html만 수정하면 가능하도록 따로 지정해준다.-->
            <!--            card.html에서 필요한 article 객체가 for문에서 정해준 article과 같다는 의미의 코드 작성-->
            {% 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 mt-3 mb-3 px-3">
            Create Project
        </a>
    </div>

{% endblock %}

card_project.html

<div style="display: block; text-align: center;">
    <img src="{{ project.image.url }}" alt="">
    <h5 class="mt-2">
<!--        truncatechars로 긴 제목 짜르기-->
        {{ project.title | truncatechars:8 }}
    </h5>
</div>

pagination.html

?page={{ page_obj.previous_page_number }} 앞에 있던 article에 한정시키는 코드 지우면 모든 app에 적용가능

<a href="?page={{ page_obj.previous_page_number }}"
    class="btn btn-secondary rounded-pill">
    {{ page_obj.previous_page_number }}
</a>

9. base.css로 외관 수정

a {
    color: black;
    text-decoration: none;
}


a:hover {
    color: black;
    text-decoration: none;
}

.leebook_header_nav {
    margin: 0 0.5rem;
}

.leebook_header_navbar {
    margin: 1rem 0;
}

Project와 Article 사이의 연결고리 만들기

articleapp/models.py에서 projcet를 Foreinkey로 만들어준 후 forms.py에도 적용시켜 create할 때 만들어져 있는 project중 골라서 선택할 수 있도록 한다.

articleapp/models.py

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

articleapp/forms.py

        fields = ['title', 'image', 'project', 'content']

모델을 수정했으니 다시 DB에 연동시키기 위해 makemigration, migrate 작업을 해준다.

Project에 articles들 보여주기

이제 Project를 들어갔을 때 그 project인 article들을 보여줘야한다.

articleapp에 commentapp을 Mixin으로 박아 넣었던 것처럼 비슷하게 해야하는데 이 방법은 무조건 다 가져올 때의 방식이고 조건을 달아서 좀 더 여러가지 작업을 하고 싶을 때에는 이런 방식은 한계가 있을 수 있다.

그래서 View안에서 MultipleObjectMixin 이용해 비슷한 방식으로 구현한다.
MultipleObjectMixin은 이름 그대로 여러가지 object를 다룰 수 있게 해준다.

get_context_data 메소드를 이용해서 실질적으로 어떤 게시글을 가져올 것인지에 대한 필터링 구문을 완성한다. object_list 안에 filter를 걸어서 project가 현재 프로젝트의 object와 같은 것을 필터링한다. 그 후 return으로 필터링한 값을 반환해준다.

projectapp/views.py

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)

articleapp/list.html을 복사해서 아무곳에도 종속되지 않은 snippets/list_fragment.html에 list_fragment.html라는 이름으로 붙여넣고 이를 projectapp/detail.html에서 include 구문으로 사용할 것이다.

list_fragment.html는 base.html이랑 관련 없으므로 extends 구문과 block 구문을 지워준다.

article_list를 object_list로 detail.html에서 지정해주면 include 구문으로 그대로 적용하여 사용할 수 있다.

projectapp/detail.html

    <div>

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

    </div>

accountapp에서 Mypage로 접속했을 때 내가 쓴 글 필터링하여 표시하기

accountapp/views.py

class AccountDetailView(DetailView, MultipleObjectMixin):
    model = User
    # 다른 pk로 접속해도 target_user의 정보를 볼 수 있도록 지정해준다.
    context_object_name = 'target_user'
    template_name = 'accountapp/detail.html'
    
    paginate_by = 25
    
    def get_context_data(self, **kwargs):
        object_list = Article.objects.filter(writer=self.get_object())
        return super(AccountDetailView, self).get_context_data(object_list=object_list, **kwargs)

accountapp/detail.html

    <div>

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

    </div>
profile
anaooauc1236@naver.com

0개의 댓글