본문 바로가기
FrameWork/pinterest clone

10. Projectapp 만들기

by mansoorrr 2023. 7. 24.

projectapp은 article이 그룹화 되어 나타나는 형태이다.

지금까지 진행했던 것과 마찬가지로 python manage.py startapp projectapp을 실시한다.

settings, urls, projectapp/urls, projectapp/models를 먼저 세팅해주고 migration까지 실시한다.

 

<settings.py>

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'accountapp',
    'bootstrap4',
    'profileapp',
    'articleapp',
    'projectapp',
]

<urls.py>

urlpatterns = [
    path('admin/', admin.site.urls),
    path('accounts/', include('accountapp.urls')),
    path('profiles/', include('profileapp.urls')),
    path('articles/', include('articleapp.urls')),
    path('projects/', include('projectapp.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

<projectapp/urls 생성>

from django.urls import path

from projectapp.views import ProjectCreateView, ProjectDetailView, ProjectListView

app_name = 'projectapp'

urlpatterns = [

]

<projectapp/models.py>

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

 

기본적인 세팅이 끝났으면 본격적으로 개발을 시작한다. projectapp의 경우 한번 생성하면 함부로 수정하거나 지울수 없다. 따라서 Create, Detail, ListView만 생성한다.

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

<CreatView>

article의 createview와 동일하게 진행한다.

<views.py>

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})

<forms.py>

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

<결과화면>

 

<DetailView>

<views.py>

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

<결과화면>

 

<ListView>

listview의 경우 html을 만들어 주는데 해당 html은 article/list.html과 동일하고 context_object_name이 project_list 이므로 파일 내의 내용을 변경해 준다.

class ProjectListView(ListView):
    model = Project
    context_object_name = 'project_list'
    template_name = "projectapp/list.html"
    paginate_by = 5
{% extends 'base.html' %}
{% load static %}

{% block content %}

<style>
.container div {
  width: 10rem;
  height: 10rem;
  border-radius: 1rem;
}
.container img {
  width: 100%;
  height: 100%;
}
</style>

<!DOCTYPE html>
{% if project_list %} # project_list를 순회
<div class="container">
  {% for project in project_list %}
  <div> # 해당 프로젝트에서 뽑을 내용들
    <a href="{% url 'projectapp:detail' pk=project.pk %}"> 
      <img src="{{ project.image.url }}" alt="" style="width: 100%; height: 100%; border-radius:1rem;">
    </a>
    <p class="text-center">
      {{ project.title }}
    </p>
  </div>
  {% endfor %}
  <script src="{% static 'js/magicgrid.js' %}"></script>
</div>
{% else %}
<h3>Project Not Yet</h3>
{% endif %}

<!--  pagination  -->
{% include 'snippets/pagination.html' %}


{% if user.is_authenticated %}
<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>
{% endif %}


{% endblock %}

<결과>

header.html의 navigation button을 Projects로 변경해주고 list로 향하는 url을 걸어주면 해당 페이지가 나타난다.

이제 project/detail.html 밑에 해당 project에 속해있는 article들이 나타나야 한다(1: N관계가 된다). 따라서  project를 부모로 갖도록 Article모델을 수정해준다. 모델을 수정했기 때문에 form도 수정해 주고, 이후 ProjectDetailView에 MultipleObjectMixin을 추가로 사용해 줌으로써 이 문제를 해결한다.

<articleapp/models.py수정>

class Article(models.Model):
    writer = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, related_name='article')
    
    project = models.ForeignKey(Project, on_delete=models.SET_NULL, null=True, related_name='article') #추가!
    
    title = models.CharField(max_length=200, null=True)
    image = models.ImageField(upload_to='article/', null=False)
    content = models.TextField(null=True)
    created_at = models.DateField(auto_now_add=True, null=True)

<articleapp/forms.py 수정>

추가 후 makemigrations과 migrate를 실시한다.

from django.forms import ModelForm

from articleapp.models import Article


class ArticleCreationForm(ModelForm):
    project = forms.ModelChoiceField(queryset=Project.objects.all()) # 아무것도 선택하지 않아도 되게 설정
    class Meta:
        model = Article
        fields = ['image', 'title', 'project', 'content'] #추가!

이후 article을 create하러 들어가보면 프로젝트를 선택할 수 있는 란이 설정되어 있다. 현재는 객체명으로 써져있기 때문에 이를 수정해주도록 하겠다.

<projectapp/models.py 내용추가>

from django.contrib.auth.models import User
from django.db import models

# Create your models here.
class Project(models.Model):
    image = models.ImageField(upload_to='project/', null=True)
    title = models.CharField(max_length=100, null=True)
    description = models.CharField(max_length=200, null=True)
    created_at = models.DateField(auto_now_add=True, null=True)

	# 이내용 추가
    def __str__(self):
        return f"{self.pk}: {self.title}"

원하는대로 잘 출력되는것을 확인할 수 있다.

그럼 이제 들어가게 projectapp/detail에 해당 article이 보여지게 해야한다. 위에서 간략하게 설명한대로 진행한다.

 

<projectapp/views.py>

class ProjectDetailView(DetailView, MultipleObjectMixin): #mixin추가
    model = Project
    context_object_name = 'target_project'
    template_name = 'projectapp/detail.html'
    
    paginate_by = 20 #추가
    
    def get_context_data(self, **kwargs): #추가
        object_list = Article.objects.filter(project=self.get_object())
        return super().get_context_data(object_list=object_list)

<projectapp/detail.py>

{% extends 'base.html' %}

{% block content %}

<div class="account_create">
  <div>
    <p>{{ target_project.title }}</p>
    <p>{{ target_project.description }}</p>
  </div>
  <div>
    <img src="{{ target_project.image.url }}" alt="" style="width: 10rem; height: 10rem; border-radius: 20rem; margin-bottom: 2rem;">
  </div>
</div>

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

{% endblock %}

<결과>

'FrameWork > pinterest clone' 카테고리의 다른 글

12. 마무리  (0) 2023.07.25
11. Subscriptionapp 만들기  (0) 2023.07.25
9. articleapp만들기  (0) 2023.07.22
8. profileapp 만들기  (0) 2023.07.22
7. accountapp 만들기  (0) 2023.07.20