묻고 답해요
152만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨실리콘밸리 엔지니어와 함께하는 샐러리(Celery)
celery.py 위치
공식문서 보면 celery.py의 위치를 프로젝트 폴더에 하라고 되어 있는데강의에서는 app폴더인 worker에 있습니다.크게 상관이 없는건가요?아니면 다른설정을 하면 app에 위치시켜도 되는건가요?
-
미해결파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트 (장고 4.2 기준)
django-component==0.139 실행 시 오류
질문을 온전히 이해할 수 있도록, 모든 맥락을 전달해주세요.질문은 질문자가 번거로워야 보다 좋은 답변을 얻으실 수 있습니다.시행착오를 알려주시면 곧바로 원하는 문제에 집중할 수 있습니다.오류 메시지는 일부만 알려주시기보다 전체 오류 메시지를 캡처해서 주시면, 오류 파악에 도움이 됩니다. 당신의 파이썬/장고 페이스메이커가 되겠습니다. ;-)인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. runserver 실행 시 하기의 오류가 발생합니다.Exception ignored in : <function Componentregistry.__del__ at 0x2af53d0bf9a0> Traceback (most recent call last): File " .venv/lib/python3.10/site-packages/django_components/component_register.py", line 267, in __del__ AttributeError: 'NoneType' object has no attribute 'on_registry_deleted' Watching for file changes with StatReloader #...일단 겉으로 보기에는 문제 없이 작동은 합니다.settings.py는 django-components 설치 - 파이썬사랑방 튜토리얼 (pyhub.kr) 과 documentation을 보고 수정하였는데 위와 같은 문제가 발생하는 이유를 모르겠어서 혹시 아실까 싶어 질문드립니다.from email.utils import getaddresses import os, sys from pathlib import Path BASE_DIR = Path(__file__).resolve().parent.parent from django.urls import reverse_lazy from environ import Env env = Env() ENV_PATH = Path(env.str("ENV_PATH", default=str(BASE_DIR / ".env"))) if ENV_PATH.exists(): with ENV_PATH.open(encoding="utf-8") as f: env.read_env(f, overwrite=True) SECRET_KEY = env.str( "SECRET_KEY", default="django-insecure-k-7_h!2*)6jefsxn6k^2@o%jb5tozyd*6^ga+ded==osow#%!!", ) # SECURITY WARNING: don't run with debug turned on in production! DEBUG = env.bool("DEBUG", default=True) ALLOWED_HOSTS = env.list("ALLOWED_HOSTS", default=[]) CSRF_TRUSTED_ORIGINS = env.list("CSRF_TRUSTED_ORIGINS", default=[]) # Application definition INSTALLED_APPS = [ # django apps "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", # third apps "crispy_forms", "crispy_bootstrap5", "django_bootstrap5", "django_components", "django_extensions", "django_filters", "django_htmx", "formtools", # will be deprecated, form wizard "imagekit", "taggit", "template_partials", # local apps "accounts", "board", "core", "pao", "simater", "dvmt", # Django clenup should be placed last "django_cleanup.apps.CleanupConfig", ] CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5" CRISPY_TEMPLATE_PACK = "bootstrap5" TAGGIT_CASE_INSENSITIVE = env.bool("TAGGIT_CASE_INSENSITIVE", default=True) if DEBUG: INSTALLED_APPS += [ "debug_toolbar", ] AUTH_USER_MODEL = "accounts.User" # Load customized user from accounts app LOGIN_REDIRECT_URL = "/" LOGIN_URL = reverse_lazy("accounts:login") from django.core.exceptions import ImproperlyConfigured EMAIL_HOST = env.str("EMAIL_HOST", default=None) if DEBUG and EMAIL_HOST is None: # EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" else: try: EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" EMAIL_PORT = env.int("EMAIL_PORT") EMAIL_USE_SSL = env.bool("EMAIL_USE_SSL", default=False) EMAIL_USE_TLS = env.bool("EMAIL_USE_TLS", default=False) EMAIL_HOST_USER = env.str("EMAIL_HOST_USER") EMAIL_HOST_PASSWORD = env.str("EMAIL_HOST_PASSWORD") DEFAULT_FROM_EMAIL = env.str("DEFAULT_FROM_EMAIL") SERVER_EMAIL = env.str("SERVER_EMAIL", default=DEFAULT_FROM_EMAIL) except ImproperlyConfigured as e: print("ERROR:", e, file=sys.stderr) EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" MIDDLEWARE = [ "django.middleware.security.SecurityMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", "django.middleware.common.CommonMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", "django_htmx.middleware.HtmxMiddleware", "csp.middleware.CSPMiddleware", ] if DEBUG: MIDDLEWARE = [ "debug_toolbar.middleware.DebugToolbarMiddleware", ] + MIDDLEWARE ROOT_URLCONF = "config.urls" TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", "DIRS": [ BASE_DIR / "core" / "templates", # BASE_DIR / "core" / "src-django-components", ], # "APP_DIRS": True, "OPTIONS": { "context_processors": [ "django.template.context_processors.debug", "django.template.context_processors.request", "django.contrib.auth.context_processors.auth", "django.contrib.messages.context_processors.messages", ], "loaders": [ ( "django.template.loaders.cached.Loader", [ # Default Django loader "django.template.loaders.filesystem.Loader", # Including this is the same as APP_DIRS=True "django.template.loaders.app_directories.Loader", # Components loader "django_components.template_loader.Loader", ], ) ], }, }, ] WSGI_APPLICATION = "config.wsgi.application" # Database # https://docs.djangoproject.com/en/4.2/ref/settings/#databases DEFAULT_DATABASE_URL = f"sqlite:///{BASE_DIR / 'db.sqlite3'}" DATABASES = { "default": env.db(default=DEFAULT_DATABASE_URL) } # Password validation # https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", }, { "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", }, { "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", }, { "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", }, ] # Internationalization # https://docs.djangoproject.com/en/4.2/topics/i18n/ LANGUAGE_CODE = env.str(var="LANGUAGE_CODE", default="ko-kr") TIME_ZONE = "Asia/Seoul" USE_I18N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/4.2/howto/static-files/ STATIC_URL = env.str("STATIC_URL", default="static/") STATICFILES_DIRS = [ # BASE_DIR / "core" / "static", # BASE_DIR / "core" / "src-django-components", ] STATIC_ROOT = env.str("STATIC_ROOT", default=BASE_DIR / "staticfiles") # django-components # - context variable를 resolve하는 방식이 변경 from django_components import ComponentsSettings COMPONENTS = ComponentsSettings( dirs=[ Path(BASE_DIR) / "core" / "src-django-components", ], ) # COMPONENTS = { # "dirs": [ # # BASE_DIR / "components", # default # BASE_DIR # / "core" # / "src-django-components", # ], # # "context_behavior": "django", # default # } STATICFILES_FINDERS = [ # Default finders "django.contrib.staticfiles.finders.FileSystemFinder", "django.contrib.staticfiles.finders.AppDirectoriesFinder", # Django components "django_components.finders.ComponentsFileSystemFinder", ] MIDDLEWARE += [ "django_components.middleware.ComponentDependencyMiddleware", ] # Media files MEDIA_URL = env.str("MEDIA_URL", default="media/") MEDIA_ROOT = env.str("MEDIA_ROOT", default=BASE_DIR / "mediafiles") # Default primary key field type # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" from django.contrib.messages import constants as messages_constants if DEBUG: MESSAGE_LEVEL = messages_constants.DEBUG INTERNAL_IPS = env.list("INTERNAL_IPS", default=["127.0.0.1"]) if DEBUG: # FORM_RENDERER = "core.forms.renderers.NoCacheDjangoTemplates" INSTALLED_APPS += [ "django.forms", ] DEFAULT_FILE_STORAGE = "django.core.files.storage.FileSystemStorage" ADMIN_PREFIX = os.environ.get("ADMIN_PREFIX", "might/") ## django default loggings : django.utils.logs.DEFAULT_LOGGING ## LOGGING settings LOGGING = { #... } ADMINS = getaddresses([env.str("ADMINS", default="")]) # Django-csp settings CSP_FRAME_ANCESTORS = env.list("CSP_FRAME_ANCESTORS", default=[]) CSP_DEFAULT_SRC = [ "'self'", ] CSP_SCRIPT_SRC = ["'self'", "'unsafe-inline'", "'unsafe-eval'"] + CSP_FRAME_ANCESTORS CSP_STYLE_SRC = [ "'self'", "'unsafe-inline'", ] + CSP_FRAME_ANCESTORS CSP_IMG_SRC = [ "'self'", "data:", ] + CSP_FRAME_ANCESTORS if not CSP_FRAME_ANCESTORS: CSP_FRAME_ANCESTORS = ["'self'"]
-
미해결파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트 (장고 4.2 기준)
django-csp 4.0 migration 관련
질문을 온전히 이해할 수 있도록, 모든 맥락을 전달해주세요.질문은 질문자가 번거로워야 보다 좋은 답변을 얻으실 수 있습니다.시행착오를 알려주시면 곧바로 원하는 문제에 집중할 수 있습니다.오류 메시지는 일부만 알려주시기보다 전체 오류 메시지를 캡처해서 주시면, 오류 파악에 도움이 됩니다. 당신의 파이썬/장고 페이스메이커가 되겠습니다. ;-)인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. django-csp 4.0 Migration Guide — Django-CSP 4.0 documentationcsp 4.0 이 나왔는데 다음과 같이 강의 내용을 변경하면 될까요?## config/settings.py from csp.constants import SELF INSTALLED_APPS = [ # ... "csp", # ... ] frame_addition = env.list("CSP_FRAME_ANCESTOS". default=[]) CONTENT_SECURITY_POLICY = { "EXCLUDE_URL_PREFIXES": ["/admin"], "DIRECTIVES": { "default-src": [SELF, "*.example.com"]+ frame_addition , "script-src": [SELF, "js.cdn.com/example/"]+ frame_addition , "img-src": [SELF, "data:", "example.com"]+ frame_addition , "csp_frame_ancestors": [SELF] + frame_addition }, } 이런식으로 변경 해주면 충분할까요?
-
미해결파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트 (장고 4.2 기준)
01 윈도우 개발환경 설치 문의
안녕하세요. 강사님.늘 강의 잘 보고 있습니다. 🙂 오늘 1강부터 청강 시작 했습니다. 윈도우 개발환경에서 파이썬 3.11 설치를 알려주셨습니다. 25년 4월 현재도 여전히 유효한지요?검토 부탁드립니다. 감사합니다. 당신의 파이썬/장고 페이스메이커가 되겠습니다. ;-)인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.
-
미해결작정하고 장고! Django로 Pinterest 따라만들기 : 바닥부터 배포까지
PasswordChangeView
강의에서 나오는 forms.py 파일을 만들어서 커스텀폼을 만드니A user with that username already exists.username 이 이미 존재하는 에러가 계속해서 발생 (다른 수강생분들도 겪은 에러인듯) 장고 기능이 추가된 건지는 몰라도 PasswordChangeView 를 활용함 views.pyclass AccountUpdateView(PasswordChangeView): form_class = PasswordChangeForm template_name = 'accountapp/update.html' success_url = reverse_lazy('accountapp:detail')여기서 success_url 이 정적 url 로 pk 파라미터 값을 전달해주지 못하는 문제가 있음그래서 수정된 코드는class AccountUpdateView(PasswordChangeView): form_class = PasswordChangeForm template_name = 'accountapp/update.html' def get_success_url(self): return reverse('accountapp:detail', kwargs={'pk': self.request.user.pk}) 2025년 3월 31일 기준1) 비밀번호 변경 기능의 기본 View,Form 있음 (PasswordChangeView, PasswordChangeForm)2) 비밀번호 변경 후 hello_world 페이지로 리다이렉트 시킬거면 success_url = 'accountapp:hello_world'3) 로그인한 계정의 detail 페이지로 이동한다면 마지막 코드 참고
-
미해결작정하고 장고! Django로 Pinterest 따라만들기 : 바닥부터 배포까지
로그아웃뷰 작동 관련 (2025년 3월)
1)앵커태그로 로그인, 로그아웃 구현하고 기존 로그인 되어있던 상황에서 로그아웃을 진행하니 에러가 발생 (405 에러) 2) 장고의 LogoutView 는 POST 요청만 허용함?next={{ request.path }} 는 GET 요청으로logout 누르면 /logout?next=/account/hello_world/ 로 GET 요청하게됨따라서, 정상적으로 로그아웃뷰를 사용하려면 1) 로그아웃 링크를 POST 요청으로 보내는 폼으로 변경 2) LogoutView 의 설정을 변경하여 GET 요청도 허용보안상 2는 권장되지 않는 사항이며, 1의 방법으로 처리{% else %} <form action="{% url 'accountapp:logout' %}" method="post" style="display: inline;"> {% csrf_token %} <button type="submit" class="btn btn-link" style="text-decoration: none; padding: 0; margin: 0;"> <span>Logout</span> </button> </form> {% endif %} 주요 변경사항 1) 로그아웃 앵커 태그를 form 태그로 변경 2) 폼의 method 를 post 로 지정 3) 이에따라 csrf 토큰 추가 추가로 logout 이후 redirect 경로를 설정해줘야하는데, 이는 pragmatic/settings.py 에서 설정# Logout Redirect URL LOGOUT_REDIRECT_URL = '/account/hello_world/' 마지막 머물렀던 페이지에서 로그아웃이 되게 하고 싶다면, 커스텀 로그아웃뷰를 만들어야하는데, 보안상 권장되지 않는다고 함. +++왜인지는 모르겠으나 로그인도?next={{ request.path }} 를 먹지 않아서pragmatic/settings.py 에서 로그인 리다이렉트 URL 을 추가하여 처리하였음# Login Redirect URL LOGIN_REDIRECT_URL = '/account/hello_world/' # Logout Redirect URL LOGOUT_REDIRECT_URL = '/account/hello_world/' 이 경우 html 템플릿에서 next 를 사용할 필요 없고 사이트 어디서 로그인하던 /account/hello_world 로 리다이렉트 시킴
-
해결됨파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트 (장고 4.2 기준)
강의 자료 문의
안녕하세요! 우선 좋은 강의를 제공해주셔서 정말 감사합니다!하지만 불편한 점이 있습니다.강의 자료를 일일이 다운받으니 번거롭고 파일 병합하기도 힘드네요..타 강의와 비교하는 것은 죄송하지만, 다른 강의들은 모두 zip파일로 강의자료를 병합하여 업로드해주십니다.본 강의도 강의자료를 병합하여 한번에 올려주시면 감사하겠습니다!
-
미해결파이썬으로 장고(Django) 공략하기: 입문
빨간 줄이 뜨네요
첨부파일 화면처럼 빨간 줄이 나타납니다. 실행은 전혀 문제가 없이 실행이 잘 됩니다.
-
미해결파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트 (장고 4.2 기준)
선생님 학습 방법 질문이 있습니다.
파이썬 기초 문법 학습 후 현재 강의를 듣는 중인데 2번 세션 맛보기 반복 숙달 어느정도까지 해야 다음 챕터로 넘어가는 것이 맞나요? 강의 이름은 맛보기인데 중요한 것 들 같아서 반복 숙달을 어느정도 까지 하는게 좋을 지 궁금합니다.
-
미해결파이썬으로 장고(Django) 공략하기: 입문
import 문장에 빨간줄이 뜹니다.
안녕하세요? 좋은 강의 감사 드립니다.처음 장고 프로젝트를 만들었는데, first 폴더를 만들어 놓았는데 폴더 안에 admin.py, apps.py 등등의 파일이 있는데 파일을 더블클릭을 해서 소스를 보았는데admin.py 파일 같은 경우에는from django.contrib import admin 문장이 있는데 django 글자와 admin 글자에 빨간줄이 나타납니다. 답변 부탁 드립니다. 감사합니다.
-
해결됨실리콘밸리 엔지니어와 함께하는 샐러리(Celery)
docker-compose
저만 이런거 일 수 도 있는데 혹시나 해서 공유드립니당~ 발생경과:강의자료에서 다운 받은 코드 docker compose up 실행컨테이너가 차례대로 올라오지만 beat 컨테이너만 죽는 상황django_celery_beat.schedulers가 Exits Error 발생이유:Celery Beat 컨테이너가 마이그레이션이 안된 상황. 방법:celery app 컨테이너 내부 접속 마이그레이트 실행.python manage.py migrate django_celery_beat 별도 로그:2025-03-04 12:14:22 celery beat v5.3.6 (emerald-rush) is starting.2025-03-04 12:14:22 - ... - _2025-03-04 12:14:22 LocalTime -> 2025-03-04 03:14:222025-03-04 12:14:22 Configuration ->2025-03-04 12:14:22 . broker -> redis://redis:6379/02025-03-04 12:14:22 . loader -> celery.loaders.app.AppLoader2025-03-04 12:14:22 . scheduler -> django_celery_beat.schedulers.DatabaseScheduler2025-03-04 12:14:222025-03-04 12:14:22 . logfile -> [stderr]@%INFO2025-03-04 12:14:22 . maxinterval -> 5.00 seconds (5s)2025-03-04 12:14:22 [2025-03-04 03:14:22,430: INFO/MainProcess] beat: Starting...2025-03-04 12:14:22 [2025-03-04 03:14:22,449: CRITICAL/MainProcess] beat raised exception <class 'django.db.utils.ProgrammingError'>: ProgrammingError('relation "django_celery_beat_periodictask" does not exist\nLINE 1: ...ango_celery_beat_periodictask"."description" FROM "django_ce...\n ^\n')2025-03-04 12:14:22 Traceback (most recent call last):2025-03-04 12:14:22 File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 89, in _execute2025-03-04 12:14:22 return self.cursor.execute(sql, params)2025-03-04 12:14:22 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^2025-03-04 12:14:22 psycopg2.errors.UndefinedTable: relation "django_celery_beat_periodictask" does not exist2025-03-04 12:14:22 LINE 1: ...ango_celery_beat_periodictask"."description" FROM "django_ce...2025-03-04 12:14:22 ^
-
해결됨파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트 (장고 4.2 기준)
bulk_update에서 updated_at 필드
안녕하세요! 해당 수업에서 django shell에서 update 부분 실습하다가 결과 값에 의문이 생겨 질문드립니다.이 부분에서 auto_now=True 필드도 같이 bulk_update 함수의 인자인 fields에 지정해야만 해당 필드도 같이 업데이트 된다고 하셨는데 제 코드에서는 updated_at 필드의 값이 업데이트 되지 않았습니다.제가 나름대로 이해한 바로는 bulk_update는 따로 save를 호출하지 않기 때문에 updated_at을 fields 인자에 추가해주더라도 변한 값이 없어서 업데이트가 되지 않는 걸까요? 그렇다면 제대로 updated_at도 업데이트 되게끔 하기 위해서는 따로 post.updated_at = timezone.now()를 title 수정할 때 해주어야 하는 걸까요?
-
해결됨파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트 (장고 4.2 기준)
정규표현식
안녕하세요! 강의 들으며 많은 부분 배우고 있습니다.DateCoverter 정규표현식 부분을 보면서 드는 의문이 있어 질문드립니다. 제가 이해한 바가 맞다면, 정규표현식에서 {1,2}부분은 앞부분의 패턴을 1번 또는 2번 반복한다고 이해했습니다.그렇다면 r"20\d{2}/([1-9]|0[1-9]|1[0-2]){1,2}/([1-9]|0[1-9]|[12][0-9]|3[01]){1,2}"라는 정규표현식에서 월과 일의 숫자를 체크하는 부분이 1번 또는 2번 반복될 수도 있으니 "2023/0303/1212"와 같은 문자열도 통과 가능한 것일까요?
-
해결됨실리콘밸리 엔지니어와 함께하는 샐러리(Celery)
standalone_celery 에만 작성된 task 들은 호출할 수 없나요?
안녕하세요. 본 강의를 통해 celery 를 처음 접하는 초보 입니다.섹션2 의 Task Routing 에 대해 알아보기 강의를 보고 질문드립니다. standalone_celery 에만 작성된 mul 이나 xsum 함수(<- 이렇게 부르는 게 맞나요?)는 어떻게 실행하나요?현재 상태에서는 실행할 수 없는 게 맞나요? django-app 에서는 해당 함수들이 ImportError 가 발생하고(실제 해당 함수가 없을 테니 여기까진 이해했습니다.)celery-standalone 에 들어가 python shell 에서 mul.delay(1,1) 을 실행하면어디에도 queue2 로 task 가 실행된 로그가 뜨지 않습니다.궁금합니다. P.S 'Celery 의 task 에 작성된 함수들이 queue 로 실행된다.' 가 맞는 표현인가요? 틀린 표현이라면 더 적합한 표현을 알고 싶습니다.
-
해결됨실리콘밸리 엔지니어가 가르치는 파이썬 장고 웹프로그래밍
Logging 질문
LOGGING ={ 'version':1, 'disable_existing_loggers':False, 'handlers':{ 'file':{ 'level':'DEBUG', 'class':'logging.FileHandler', 'filename':os.path.join(BASE_DIR, 'logs/django.log'), 'formatter':'json', }, 'console':{ 'class':'logging.StreamHandler', 'formatter':'json', }, }, 'formatters':{ 'json':{ 'class': 'pythonjsonlogger.jsonlogger.JsonFormatter', 'format': '%(asctime)s %(levelname)s %(name)s %(message)s', }, }, 'root':{ 'handlers':['file','console'], 'level':'DEBUG', }, 'loggers':{ 'django':{ 'handlers':['file','console'], 'level': 'DEBUG', 'propagate':False, }, }, runserver 하는 순간 {"asctime": "2025-02-14 20:41:50,823", "levelname": "DEBUG", "name": "django.utils.autoreload", "message": "File C:\\Users\\moon\\miniforge3\\envs\\workout\\Lib\\site-packages\\PIL\\__init__.py first seen with mtime 1739352505.781736"} 이런 변경한 적 없는 것들이 자동리로드 되면서 콘솔에 계속 올라옵니다. 이유가 궁금합니다.
-
미해결파이썬/장고로 웹채팅 서비스 만들기 (Feat. Channels) - 기본편
유저목록 확인 문제 질문드립니다.
def room_users(request, room_name): # room_name으로 해당 방을 찾기 room = get_object_or_404(Room, name=room_name) # 사용자가 방에 참여한 상태인지 확인 if not room.is_joined_user(request.user): return HttpResponse("Unauthorized user", status=401) # 방에 접속 중인 사용자 목록 가져오기 username_list = room.get_online_usernames() return JsonResponse({ "username_list": username_list, }) 저는 하나의 채팅방만 사용하기때문에 room_pk가 아니라 room_name을 전달했습니다. 근데 page not found가 뜹니다. 제가 생각기로는 name = room_name 전달이 제대로 안되어서 이렇게 뜨는거같습니다. room_pk에 관한 부분을 제대로 처리하지 못해 접속하거나 나갈때 뜨는 메세지도 제대로 작동하지 않고 있습니다.class Room(OnlineUserMixin, models.Model): owner = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="owned_room_set", ) name = models.CharField(max_length=100) class Meta: ordering = ["-pk"] @property def chat_group_name(self): return self.make_chat_group_name(room=self) chat/routing.pyfrom django.urls import path, re_path from chat import consumers websocket_urlpatterns = [ path("ws/chat/<str:room_name>/chat/", consumers.ChatConsumer.as_asgi()), ] chat/urls.py from django.urls import path from app.urls import urlpatterns from chat import views # 향후 url reverse에 활용 app_name = "chat" urlpatterns=[ path("", views.index, name = "index"), path("<str:room_name>/chat/", views.room_chat, name = "room_chat" ), path("<str:room_name>/users/", views.room_users, name = "room_users" ), ] consumers.pyfrom asgiref.sync import async_to_sync from channels.generic.websocket import JsonWebsocketConsumer from chat.models import Room # 모든 유저가 고정된 채널 레이어 그룹을 가질것. class ChatConsumer(JsonWebsocketConsumer): SQUARE_GROUP_NAME = "1" group_name = [SQUARE_GROUP_NAME] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def connect(self): user = self.scope['user'] self.group_name = self.SQUARE_GROUP_NAME if not user.is_authenticated: self.close() else: is_new_join = self.group_name if is_new_join: async_to_sync(self.channel_layer.group_send)( self.group_name, { "type": "chat.user.join", "username": user.username, } ) async_to_sync(self.channel_layer.group_add)( self.group_name, self.channel_name ) self.accept() def disconnect(self, code): if self.group_name: async_to_sync(self.channel_layer.group_discard)( self.group_name, self.channel_name ) user = self.scope['user'] # if self.room is not None: # is_last_leave = self.room.user_leave(self.channel_name, user) # if is_last_leave: # async_to_sync(self.channel_layer.group_send)( # self.group_name, # { # "type": "chat.user.leave", # "username": user.username, # } # ) def chat_user_join(self, message_dict): self.send_json({ "type": "chat.user.join", "username": message_dict["username"], }) def chat_user_leave(self, message_dict): self.send_json({ "type": "chat.user.leave", "username": message_dict["username"], }) def chat_message(self, message_dict): self.send_json({ "type": "chat.message", "message": message_dict["message"], "sender": message_dict["sender"], }) def receive_json(self, content, **kwargs): user = self.scope["user"] _type = content["type"] if _type == "chat.message": message = content["message"] sender = user.username async_to_sync(self.channel_layer.group_send)( self.SQUARE_GROUP_NAME, { "type": "chat.message", "message": message, "sender": sender, } ) else: print(f"Invalid message type : ${_type}") 질문 받아주셔서 감사합니다. 선생님의 파이썬 장고 가이드를 다 보고 이 강의 질문하는게 맞다고 생각합니다. , 제 팀프로젝트 데드라인이 임박하여 파이썬 장고 가이드를 다 보지 못하고, 제대로 공부하지 못하고 채널스를 공부하게 되어 이런 질문을 드리게되는거같아 죄송합니다. 프로젝트가 끝나도 장고 놓지 않고 제대로 이해할수있게 공부하겠습니다. 감사합니다ㅠ
-
미해결파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트 (장고 4.2 기준)
선생님 질문 있습니다.
1) request.META["HTTP_USER_AGENT"] 실습 5번 내내 NameError로 표기 되지 않습니다. 구글링해도 정확히 어떤 이유인지 잘모르겠습니다.2) 아래 pwsh 느낌표가 왜 나오는지 궁금합니다.
-
미해결파이썬/장고로 웹채팅 서비스 만들기 (Feat. Channels) - 기본편
안녕하세요 선생님,
#consumers.py from asgiref.sync import async_to_sync from channels.generic.websocket import JsonWebsocketConsumer from chat.models import Room # 모든 유저가 고정된 채널 레이어 그룹을 가질것. class ChatConsumer(JsonWebsocketConsumer): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) SQUARE_GROUP_NAME = "square" self.group_name = [SQUARE_GROUP_NAME] self.room = None def connect(self): user = self.scope['user'] if not user.is_authenticated: self.close() else: room_name = self.scope['url_route']['kwargs']['room_pk'] try: self.room = Room.objects.get(pk=room_name) except Room.DoesNotExist: #지정 룸 pk에 룸 인스턴스가 없을 경우 웹소켓 연결요청 수락. pass else: self.group_name = self.SQUARE_GROUP_NAME is_new_join = self.room.user_join(self.channel_name, user) if is_new_join: async_to_sync(self.channel_layer.group_send)( self.group_name, { "type": "chat.user.join", "username": user.username, } ) async_to_sync(self.channel_layer.group_add)( self.group_name, self.channel_name ) self.accept() def disconnect(self, code): if self.group_name: async_to_sync(self.channel_layer.group_discard)( self.group_name, self.channel_name ) user = self.scope['user'] if self.room is not None: is_last_leave = self.room.user_leave(self.channel_name, user) if is_last_leave: async_to_sync(self.channel_layer.group_send)( self.group_name, { "type": "chat.user.leave", "username": user.username, } ) def chat_user_join(self, message_dict): self.send_json({ "type": "chat.user.join", "username": message_dict["username"], }) def chat_user_leave(self, message_dict): self.send_json({ "type": "chat.user.leave", "username": message_dict["username"], }) def chat_message(self, message_dict): self.send_json({ "type": "chat.message", "message": message_dict["message"], "sender": message_dict["sender"], }) def receive_json(self, content, **kwargs): user = self.scope["user"] _type = content["type"] if _type == "chat.message": message = content["message"] sender = user.username async_to_sync(self.channel_layer.group_send)( self.SQUARE_GROUP_NAME, { "type": "chat.message", "message": message, "sender": sender, } ) else: print(f"Invalid message type : ${_type}") room_name = self.scope['url_route']['kwargs']['room_pk'] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^ KeyError: 'room_pk' 이런 에러가 나서, urls.py, views.py, index.html도 맞춰줘 봤지만, 잘 해결이 되질 않습니다. 어떤식으로 이 에러를 처리해야할까요. 오늘도 좋은 하루 되시길 바랍니다. 감사합니다.
-
미해결파이썬/장고로 웹채팅 서비스 만들기 (Feat. Channels) - 기본편
하나의 채팅방만 만들어보려고 하는데 잘 안되고 있습니다.
안녕하세요 선생님. 인증받지 않은 유저의 웹소켓 접근을 거부하려고 하는데요,Traceback (most recent call last): File "/Users/sunnnwo/workspace/pongchatT/venv/lib/python3.11/site-packages/django/contrib/staticfiles/handlers.py", line 101, in __call__ return await self.application(scope, receive, send) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/sunnnwo/workspace/pongchatT/venv/lib/python3.11/site-packages/channels/routing.py", line 62, in __call__ return await application(scope, receive, send) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/sunnnwo/workspace/pongchatT/venv/lib/python3.11/site-packages/channels/sessions.py", line 47, in __call__ return await self.inner(dict(scope, cookies=cookies), receive, send) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/sunnnwo/workspace/pongchatT/venv/lib/python3.11/site-packages/channels/sessions.py", line 263, in __call__ return await self.inner(wrapper.scope, receive, wrapper.send) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/sunnnwo/workspace/pongchatT/venv/lib/python3.11/site-packages/channels/auth.py", line 185, in __call__ return await super().__call__(scope, receive, send) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/sunnnwo/workspace/pongchatT/venv/lib/python3.11/site-packages/channels/middleware.py", line 24, in __call__ return await self.inner(scope, receive, send) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TypeError: 'list' object is not callable WebSocket DISCONNECT /ws/chat/test/chat/ [127.0.0.1:61013] HTTP GET /chat/ 200 [0.01, 127.0.0.1:61007] /Users/sunnnwo/workspace/pongchat/mysite/asgi.py changed, reloading. Watching for file changes with StatReloader 아래와 같이 설정하고 실행해봤는데, 위와 같은 에러가 발생했습니다. AuthMiddlewareStack을 이용하여 인증된 사용자만 채팅할 수 있게 하려면 어느 부분을 수정해야할까요. 감사합니다. 좋은 하루되세요.asgi.py application = ProtocolTypeRouter({ "http" : django_asgi_app, "websocket" : AuthMiddlewareStack( app.routing.websocket_urlpatterns + chat.routing.websocket_urlpatterns, ), })consumers.pyfrom asgiref.sync import async_to_sync from channels.generic.websocket import JsonWebsocketConsumer # 모든 유저가 고정된 채널 레이어 그룹을 가질것. class ChatConsumer(JsonWebsocketConsumer): SQUARE_GROUP_NAME = "square" groups = [SQUARE_GROUP_NAME] def receive_json(self, content, **kwargs): # user = self.scope["user"] user = self.scope["user"] _type = content["type"] if not user.is_authenticated: self.close() else: if _type == "chat.message": message = content["message"] async_to_sync(self.channel_layer.group_send)( self.SQUARE_GROUP_NAME, { "type": "chat.message", "message": message, } ) else: print(f"Invalid message type : ${_type}") def chat_message(self, message_dict): self.send_json({ "type": "chat.message", "message": message_dict["message"], })chat/routing.pyfrom django.urls import path, re_path from chat import consumers websocket_urlpatterns = [ path("ws/chat/<str:room_name>/chat/", consumers.ChatConsumer.as_asgi()), ] chat/urls.pyurlpatterns=[ path("", views.index, name = "index"), path("<str:room_name>/chat/", views.room_chat, name = "room_chat" ), ]
-
미해결파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트 (장고 4.2 기준)
공유자님 이 강의 공부 방법에 대한 질문입니다.
이 강의는 어떤 식으로 접근해야 되나요?이런 것이 있구나~ 라고 생각하고 넘어가야 하나요? 아니면 하나하나 다 알아가면서 넘어가는 것이 좋나요?