현재 이력서 앱을 만들고 있습니다.

근데 막히는 부분이 많네요...


이번에는 1:N 관계로 설정된 모델 클래스들을 뷰로 어떻게 가져와서 입력을 시킬 것인가에 대한 문제입니다....ㅠㅜ


현재 1:N 관계로 모델에는 다음과 같이 설정이 되어 있습니다. 

인적 사항 (Resume) 1 ------ N 학력, 경력, 병역, 직무, 기술 필드로 각각 설정되어 있습니다. 



forms.py

class ResumeForm(forms.ModelForm):
    class Meta:
        model = Resume
        fields = ['user', 'occupation', 'current_salary', 'hope_salary']


class EducationForm(forms.ModelForm):
    class Meta:
        model = Education
        fields = ['colleage_name', 'is_overseas', 'major', 'start_date', 'completion_date', 'grade']


class CareerForm(forms.ModelForm):
    class Meta:
        model = JobCareer
        fields = ['company', 'partname', 'position', 'duty',
                  'start_date', 'is_current', 'completion_date',
                  'job', 'description']


class LicenceForm(forms.ModelForm):
    class Meta:
        model = License
        fields = ['name', 'rank', 'publishing', 'get_date']


class TrainingForm(forms.ModelForm):
    class Meta:
        model = Training
        fields = ['title', 'place']

 이런식으로 모든 외래키 참조 모델필드를 가져와서 뷰에서 이런 형식으로 넘기고 있는데 이게 맞는건지는 잘 모르겠네요... 


views.py

def resume(request):
    user_form = ResumeForm(request.POST or None)
    edu_form = EducationForm(request.POST or None)
    career_form = CareerForm(request.POST or None)
    license_form = LicenceForm(request.POST or None)
    military_form = MilitaryForm(request.POST or None)
    training_form = TrainingForm(request.POST or None)

    if user_form.is_valid():

        user = user_form.save(commit=False)
        edu = edu_form.save(commit=False)
        career = career_form.save(commit=False)
        license = license_form.save(commit=False)
        military = military_form.save(commit=False)
        training = training_form.save(commit=False)

        user.save()

        edu.user = user
        edu.save()

        career.user = user
        career.save()

        license.user = user
        license.save()

        military.user = user
        military.save()

        training.user = user
        training.save()

        return HttpResponseRedirect('/accounts/resume_list.html')

    template = 'accounts/resume_form.html'

    context = {
        'form': user_form,
        'edu_form': edu_form,
        'career': career_form,
        'license': license_form,
        'military': military_form,
        'training': training_form

    }
    return render(request, template, context)

많은 곳을 뒤져 봐도 외래키 필드에도 입력을 받을 수 있게 하는 곳은 찾기가 어려운 듯합니다. 

좋은 의견 주시면 감사하겠습니다. 

문제 



모델에 MyUser, ActivationProfile, Profile 이렇게 3개 테이블이 있는데 모두 MyUser 모델과 관계를 맺고 있습니다. 

MyUserModel에 User정보가 등록이 되면 그에 따라서 ActivationProfile과, Profile 오프젝트가 생성이 되도록 하는데 왜 외래키를 참조하고 있는 모델들이 오브젝트 생성이 안되는 현상입니다. 


해결 


외래키로 연결을 하고 있는 Pofile 에 email, phone에 'unique=True' 라는 옵션을 제거합니다. 

옵션하나로 ... 문제가 쉽게 해결이 되네요.  


Model.py 

class MyUserManager(BaseUserManager): def create_user(self, username, phone, email, password=None): """ Creates and saves a User with the given email, date of birth and password. """ if not email: raise ValueError('Users must have an email address') user = self.model( username = username, phone = phone, email=self.normalize_email(email), ) user.set_password(password) user.save(using=self._db) return user def create_superuser(self, username, phone, email, password): """ Creates and saves a superuser with the given email, date of birth and password. """ user = self.create_user( username, phone, email, password=password, ) user.is_admin = True user.is_staff = True user.save(using=self._db) return user class MyUser(AbstractBaseUser): username = models.CharField(max_length=100, unique=True) email = models.EmailField( verbose_name='email address', max_length=255, unique=True, ) phone = models.CharField(max_length=15, unique=True) is_active = models.BooleanField(default=True) is_staff = models.BooleanField(default=False) is_admin = models.BooleanField(default=False) objects = MyUserManager() USERNAME_FIELD = 'username' REQUIRED_FIELDS = ['phone','email'] def __str__(self): return self.username def has_perm(self, perm, obj=None): "Does the user have a specific permission?" # Simplest possible answer: Yes, always return True def has_module_perms(self, app_label): "Does the user have permissions to view the app `app_label`?" # Simplest possible answer: Yes, always return True class ActivationProfile(models.Model): user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) key = models.CharField(max_length=120) expired = models.BooleanField(default=False) def save(self, *args, **kwargs): self.key = code_generator() super(ActivationProfile, self).save(*args, **kwargs) def post_save_activation_receiver(sender, instance, created, *args, **kwargs): if created: #send Email print('id activation created') url = "/activate" + instance.key post_save.connect(post_save_activation_receiver, sender=ActivationProfile) class Profile(models.Model): user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, primary_key=True,) phone = models.CharField(max_length=15, unique=True) # 오류 발생 unique key 삭제 email = models.EmailField(max_length=255, unique=True) # 오류 발생 unique key 삭제 def __str__(self): return str(self.user.username) def post_save_user_model_receiver(sender, instance, created, *args, **kwargs): if created: try: #이곳이 문제 Profile.objects.create(user=instance) ActivationProfile.objects.create(user=instance) except: print(settings.AUTH_USER_MODEL) post_save.connect(post_save_user_model_receiver, sender=settings.AUTH_USER_MODEL)


