[Django] 경로를 못 찾는 장고... Not Found: /

Heeyoung Joe·2023년 8월 10일
0

[Django]

목록 보기
2/3

url 오타도 아냐... 모델 import, view import 문제가 있는 것도 아냐... 왜 문제가 있는지 모르겠어서 답답할 따름인 내 코드. 차근차근 해결 시도를 해본 것을 풀어보겠다.

현 상황

파일 구조

-/wordcloud_network_web (프로젝트 폴더)
-/wordcloud (워드클라우드 앱 폴더)
-/users (사용자 앱 폴더)

사용자 앱을 따로 만들어둔 이유는 이게 데이터 분석을 진행하는 웹 애플리케이션인데 사용자 데이터가 엄청 크고 관련 작업이 많아질 것 같아 지레 겁을 먹었기 때문이다. 앱 간의 연관이 낮아야 진정한 모듈화라고 할 수 있지만... 일단은 이렇게 진행하고 있다.

프로젝트 폴더의 urls.py


urlpatterns = [
    path('admin/', admin.site.urls),
]
urlpatterns+=[path('',include('users.urls'))]

users 앱 폴더의 urls.py

urlpatterns = [
    path('', UserView.as_view(),name="users"),
]

users 앱 폴더의 views.py


class UserView(APIView):

    def get(self,request):
        users=get_list_or_404(UserModel)
        serializer=UserSerializer(users)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        else:
            print("??")
            print(UserModel.objects.filter(hierarchy="사원"))
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

users 앱 폴더의 models.py


# Create your models here.
class UserModel(models.Model):
    employeenumber=models.IntegerField()   
    name=models.CharField(max_length=100)
    age=models.IntegerField()
    hierarchy=models.CharField(max_length=100)

users 앱 폴더의 serializers.py


class UserSerializer(serializers.ModelSerializer):
    def __init__(self):
        #파일 불러오기 
        df=pd.read_csv('IBM-HR-Employee-Attrition_cat2num.csv')
        
        #소문자화 함수 정의하기
        l_case_func = str.lower

        #열 이름 소문자화하기
        df_lower =df.rename(columns = l_case_func)

        #not unique error가 났지만 unique함...
        print(len(df_lower['employeenumber'].unique())==len(df_lower['employeenumber']))

        #모델에 넣기
        UserModel.objects.bulk_create(
            UserModel(**vals) for vals in df_lower.to_dict('records')
        )
    class Meta:
        model=UserModel
        fields=["name","hierarchy"]
        lookup_field=["hierarchy"]
    
    def get_queryset(self):
        group = self.kwargs["hierarchy"]
        return UserModel.objects.all() #(group = group) # return a queryset

뭐가 문제일까?


settings.py는 문제가 아니었다.

INSTALLED_APPS 목록에 멀쩡하게 'users'가 존재함

serializer.is_valid()가 False인가?

그래서 else문을 붙여놓았는데 프린트 되는게 없다.

그래서 urls.py구나 했다.

urls.py도 문제 없어 보이지 않나요?

프로젝트 폴더에 include(users.urls)를 보면 앱 이름도 오타 없이 users라고 잘 썼고, urls.py 이름도 오타가 없다. 그리고 혹시 몰라 프로젝트 urls.py에서도 users.url을 ''으로 빈 스트링으로 path를 등록해두었고, 앱 urls.py에서도 UserModel.as_view()를 ''으로 빈 스트링으로 등록해두었기 때문에 원래라면 127.0.0.1:8000/ 경로에 가면 404 에러가 나면 안된다.

하지만 난다.

저 9944는 뭘까?

근데 에러 메세지를 자세히 보면 그냥 404가 아니라 9944가 따라붙길래 한 번 찾아봤다.

그런데 오히려 다른 문제 지점을 찾았다.

https://stackoverflow.com/questions/67215329/why-am-i-getting-error-404-in-my-django-project-when-everything-seems-correct
위 stack overflow에서 짚어준 게 아래와 같다.

