목표
https://yellowdonkey0329.blogspot.com/2018/12/django-django-allauth.html 로부 터확장하여, UserModel을 확장하고자 한다.
몇가지 필드만 추가 할 예정이므로, one-to-one mapping을 이요한 UserModel확장방법을 해본다.
보안 필요
핵심흐름
0. ProfileModel을 만든다 (OneToOneField으로 User와 연결한다)
1. allauth의 signup을 사용하지 않게 하지위해, urls.py를 수정후 (allauth보다 이전), view로 이동하게 한다.
2. ProfileForm을 ProfileModel을 가지고 만든다.
3. view에서 기존의 form과 확장된 form (Profile)을 같이 처리 해준다.
4. templates에서의 구성
5. 기타
- form field를 hidden 시키는것
https://stackoverflow.com/questions/6862250/change-a-django-form-field-to-a-hidden-field
- form.is_valid()에서 실패 할경우
return self.render_to_response(self.get_context_data(form=form)) 사용 가능
고민해봐야 하는 점
1) 처리 하는 방법은 원래의 form(SingupForm)과 확장된 form (ProfileForm)을 동시에 다루어 각각 저장 하는 방법이 있을수 있고, 2) 하나의 form을 새로 만들어 model을 두개(User그리고 Profile models)을 우겨 넣는 방법이 있을수 있을것 같은데, 처음에는 2)으로 시도 하다가 대부분의 사이트에서 1)을 사용하고 있고, 또 기존의 User logic 을 수정없이 진행하기 위해 1)방식을 사용.
또한 대부분은 class view 방식을 사용 하는것이 아니라, function방식을 하는 예제여서 바로 적용 하기 힘들었음. 다행히 https://medium.com/@EmadMokhtar/extend-django-user-model-and-gcbv-4745ab901ba 이것을 참조하였음.
Model을 사용 하는데 있어서도 추가될 field를 가지고 있는 ProfileModel에 user을 OneToOneField으로 연결후 그 ProfileModel을 사용 하여 form을 구성 하는 방법이 있을것 같은데, 시도 해 보지 못하였음 (https://medium.com/@EmadMokhtar/extend-django-user-model-and-gcbv-4745ab901ba 여기서는 Teacher model의 역할)
두개로 모델이 분리 되어 있어 form을 저장할때도 atomic을 유지 하는것이 여간 번거롭지 않다. 잘못 commit되었을때도 rollback시켜야 하는데 어렵다.
관련링크
- https://simpleisbetterthancomplex.com/tutorial/2016/07/22/how-to-extend-django-user-model.html
- https://cjh5414.github.io/extending-user-model-using-one-to-one-link/
- https://medium.com/@EmadMokhtar/extend-django-user-model-and-gcbv-4745ab901ba
- http://www.joshuakehn.com/2013/7/18/multiple-django-forms-in-one-form.html
- https://stackoverflow.com/questions/2770810/multiple-models-in-a-single-django-modelform (두개의 Form을 사용 할때 문제 되면 prefix 사용)
- http://whatisthenext.tistory.com/118 (one-to-one mapping에 관한 유용한글)
0. ProfileModel을 만든다 (OneToOneField으로 User와 연결한다)
1. allauth의 signup을 사용하지 않게 하지위해, urls.py를 수정후 (allauth보다 이전), view로 이동하게 한다.
2. ProfileForm을 ProfileModel을 가지고 만든다.
3. view에서 기존의 form과 확장된 form (Profile)을 같이 처리 해준다.
4. templates에서의 구성
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
us = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(max_length=300, blank=True)
location = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
def __unicode__(self):
return self.us.username
| cs |
# all-auth
url(r'^accounts/signup/$', NewSignupView.as_view(), name='signup'),
url(r'^accounts/', include('allauth.urls')),
| cs |
2. ProfileForm을 ProfileModel을 가지고 만든다.
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ("location","birth_date")
| cs |
3. view에서 기존의 form과 확장된 form (Profile)을 같이 처리 해준다.
from allauth.account.views import SignupView
from login_ext.forms import ProfileForm
class NewSignupView(SignupView):
second_form_class = ProfileForm
def get_context_data(self, **kwargs):
# Get the context
context = super(NewSignupView, self).get_context_data(**kwargs)
# Adding the second form
context['profile_form'] = self.second_form_class
return context
def form_valid(self, form):
profile_form = ProfileForm(self.request.POST) #bind vs unbind FORM : using POST
self.second_form_class = profile_form #In case that is_valid() is false,
if profile_form.is_valid():
ret = super(NewSignupView, self).form_valid(form)
profile_form.instance.us = self.user
profile_form.save()
return ret
else:
return self.render_to_response(self.get_context_data(form=form))
| cs |
4. templates에서의 구성
<form class="signup" id="signup_form" method="post" action="{% url 'account_signup' %}">
{% csrf_token %}
{{ form.as_p }}
{{ profile_form.as_p }}
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}
<button type="submit">{% trans "Sign Up" %} »</button>
</form>
| cs |
댓글 없음:
댓글 쓰기