하하... 이 오류 찾는데 하루... 

저번에는 순환참조가 말썽이더니 이번에는 url관련.. 문제가 저를 괴롭히네요.

일단 에러 메세지는 다음과 같이 나옵니다. 

분명 매칭 url이 없을때 NoreverseMatch에러가 나오는 것으로 알고 있는데... 설정은 잘 맞게 한것 같은데 해결이 안됩니다.



에러메세지는 다음과 같습니다.





Models.py
from django.db import models
from django.urls import reverse
from django.db.models.signals import pre_save, post_save
from django.utils.text import slugify

class CompanyModel(models.Model):
    cmp_name = models.CharField(max_length=100)
    cmp_descript = models.TextField()
    cmp_email = models.EmailField()
    slug = models.SlugField(max_length=128)
    updated = models.DateTimeField(auto_now_add=True, auto_now=False)

    def __str__(self):
        return self.cmp_name

    def get_absolute_url(self): # reverse 함수 설정 *************
        return reverse('company_detail', kwargs={"slug":self.slug})
Views.py
from django.shortcuts import render
from .forms import CompanyForm
from .models import CompanyModel
from django.contrib.auth.decorators import login_required
from django.views.generic.base import TemplateView
from django.views.generic.detail import DetailView
from django.views.generic.list import ListView
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.urls import reverse


class CmpCreate(CreateView):
    form_class = CompanyForm
    template_name = "create.html"
    fields = ["cmp_name", "cmp_email", c"cmp_descript"]

    def get_success_url(self):
        return reverse("company-list")

class CompanyUpdateView(UpdateView):
    form_class = CompanyForm
    template_name = "create.html"

class CmpDetail(DetailView): #DetailView 설정
    model = CompanyModel

class CmpListView(ListView):
    model = CompanyModel
urls.py
from django.views.generic.base import TemplateView
from .views import DashboardTemplateView, CmpDetail, CmpListView, CmpCreate, CompanyUpdateView
from django.conf.urls import include
from django.urls import path
from . import views

#보기 편하게 하기 위해서 나머지 불필요한 url은 모두 주석처리 했습니다. 
urlpatterns = [
    #path('', views.home, name='home'),
    #path('about/', TemplateView.as_view(template_name="about.html"), name="about"),
    # path('about2/', DashboardTemplateView.as_view(), name='dashboard'),
    #path('company/create/', CmpCreate.as_view(), name="company-create"),
    #path('company/', CmpListView.as_view(), name="company-list"),
    path('company//', CmpDetail.as_view(), name="company_detail"), #디테일 뷰 slug를 찾지 못함. ********
    #path('company//update', CompanyUpdateView.as_view(), name="company_update"),
    #path('login/', TemplateView.as_view(template_name="login.html"), name="login"),
    #path('accounts/', include('registration.backends.default.urls')),
    #path('contact/', views.contact, name="contact")
]

분명 get_absolute_url 을 설정하고 그것을 자연스럽게 urls.py로 넘겨줬는데 왜 ReverseMatch 에러가 나는지 잘 이해를 하지 못하겠습니다... 도대체... 왜 그럴까요..ㅠㅜ




문제해결..


이번 문제도 너무나도 간단하게 풀려버렸습니다. askDjango의 이진석 님께서 조언을 해주셨는데요. 


Slug 필드를 확인을 해보았습니다. 



위 사진과 같이 SLUG 필드가 한개 빠져있더군요.


영문으로 쓰면 그것을 slugify로 변환을해서 저장을 하는데... 한글은 그게 안되는 것이였음.

하하.... 그래서 slug를 가져오지 못해서 에러가 나더군요. 


만약 한글로 저장을 하게 된다면 숫자로라도 Slug필드를 넣어야 겠습니다. 읕...


장고를 나도 처음 사용해 보는 거라 Registration Redux를 적용할때 참... 이해가 가지 않는 몇몇 부분이 있다. 이번에도 register부분에서 에러가 났는데, 해결방법은 이것저것 찾아보니 Setting에 Email 세팅을 안했더라...


Setting.py

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' 를 추가 


Register 를 등록할떄 왜 Email 셋팅이 필요한가 했는데... 가입을 할 때 Email 인증이 필요하기 때문.



이후 관리자 페이지에서 해당 아이디에 대한 인증값을 복사한뒤

 

