7.[drf] 프로필 앱 만들기

기본앱

  • 간단하고 기본적인 앱을 만들어보겠습니다.
  • 다른 종류의 앱을 만든다고 해도 구조를 참고할 수 있습니다.

프로필 앱

  • 공식에서는 User와 Profile의 역할을 분리하는 걸 추천하는 편입니다
  • Profile쪽을 만들게 되면 괜히 테이블이 하나 더 생성되는 것 같아 개인적으로 선호하는 편은 아니지만 필요할 경우 참조합니다.

models.py

from django.contrib.auth import get_user_model
from django.db import models
from django.utils.translation import gettext_lazy as _

from django_countries.fields import CoutryField
from phonenumber_field.modelfields import PhoneNumberField

from core_apps.common.models import TimeStampedUUIDModel
User = get_user_model()

class Profile(TimeStampUUIDModel):
    class Gender(models.TextChoices):
        MALE = "male", _("male")
        FEMALE = "female", _("male")
        OTHER = "other", _("other")

    user = models.OneToOneField(User, related_name={}. on_delete=models.CASCADE)
    phone_number = PhoneNumberField(verbose_name="", max_length=30, default="+250784123456", ),
    about_me = models.TextField(
        verbose_name = _("about me"),
        default="say something about yourself",
    )

    gender = models.CharField(
        verbose_name = _("gender").
        choices = Gender.choices,
        default = Gender.OTHER,
        max_length=20,
    )
    contry = CountryField(
        verbose_name = _("country"), default="KE", blank=False, null=False
    )
    city = models.CharField(
        verbose_name=_("city"),
        max_length=180,
        default="Nairobi",
        blank=False,
        null=False,
    )
profile_photo = models.ImageField(verbose_name=_("profile photo"), default="/profile_default.png")
twitter_handle = models.CharField(
    verbose_name = _("twitter_handle"), max_length=20, blank=True
)
follows = models.ManyToManyField("self", symmetrical=False, related_name="followed_by", blank=True)

def __str__(self):
    return f"{self.user.username}'s profile"

def following_list(self):
    return self.follows.all()

def followers_list(self):
    return self.followed_by.all()

def follow(self, profile):
    self.follows.add(profile)

def unfollow(self, profile):
    self.follows.remove(profile)

def check_following(self, profile)
    return self.follows.filter(pkid=profile.pkid).exists()

def check_is_followed_by(self, profile)
    return self.followed_by.filter(pkid=profile.pkid).exists()-
  • manytomany symetrical=False 페이스북 친구를 추가 할 경우 서로 친구가 되는 관계
  • 친구추가를 할 경우 서로 친구가 되는것이 아니라 친구를 추가 한 쪽에서만 친구의 관계가 되는 것

signals.py

import logging

from django.db.models.signals import post_save
from django.dispatch import receiver
from authors_api.settings.base import AUTH_USER_MODEL

from core_apps.profiles.models import Profile

logger = logging.getLogger(__name__)

@receiver(post_save, sender=AUTH_USER_MODEL)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)

@receiver(post_save, sender=AUTH_USER_MODEL)
def save_user_profile(sender, instance, **kwargs):
    instance.profile.save()
    logger.info(f"{instance}'s profile created")

apps.py

from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _

class ProfilesConfig(AppConfig):
    default_auto_field = "django.db.models.BigAutoField"
    name = "profiles"
    verbose_name = _("Profiles")

def ready(self):
    from core_apps.profiles import signals

admin.py

from django.contrib import admin
from .models import Profile

class ProfileAdmin(admin.ModelAdmin):
    list_display = ["pkid", "id", "user", "gender", "phonenumber", "country", "city"]
    list_filter = ["gender", "country", "city"]
    list_display_links= ['id', 'pkid']

admin.site.register(Profile.ProfileAdmin)

serializer.py

from phonenumber_field.serializerfields import PhoneNumberField
from rest_framework import serializers
from rest_framework import serializers

User = get_user_model()

class UserSerializer(serizlizers.ModelSerializer):
    gender = serializers.CharField(source="profile.gender")
    phone_number = PhoneNumberField(source="profile.phone_number")
    profile_photo = serializers.ReadOnlyField(source="profile.profile_photo")
    country = CountryField(source ="profile.country")
    city = serializers.CharField(source="profile.city

class Meta:
    model = User
    fields = (
        "id",
        "username",
        "email",
        "first_name",
        "last_name",
        "full_name",
        "gender",
        "phone_number",
        "profile_photo",
        "country",
        "city"
)

def get_first_name(self.obj):
    return obj.first_name.title()

def get_last_name(self.obj):
    return obj.last_name.title()

def get_full_name(self.obj):
    first_name = obj.user.first_name.title()
    last_name = obj.user.last_name.title()
    return f"{first_name} {last_name}"

def to_representation(self, instance):
    representation = super(UserSerializer, self).to_representation(instance)
    if instance.is_superuser:
        representation["admin"] = True
    return representation

class CreateUserSerializer(UserCreateSerializer):
    class Meta(UserCreateSerializer.Meta):
        model = User
        fields = ["id", "username", "email", "name", "password"]

renderers.py 왜 있는지 모르겠음

import json

from rest_framework.renderers import JSONRenderer

class ProfileJSONRenderer(JSONRenderer):
        charset = "utf-8"

def render(self, data, accepted_media_type= None, renderer_context=None):
    status_code = renderer_context["response"].status_code
    errors = data.get("errors", None)
    if errors is not None:
        return super(ProfileJSONRenderer, self).render(data)
    return json.dumps({"status_code": status_code, "profile": data})

Did you find this article valuable?

Support Fullstack Developer at Your Service by becoming a sponsor. Any amount is appreciated!