7.[drf] 프로필 앱 만들기
기본앱
- 간단하고 기본적인 앱을 만들어보겠습니다.
- 다른 종류의 앱을 만든다고 해도 구조를 참고할 수 있습니다.
프로필 앱
- 공식에서는 User와 Profile의 역할을 분리하는 걸 추천하는 편입니다
- Profile쪽을 만들게 되면 괜히 테이블이 하나 더 생성되는 것 같아 개인적으로 선호하는 편은 아니지만 필요할 경우 참조합니다.
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 페이스북 친구를 추가 할 경우 서로 친구가 되는 관계
- 친구추가를 할 경우 서로 친구가 되는것이 아니라 친구를 추가 한 쪽에서만 친구의 관계가 되는 것
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")
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
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)
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})