모델 불러오는 방법을 달리 해보자

냅다 get_model_or_404() 없애버리고

users=UserModel

으로 바꾸어줬더니 제대로 된 에러(?)가 등장합니다.

그... 제가 딱 self만 넣어두긴 했는데 뭔가 restframework serializer는 디폴트로 뭐가 더 들어오나봅니다.

아래 링크 참고해서 user 앱 폴더의 serializers.py를 바꿔줬습니다.
https://www.reddit.com/r/django/comments/q5q2o6/init_function_inside_serializer_class_in_django/



class UserSerializer(serializers.ModelSerializer):
   def __init__(self, *args, **kwargs):
       super().__init__(*args, **kwargs)
       #파일 불러오기 
       df=pd.read_csv('F:\\9DevPortfolio\\2023\\2308_KB Future Finance AI\\KBFFAI\\AI\\Dataset\\IBM-HR-Employee-Attrition_cat2num.csv')
       
       #소문자화 함수 정의하기
       l_case_func = str.lower

       #열 이름 소문자화하기
       df_lower =df.rename(columns = l_case_func)

       #모델에 넣기
       UserModel.objects.bulk_create(
           UserModel(**vals) for vals in df_lower.to_dict('records')
       )
   class Meta:
       model=UserModel
       fields=["name","hierarchy"]
       lookup_field=["hierarchy"]
   
   def get_queryset(self):
       group = self.kwargs["hierarchy"]
       return UserModel.objects.all() #(group = group) # return a queryset

오! 효과가 있었습니다

다른 에러가 나는군요

아래 링크를 보니까 view 클래스에서 serializer를 초기화 할 때 model object를 넘겨줘야 하는데 그렇지 않으면 이런 에러가 난다고 합니다.
https://stackoverflow.com/questions/29731013/django-rest-framework-cannot-call-is-valid-as-no-data-keyword-argument

그런데 저는 UserModel 자체를 넘겨줬거든요. User.objects.all()과 같이 여러 개의 instance를 넘겨줘도 괜찮은 걸까요? 아니면 저는 serializer의 __init__을 재정의하여 첫 serializer instance 초기화시 입력값과 무관하게 pandas dataframe으로부터 instance를 bulk_create하게 만들어놓았으니 아예 __init__에서 args,kwargs를 빼버리고 serializer instance 초기화도 매개변수 없이 진행하도록 바꾸어야 할까요?

전자보다 후자가 이론적 배경이 있는 해결 방법인 것 같아서 해보겠습니다.

결과

에러는 그대로 유지됐지만, 이번에 하나 print 문을 추가했었거든요? views.py에서 serializer.data를 프린트하게 둔 구문입니다.

앱 폴더의 views.py 업데이트 버전


class UserView(APIView):

    def get(self,request):
        #users=UserModel
        serializer=UserSerializer()
        print(serializer.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        else:
            print("??")
            print(UserModel.objects.filter(hierarchy="사원"))
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

아래와 같은 게 프린트 되었습니다.

{'name': '<django.db.models.query_utils.DeferredAttribute object at 0x000001F89620FDF0>', 'hierarchy': '<django.db.models.query_utils.DeferredAttribute object at 0x000001F89620FC40>'}

보면 제가 예상한 것과 달리 pandas dataframe에 있던 정보가 아닙니다. DeferredAttribute object를 찾아봐야겠습니다.

딱히 검색 결과가 안 나오는군요. 아예 model에 pandas dataframe의 행을 넣는 것을 serializer init에서 진행하지 않고 view에서 만약 model instance가 존재하지 않으면 넣어주는 것으로 대체해야겠습니다. 2편에서 만나요!

profile
SW Engineer

1개의 댓글

comment-user-thumbnail
2023년 8월 10일

감사합니다. 이런 정보를 나눠주셔서 좋아요.

답글 달기