본문 바로가기
기타/django

작정하고 장고 - profile 구현

by 방배킹 2023. 5. 20.

Profileapp 시작 그리고 ModelForm

 

python manage.py startapp profileapp 명령어를 통해 profileapp을 만든다.

그리고 settings.py에 다음과 같이 profileapp을 추가해준다.

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'bootstrap4',
    'accountapp',
    'profileapp',
]

마찬가지로 urls.py에도 profileapp에 대한 정보를 추가해준다.

urlpatterns = [
    path('admin/', admin.site.urls),
    path('accounts/', include('accountapp.urls')),
    path('profiles/', include('profileapp.urls')),
]

models.py에 모델을 만들어준다.

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile') # User가 탈퇴하면 Profile도 사라짐
    image = models.ImageField(upload_to='profile/', null=True)
    nickname = models.CharField(max_length=20, unique=True, null=True)
    message = models.CharField(max_length=100, null=True)

account는 django에서 기본적으로 제공해주는 form이 있었지만,
profile은 기본적으로 제공해주는 form이 없어 직접 만들어야한다.

새로운 form을 만들어서 사용하면된다, 직접 form을 만드는것 보다 기존의 model을 form으로 변환해주는 ModelForm이라는게 존재하는데 더 편하하므로 ModelForm을 사용하자.

forms.py를 만들어주고 ModelForm을 상속받아 어떤 Model을 사용하고 어떤 field를 사용하지 코드로 작성해주자.

class ProfileCreationForm(ModelForm):
    class Meta:
        model = Profile
        fields = ['image', 'nickname', 'message']

profileapp 구현 시작

우선 model을 만들었으니 database에 적용시켜주는 작업이 필요하다.

 

다음과 같이 database에 적용시켜주자.

profileapp의 views.py에 createview를 만들어준다.

class ProfileCreateView(CreateView):
    model = Profile
    context_object_name = 'target_profile'
    form_class = ProfileCreationForm
    success_url = reverse_lazy('accountapp:hello_world')
    template_name = 'profileapp/create.html'

view를 만들었으면 url을 설정과 create.html을 만들어준다.

app_name = 'profileapp'

urlpatterns = [
    path('create/', ProfileCreateView.as_view(), name='create')
]
{% extends 'base.html' %}
{% load bootstrap4 %}

{% block content %}

  <div style="text-align: center; max-width: 500px; margin: 4rem auto">
    <div class="mb-4">
      <h4>Profile Create</h4>
    </div>
    <form action="{% url 'profileapp:create' %}" method="post">
      {% csrf_token %}
      {% bootstrap_form form %}
      <input type="submit" class="btn btn-dark rounded-pill col-6 mt-3">
    </form>
  </div>

{% endblock %}

그리고 http://127.0.0.1:8000/profiles/create/에 접속하면


다음과 같은 화면이 나온다.

프로필을 설정할 수 있도록 해당 페이지로 이동할 수 있도록 해줘야 하므로

detail.html에서 만약 profile이 없다면 해당 페이지로 갈수 있는 링크를 띄워준다.

{% if target_user.profile %}
    <h2 style="font-family:'NanumGothic'">
      {{ target_user.profile.nickname }}
    </h2>
    {% else %}
    <a href="{% url 'profileapp:create' %}">
      <h2 style="font-family: NanumGothic">
        Create Profile
      </h2>
    </a>
    {% endif %}

만약 profile을 설정을 안했으면 위와 같이 Change Profile를 눌러 프로필을 설정할 수 있는 페이지로 이동이 가능하다.

하지만 이때 이미지파일을 등록하기 위해서는

<form action="{% url 'profileapp:create' %}" method="post" enctype="multipart/form-data">
      {% csrf_token %}
      {% bootstrap_form form %}
      <input type="submit" class="btn btn-dark rounded-pill col-6 mt-3">
    </form>

form 태그에 enctype="multipart/form-data"를 추가해줘야 한다.


그러나 여전히 문제가 발생한다.

왜나하면 model에는 user라는 field가 있는데 form에서 user의 정보를 사용하지 않았기 때문이다 (즉, 다른 사람의 profile을 설정할 수 도 있기 때문이다.)

해당 부분은 서버 내에서 구현을 할것이다.

방법은 views.py의 ProfileCreateView에 form_valid를 추가해서 해결을 할 수 있다.

    def form_valid(self, form):
        temp_profile = form.save(commit=False) #날라온 form의 정보를 일시적으로 저장 (user 정보는 없음)
        temp_profile.user = self.request.user #profile의 user를 request를 보낸 user로 설정
        temp_profile.save() #해당 정보를 저장
        return super().form_valid(form)

해당 코드를 추가해주면 다음과 같이 profile을 설정할 수 있게 된다.

댓글