비SPA방식 유저페이지 구현 참고

duo2208·2022년 1월 11일
0

Django

목록 보기
11/23
post-thumbnail

유저 페이지 구현 참고


models.py

avatar_url() 메서드는 회원가입 유저가 아바타 이미지를 업로드 하였을 경우 업로드한 이미지의 주소를 리턴하고, 업로드하지 않았으면 pydenticon_image 의 이미지 주소를 리턴한다.

다른 곳에서 유효성 검사를 하지 말고, 자주 쓰이니 @property 데코레이터를 이용하여 모델단에 메서드를 구현한다.

from django.conf import settings
from django.contrib.auth.models import AbstractUser
from django.core.mail import send_mail
from django.core.validators import RegexValidator
from django.db import models
from django.template.loader import render_to_string
from django.shortcuts import resolve_url

# Create your models here.
class User(AbstractUser):
    class GenderChoices(models.TextChoices):
        MALE = "M", "Male"
        FEMALE = "F", "Female"

    website_url = models.URLField(blank=True)
    bio = models.TextField(blank=True)
    phone_number = models.CharField(max_length=13, blank=True, validators=[RegexValidator(r"^010-?[1-9]\d{3}-?\d{4}$")])
    gender = models.CharField(max_length=1, blank=True, choices=GenderChoices.choices)
    avatar = models.ImageField(blank=True, upload_to='accounts/profile/%Y/%m/%d', help_text="48px * 48px 크기의 파일을 업로드해주세요.")

    @property
    def name(self):
        return f"{self.first_name} {self.last_name}"

    @property
    def avatar_url(self):
        if self.avatar:
            return self.avatar.url
        else:
            return resolve_url("pydenticon_image", self.username)

    def send_welcome_email(self):
        # 중략

urls.py

# instagram/urls.py
from django.urls import path, re_path
from . import views

app_name = 'instagram'

urlpatterns = [
    ... 중략
    re_path(r'^(?P<username>[\w.@+-]+)/$',
    views.user_page, name='user_page'),
]

views.py

len(post_list) 는 post_list 전체를 다 가져와서 메모리에 얹은 다음에 메모리상의 리스트의 갯수를 반환하므로 상대적으로 느리다.

# instagram/views.py
def user_page(request, username):
    # urls.py에서 넘겨받은 username이 
    # logined된 User가 가진 필드에 존재하는가를 체크해야 한다.
    page_user = get_object_or_404(get_user_model(), username=username, is_active=True)  # is_active로 접근이 허용된 사람이 아니면 404
    post_list = Post.objects.filter(author=page_user)
    post_list_count = len(post_list)

    return render(request, "instagramsns/user_page.html",{
        "page_user": page_user,
        "post_list": post_list,
        "post_list_count": post_list_count,
    })

post_list_count() 는 실데 DB에 count 쿼리를 던지므로 상대적으로 빠르다.

# instagram/views.py
def user_page(request, username):
    # urls.py에서 넘겨받은 username이 
    # logined된 User가 가진 필드에 존재하는가를 체크해야 한다.
    page_user = get_object_or_404(get_user_model(), username=username, is_active=True)  # is_active로 접근이 허용된 사람이 아니면 404
    post_list = Post.objects.filter(author=page_user)
    post_list_count = post_list.count() 
    
    return render(request, "instagramsns/user_page.html",{
        "page_user": page_user,
        "post_list": post_list,
        "post_list_count": post_list_count,
    })

user_page.html

easy-thumnails 를 이용하여 원본 이미지를 CROP 할 경우, 원본 이미지의 크기가 512x512 보다 작을 경우 고정된 크기의 썸네일을 제공하지 못하는 문제가 있다.

# instagram/templates/user_page.html
{% extends "instagramsns/layout.html" %}
{% load thumbnail %}

{% block content %}

    <div class="container">
        <div class="row pt-5 pb-5">
            <div class="col-sm-3" style="text-align: center;">
                <img src="{{ user.avatar_url }}" class="rounded-circle" style="width: 160px; height: 160px;" />
            </div>

            <div class="col-sm-9">
                {{ page_user.username }}    <!--user.username 은 현재 로그인한 유저를 나타낸다.-->
                <a href="{% url 'profile_edit' %}" class="btn btn-outline-dark btn-sm">
                    Edit Profile
                </a>
                <hr>
                {{ post_list_count }} posts, 0 fllowers, 0 following
                <hr>
                {{ page_user.username }}
            </div>
        </div>

        <div class="row mt-3">
            {% for post in post_list %}
                <div class="col-sm-4 mb-3">
                    <img src="{% thumbnail post.photo 512x512 crop %}" alt="{{ post.caption }}" style="width: 100%;" />
                </div>
            {% endfor %}
        </div>

    </div>

0개의 댓글