프런트엔드에서 생성한 데이터 표시

이제 블로그용 데이터를 생성했으므로 이 장에서는 Django ORM을 사용하여 데이터를 표시하는 방법을 배웁니다. 무엇을 기다립니다? 또는 무엇을?

Django ORM은 데이터베이스에 접근하는 편리한 방법을 제공합니다. Object Relational Mapper의 약자입니다. 즉, 데이터베이스에서 데이터를 가져오는 것이 더 쉬운 방법입니다. SQL 쿼리를 만드는 대신 객체의 속성을 해당 테이블에 매핑합니다. ORM을 사용하여 데이터를 개별 테이블에 매핑함으로써 우리는 SQL 쿼리를 작성하고 있지만 그렇지 않습니다.

프런트 엔드를 더 예쁘게 만들기 위해 UI를 약간 조정했습니다.

우리 홈페이지에는 우리가 파이썬 셸에서 만든 4개의 블로그 목록이 표시되어 있습니다. Django ORM을 사용하여 매핑하기 위해 BlogListView의 views.py에서 지정한 context_object_name을 가져오는 for 루프를 만듭니다. 실제로 데이터베이스의 데이터를 가져오기 위해 생성한 각 뷰에서 지정한 각 context_object_name을 사용합니다. 쉽지 않니?

# pages/home.html
<div class="row row-cols-1 row-cols-md-2">
  {% for post in posts %}
    <div class="col mb-4">
    <div class="card h-100 bg-light">
      <div class="card-body bg-dark">
        <h3 class="card-title text-center">
        <a href="{% url 'blog-detail' post.slug %}">{{ post.title }}</a></h3>
        <img style="height: 200px; width: 100%; display: block;" src="{{ post.image.url }}" class="card-img-top" alt="...">
        <p class="card-text text-center p-3">{{ post.overview }}</p>
      </div>
      <div class="card-footer text-center">
            <small class="text-muted">{{ post.created_on }}</small><br />
          {% for category in post.categories.all %}
            <span class="p-2">
          <a href="{% url 'categories' category.title %}">
            #{{ category.title }}
          </a>
        </span>
           {% endfor %}
      </div>
    </div>
    </div>
  {% endfor %}
 </div>


범주에 대해 중첩된 for 루프가 보이십니까? for 루프를 사용하여 생성한 데이터를 반복합니다. Django가 DRY 원칙을 어떻게 활용하는지에 대해 이야기해 주시겠습니까?

게시물 세부 정보 페이지에서 각 게시물의 범주를 통해서만 반복하므로 for 루프를 사용하지 않더라도 여전히 ORM 데이터를 호출할 수 있습니다.

# pages/post_detail.html
{% load static humanize %}
<header class="container">
  <h1 class="text-center mt-5 mb-3 text-dark">{{ post.title }}</h1>
  <div class="text-center pb-3 font-weight-bold">
    <small class="text-center text-secondary">Date posted: <i>{{ post.created_on }}</i></small>
  </div>
  <div class="text-center pb-3 font-weight-bold text-secondary">
    {% for category in post.categories.all %}
    <span class="p-2">
      <a href="{% url 'categories' category.slug %}">
        #{{ category.title }}
      </a>
    </span>
    {% endfor %}
  </div>
</header>
<section class="container">
  <article>
    <div class="card mb-3 bg-light">
    <img src="{{ post.image.url }}" class="card-img-top" style="height:40vh;" alt="...">
      <div class="card-body bg-dark">
        <p class="card-text">{{ post.body|safe }} </p>
      </div>
    </div>
  </article>
</section>


category for 루프의 a 태그에서 카테고리를 호출하여 특정 게시물에서 지정한 사용 가능한 모든 카테고리를 표시하도록 반복합니다. 그런 다음 category.slug를 호출하여 요청한 게시물에 대한 올바른 URL을 얻을 수 있도록 도와줍니다.

# pages/category_list.html
<article>
  <h1 class="text-center mt-5 mb-5 text-dark">Category: {{ category | title }}</h1>
      <div class="row row-cols-1 row-cols-md-3">
        {% for post in posts %}
          <div class="col mb-4 text-center">
            <div class="card h-100 bg-light">
               <img src="{{ post.image.url }}" style="height: 200px; width: 100%; display: block;" class="card-img-top" alt="...">
                <div class="card-body bg-dark">
                  <h3 class="card-title"><a href="{% url 'blog-detail' post.slug %}">{{ post.title }}</a></h3>
                    {% for category in post.categories.all %}
                      <span class="p-1"><a href="{% url 'categories' category.slug %}">#{{ category.title }}</a></span>
                    {% endfor %}
                    <p class="card-text p-2">{{ post.overview }}</span>
                </div>
                <div class="card-footer">
                <small class="text-muted">Published on: {{ post.created_on }}</small>
             </div>
           </div>
          </div>
        {% endfor %}
      </div>
</article>


페이지/category_list.html에서 h1 태그에 쿼리하는 카테고리의 제목을 지정합니다. {{ category.title }}를 통해 매핑하여 수행했습니다. 그런 다음 for 루프를 사용하여 blog_category 함수 기반 보기를 사용하여 요청한 현재 카테고리의 게시물을 필터링합니다.

posts = Post.objects.filter(
        categories__slug__contains=category
    )


프로젝트 페이지는 다른 페이지와 동일하므로 최소한 HTML 템플릿에서 ORM을 쿼리하는 방법에 대한 기본적인 이해가 있어야 합니다.

Cookiecutter-Django에는 페이지/base.html 템플릿에 대한 경고가 포함되어 있으므로 연락처 페이지는 5줄의 코드만 사용하여 작동하도록 합니다.

{% if messages %}
  {% for message in messages %}
    <div class="alert {% if message.tags %}alert-{{ message.tags }}{% endif %}">{{ message }}<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button></div>
  {% endfor %}
{% endif %}


양식이 제출되면 알림을 표시하도록 ContactFormView에 지정했기 때문에 base.html에서 contact.html 템플릿을 확장했기 때문에 base.html 템플릿에 대한 알림을 사용합니다.

{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div>
  {% csrf_token %}
  {% crispy form %}
</div>
{% endblock content %}


그러나 양식을 제출하면 양식이 페이지에 표시되지 않고 성공 메시지만 표시되어야 합니다.



이 문제를 해결하기 위해 다음을 추가합니다.

<div class="py-5 mb-1">
  {% if messages %}

  {% else %}
<div>
  {% csrf_token %}
  {% crispy form %}
</div>
{% endif %}
</div>




base.html에서도 경고를 이동할 수 있습니다. 원한다면 하세요. 이 블로그의 새로운 기능에 대한 알림이 필요하기 때문에 하지 않을 것입니다.

양식에서 마지막으로 중요한 것은 {% csrf_token %} 템플릿 태그입니다. Cross-Site Request Forgery로부터 우리를 보호하기 위해 Django가 제공하는 가장 간단한 방법입니다.

Django's documentation에 따르면 이러한 유형의 공격은 악의적인 웹 사이트에 방문하는 로그인한 사용자의 자격 증명을 사용하여 웹 사이트에서 일부 작업을 수행하도록 의도된 링크, 양식 버튼 또는 일부 JavaScript가 포함된 악의적인 웹 사이트에서 발생합니다. 브라우저의 사이트. 또한 잠시 후에 표시할 명령을 실행한 후 프로젝트를 포함하지 않으면 프로젝트를 Heroku에 한 번 배포할 수 없습니다.

좋은 웹페이지 즐겨찾기