장고 - 관리자 사이트의 결제 정보 PDF 파일

  • 온라인 쇼핑몰 사이트의 경우, 관리자페이지에서 고객의 결제 정보를 PDF로 저장하는 경우가 있다.
  • 이번 포스트에서는 온라인 쇼핑몰 사이트를 예로 들어 관리자 사이트에서 고객이 주문한 상품정보를 PDF 파일로 조회 및 다운로드하는 방법에 대해 다룰 것이다.

1. Weasyprint 설치

ex) wps-onlineshop 프로젝트

  • 경로 : wps-onlineshop
    1
    pip install weasyprint

2. Weasyprint 실행

  • 경로 : wps-onlineshop
    1
    python -m weasyprint http://weasyprint.org weasyprint.pdf

3. 관리자 사이트에서 PDF 링크 설정

  • 경로 : wps-onlineshop > order > admin.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from django.utils.safestring import mark_safe

    def order_pdf(obj):
    # pdf 파일 뷰로 가는 링크
    url = resolve_url('admin_order_pdf', obj.id)
    # mark_safe를 사용하여 텍스트를 html 형태로 변환
    return mark_safe(f'<a href="{url}" target="_blank">pdf</a>')

    # 관리자페이지에서 링크로 연결되어지는 문구를 'PDF'로 설정
    order_pdf.short_description = 'PDF'

4. PDF 클릭 시, 이동할 페이지 경로 설정

  • 경로 : order > urls.py
    1
    2
    3
    4
    5
    6
    from django.urls import path

    from .views import *
    urlpatterns = [
    path('admin/pdf/<int:order_id>/', admin_order_pdf, name='admin_order_pdf'),
    ]

5. PDF 파일에서 보여지는 내용 작성

  • 경로 : order > views.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    from django.contrib.admin.views.decorators import staff_member_required
    from django.template.loader import render_to_string
    from django.http import HttpResponse
    import weasyprint
    # 유저가 로그인했다면, 그 유저가 관리자인지 확인하여 관리자가 아니라면 기존 요청한 주소로 이동되도록 @staff_member_required 사용
    @staff_member_required
    def admin_order_pdf(request, order_id):
    order = get_object_or_404(Order, id=order_id)
    html = render_to_string('order/admin/pdf.html', {'order':order})
    response = HttpResponse(content_type='application/pdf')
    response['Content-Disposition'] = f'filename=invoice_{order.id}.pdf'
    weasyprint.HTML(string=html).write_pdf(response)
    return response
  • 경로 : order > templates > order > admin > pdf.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    <html>
    <body>
    <h1>WPS Onlineshop</h1>
    <p>
    Invoice no. {{ order.id }}</br>
    <span class="secondary">{{ order.created|date:"M d, Y" }}</span>
    </p>

    <h3>{% if order.paid %}Payment Accepted{% else %}Pending payment{% endif %}</h3>
    <p>
    {{ order.first_name }} {{ order.last_name }}<br>
    {{ order.email }}<br>
    {{ order.address }}<br>
    {{ order.postal_code }}, {{ order.city }}
    </p>

    <h3>Product List</h3>
    <table>
    <thead>
    <tr>
    <th>Product</th>
    <th>Price</th>
    <th>Quantity</th>
    <th>Cost</th>
    </tr>
    </thead>
    <tbody>
    {% for item in order.items.all %}
    <tr class="row{% cycle '1' '2' %}">
    <td>{{ item.product.name }}</td>
    <td class="num">${{ item.price }}</td>
    <td class="num">{{ item.quantity }}</td>
    <td class="num">${{ item.get_item_price }}</td>
    </tr>
    {% endfor %}
    {% if order.coupon %}
    <tr class="discount">
    <td colspan="3">Discount</td>
    <td class="num">${{ order.discount }}</td>
    </tr>
    {% endif %}
    <tr class="total">
    <td colspan="3">Total</td>
    <td class="num">${{ order.get_total_price }}</td>
    </tr>
    </tbody>
    </table>
    </body>
    </html>

6. 관리자 사이트에 보여질 항목에 pdf 항목 추가

  • 경로 : order > admin.py

    1
    2
    3
    4
    5
    class OrderOption(admin.ModelAdmin):
    # 관리자 사이트 항목에 'order_pdf' 추가
    list_display = ['id','first_name','last_name','email','paid', order_pdf, 'created','updated']

    admin.site.register(Order, OrderOption)
  • 경로 : order > models.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    # order 모델 참고
    from django.db import models
    class Order(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    email = models.EmailField()

    address1 = models.CharField(max_length=100)
    address2 = models.CharField(max_length=100)
    city = models.CharField(max_length=50)
    postal_code = models.CharField(max_length=20)

    created = models.DateTimeField(auto_now_add=True )
    updated = models.DateTimeField(auto_now=True)

    paid = models.BooleanField(default=False)
    # 결제 시도 전에 주문을 먼저 생성한다.

    class Meta:
    ordering = ['-updaed']