http://127.0.0.1:8000/accounts/activate/17d2f950ecf031a0d939bfb854703a669eebef97


해당 계정을 활성화 시키면 됨. 

이 과정은 아마도 계정 이메일을 셋팅하고 설정을 하면 되지만, local 단계에서는 이해정도로 빨리 습득을 해야 하기 때문에 실제 이메일 Sent는 하지 않았음.



참... 편리하게 만들어놨네.


ModuleNotFoundError: No module named 'helloeb2.settings'





AWS 나 다른 환경으로 배포하기 위해 settings.py 를 분기시켜야 한다. 


그런데 말입니다. 



1. 기존 settins.py 외 settings 폴더를 생성한다.

2. settings 폴더내 common, dev, prod 파일을 생성한다. 

3. 이후 common 파일에 기존 settings 파일의 내용을 복사하고 settings 파일 삭제

4.  최상단 manage.py 의 settings 경로를 settings/dev 로 수정한다. 



그리고 


ModuleNotFoundError: No module named 'helloeb2.settings'


이 에러가 뜬다. 

분명 다른 사람들은 이렇게 하면 잘만 되던데 왜 나만... ㅅㅂ... 


분명 manage.py에서 수정을 해줬는데도  기존 settings.py을 찾는 이유는 뭘까 ? 

음 ... 몇군데 찾아보니 이유에 대한 원인을 몇가지 찾을 수 있었다. 


1., 분기전 migrations을 하면서 데이터 저장 부분이 settings를 참조하고 있거나

=> 다른 프로젝트를 만들어서 똑같이 해봤지만 에러. 마이그레이션 문제는 아닌듯 하다.


2. 상위 루트 폴더인 helloeb2  부분을 헷갈려서 에러가 나거나

=> 상위 폴더 이름을 변경해봤는데 그래도 오류가 난다. 


3. 장고 버전이 안맞아서 그런다 ?

=> 장고 2.0으로 업데이트 했으나 같은 현상이 일어났다. 





해결책. 



근데 해결은 비교적 간단하게.. . 이렇게 쉽게 풀리다니


os.environ.setdefault("DJANGO_SETTINGS_MODULE", 'helloeb2.settings.dev')

에서


os.environ.setdefault("DJANGO_SETTINGS_MODULE", 'settings.dev')


이렇게 하니 작동을 한다. 


어떤 이유인지는 모르겠으나 상위 디렉토리를 제거하면 된다. 

하... 2시간 날렸네.. 






나의 삽질로 남들의 시간이 단축 될 수 있다면 ... 

글 보고 해결되셨다면 댓글 하나씩만 남겨주세요. 



최근 장고라는 프레임 워크로 갈아타면서 엄청나게 삽질을 해대고 있는 중이다.. 


장고프레임 워크는 파이썬을 웹으로 만들어 줄수 있는 툴인데, 내가 그동안 해왔던 자바, C++과는 또 다른 매력이 있는 소프트웨어인듯 하다. 



지금 내가 공부를 하고 있는 방법은 Udemy와 Nomade 라는 사이트를 이용해서 공부를 하고 있는데, 정말 ... 쉽지 않다. 


기본적인 웹상의 구조를 알고 있음에도 불구하고 너무도 다른 양식의 툴을 접하니..  지금 10일째 삽질만 ... 





1. 프로젝트 진행을 배울 수 있는 좋은 강의:  Udemy.com


하지만 자세히 이것들이 어떻게 동작이 되고 왜 이렇게 되는지는 강의를 들어도 잘 모르겠다. 


내가 영어를 못해서 못 알아 듣는 것일 수도 있고... ㅋㅋ 


자세히 하나하나의 원리를 알 고 싶다면 nomade.kr의 강의를 듣는 것을 추천.





2. 한국 대표 장고 강의 사이트 :  Nomade.kr


 진짜 장고의 '장'자도 모르는 내가 이 강의를 들으면서 조금씩 장고 웹 개발에 대한 이해를 높이고 있다. 


이 사이트 강의의 장점은 장고 웹 구조의 하나하나에 대한 자세한 설명과 이해가 있다는 부분이다. 


하지만 Udemy 사이트의 강의와는 다르게 조금 강의의 평균 시간이 약 30분이다. 


길다면 길수 있지만 다양한 것들을 많이 배울 수 있어서 좋음. (30일 구독 5만원, 60일 구독 9만원)





Udemy 사이트는 할인을 많이 하기 때문에 최저가로 사면 12,000원 정도에 강의를 볼 수 있지만, Nomade 는 유데미에 비하면 가격이 조금은 있는 편이다. 


하지만 5만원 정도에 이런 지식을 배울 수 있다는 것은... 사실 싼편이라고 생각한다. 


한국인은 역시 한국어로 된 강의를 들어야 됨...




아직 장고를 시작한지 한달이 채 되지도 않았지만 조금씩 감을 익혀가는 중이다. 


언젠간 나도 이진석 대표님 만큼 장고를 다룰 날이 오겠지.... 



노력합시다.