I am contributing to an open-source org where they are using django-rest-auth for authentication purposes. I have to simply override the email template for a password reset. So I used imported PasswordResetSerializer and then customized it. It worked in the first place but when I restarted the whole environment it stopped working and just showed this in terminal
django_1 | [pid: 65|app: 0|req: 1/1] 172.19.0.1 () {42 vars in 696 bytes} [Thu Jan 7 22:06:59 2021] OPTIONS /api/auth/password/reset/ => generated 0 bytes in 4 msecs (HTTP/1.1 200) 7 headers in 365 bytes (1 switches on core 0)
django_1 | [pid: 67|app: 0|req: 1/2] 172.19.0.1 () {42 vars in 696 bytes} [Thu Jan 7 22:06:59 2021] POST /api/auth/password/reset/ => generated 22264 bytes in 796 msecs (HTTP/1.1 500) 5 headers in 177 bytes (1 switches on core 0)
It's showing me error 500.
I tried to use debugger but here the all environment is setup using docker and I couldn't figure out what's going wrong.
Here are the files
settings.py
"""
Django settings for evalai project.
Generated by 'django-admin startproject' using Django 1.10.2.
For more information on this file, see
https://docs.djangoproject.com/en/1.10/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.10/ref/settings/
"""
import datetime
import os
import sys
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
APPS_DIR = os.path.join(BASE_DIR, "apps")
sys.path.append(APPS_DIR)
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ.get("SECRET_KEY", "random_secret_key")
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
TEST = False
ALLOWED_HOSTS = []
EVALAI_API_SERVER = os.environ.get("EVALAI_API_SERVER", "http://localhost:8000")
# Application definition
DEFAULT_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"django.contrib.sites",
]
OUR_APPS = [
"accounts",
"analytics",
"base",
"challenges",
"hosts",
"jobs",
"participants",
"web",
]
THIRD_PARTY_APPS = [
"allauth",
"allauth.account",
'allauth.socialaccount',
"corsheaders",
"django_ses",
"import_export",
"rest_auth",
"rest_auth.registration",
"rest_framework.authtoken",
"rest_framework",
"rest_framework_expiring_authtoken",
"drf_yasg",
"django_filters",
]
INSTALLED_APPS = DEFAULT_APPS + OUR_APPS + THIRD_PARTY_APPS
MIDDLEWARE = [
"corsheaders.middleware.CorsMiddleware",
"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",
]
ROOT_URLCONF = "evalai.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"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",
]
},
}
]
WSGI_APPLICATION = "evalai.wsgi.application"
# Password validation
# https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator" # noqa
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator" # noqa
},
{
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator" # noqa
},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator" # noqa
},
]
# Internationalization
# https://docs.djangoproject.com/en/1.10/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.10/howto/static-files/
STATIC_URL = "/static/"
STATIC_ROOT = os.path.join(BASE_DIR, "static")
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
MEDIA_URL = "/media/"
SITE_ID = 1
REST_FRAMEWORK = {
"DEFAULT_PAGINATION_CLASS": (
"rest_framework.pagination.LimitOffsetPagination"
),
"PAGE_SIZE": 100,
"TEAM_PAGE_SIZE": 10,
"DEFAULT_PERMISSION_CLASSES": [
"rest_framework.permissions.IsAuthenticatedOrReadOnly"
],
"DEFAULT_AUTHENTICATION_CLASSES": [
"rest_framework_expiring_authtoken.authentication.ExpiringTokenAuthentication"
],
"TEST_REQUEST_DEFAULT_FORMAT": "json",
"DEFAULT_THROTTLE_CLASSES": (
"rest_framework.throttling.AnonRateThrottle",
"rest_framework.throttling.UserRateThrottle",
),
"DEFAULT_THROTTLE_RATES": {
"anon": "100/minute",
"user": "100/minute",
"resend_email": "3/hour",
},
"DEFAULT_RENDERER_CLASSES": ("rest_framework.renderers.JSONRenderer",),
}
# ALLAUTH SETTINGS
ACCOUNT_EMAIL_REQUIRED = True
OLD_PASSWORD_FIELD_ENABLED = True
ACCOUNT_CONFIRM_EMAIL_ON_GET = True
ACCOUNT_EMAIL_CONFIRMATION_ANONYMOUS_REDIRECT_URL = (
"/api/auth/email-confirmed/"
)
ACCOUNT_EMAIL_CONFIRMATION_AUTHENTICATED_REDIRECT_URL = (
"/api/auth/email-confirmed/"
)
AUTHENTICATION_BACKENDS = (
# Needed to login by username in Django admin, regardless of `allauth`
"django.contrib.auth.backends.ModelBackend",
# `allauth` specific authentication methods, such as login by e-mail
"allauth.account.auth_backends.AuthenticationBackend",
)
AWS_STORAGE_BUCKET_NAME = os.environ.get("AWS_STORAGE_BUCKET_NAME")
AWS_ACCOUNT_ID = os.environ.get("AWS_ACCOUNT_ID", "aws_account_id")
AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID", "aws_access_key_id")
AWS_SECRET_ACCESS_KEY = os.environ.get(
"AWS_SECRET_ACCESS_KEY", "aws_secret_access_key"
)
AWS_REGION = os.environ.get("AWS_DEFAULT_REGION", "us-east-1")
# Broker url for celery
CELERY_BROKER_URL = "sqs://%s:%s#" % (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
# CORS Settings
CORS_ORIGIN_ALLOW_ALL = True
# REST Framework Expiring Tokens Configuration
EXPIRING_TOKEN_LIFESPAN = datetime.timedelta(days=365)
# Logging
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"root": {"level": "INFO", "handlers": ["console"]},
"filters": {
"require_debug_false": {"()": "django.utils.log.RequireDebugFalse"},
"require_debug_true": {"()": "django.utils.log.RequireDebugTrue"},
},
"formatters": {
"simple": {
"format": "[%(asctime)s] %(levelname)s %(message)s",
"datefmt": "%Y-%m-%d %H:%M:%S",
},
"verbose": {
"format": "[%(asctime)s] %(levelname)s %(module)s %(message)s",
"datefmt": "%Y-%m-%d %H:%M:%S",
},
},
"handlers": {
"console": {
"level": "INFO",
"filters": ["require_debug_true"],
"class": "logging.StreamHandler",
"formatter": "simple",
},
"logfile": {
"level": "DEBUG",
"class": "logging.handlers.RotatingFileHandler",
"filename": os.path.join(BASE_DIR, "django.log"),
"maxBytes": 50000,
"backupCount": 10,
"formatter": "verbose",
},
"mail_admins": {
"level": "ERROR",
"class": "django.utils.log.AdminEmailHandler",
"filters": ["require_debug_false"],
},
},
"loggers": {
"django": {"handlers": ["console"], "propagate": False},
"django.request": {
"handlers": ["mail_admins"],
"level": "ERROR",
"propagate": False,
},
"django.security": {
"handlers": ["mail_admins"],
"level": "ERROR",
"propagate": False,
},
"django.db.backends": {
"handlers": ["mail_admins"],
"level": "ERROR",
"propagate": False,
},
},
}
CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.memcached.MemcachedCache"
}
}
# The maximum size in bytes for request body
# https://docs.djangoproject.com/en/1.10/ref/settings/#data-upload-max-memory-size
FILE_UPLOAD_MAX_MEMORY_SIZE = 4294967296 # 4 GB
DATA_UPLOAD_MAX_MEMORY_SIZE = 4294967296 # 4 GB
# To make usermame field read-only, customized serializer is defined.
REST_AUTH_SERIALIZERS = {
"USER_DETAILS_SERIALIZER": "accounts.serializers.ProfileSerializer",
"PASSWORD_RESET_SERIALIZER": "accounts.serializers.CustomPasswordResetSerializer"
}
# For inviting users to participant and host teams.
ADMIN_EMAIL = "admin#cloudcv.org"
CLOUDCV_TEAM_EMAIL = "EvalAI Team <team#cloudcv.org>"
# Expiry time of a presigned url for uploading files to AWS, in seconds.
PRESIGNED_URL_EXPIRY_TIME = 3600
# Slack web hook url
SLACK_WEB_HOOK_URL = os.environ.get(
"SLACK_WEB_HOOK_URL", "http://testslackwebhook.com/webhook"
)
SWAGGER_SETTINGS = {
"DEFAULT_INFO": "evalai.urls.swagger_api_info",
"SECURITY_DEFINITIONS": {
"Token Authentication": {
"type": "apiKey",
"name": "Authorization",
"in": "header",
}
},
}
REDOC_SETTINGS = {"SPEC_URL": ("docs.yaml", {"format": ".yaml"})}
DJANGO_SERVER = os.environ.get("DJANGO_SERVER")
DJANGO_SERVER_PORT = os.environ.get("DJANGO_SERVER_PORT")
HOSTNAME = os.environ.get("HOSTNAME")
SENDGRID_SETTINGS = {
"TEMPLATES": {
"CHALLENGE_INVITATION": "d-60825bcf014f4958bdb1b9173471d420",
"CHALLENGE_APPROVAL_EMAIL": "d-45e0adc0597b4b60bd7c384aa903c488",
"WORKER_RESTART_EMAIL": "d-3d9a474a5e2b4ac4ad5a45ba9c0b84bd",
"CLUSTER_CREATION_TEMPLATE": "d-6de90fd760df4a41bb9bff1872eaab82",
"WORKER_START_EMAIL": "d-debd127cab2345e789538131501ff416",
}
}
# EKS configs for Rl-worker
EKS_CLUSTER_ROLE_ARN = os.environ.get("EKS_CLUSTER_ROLE_ARN")
EKS_NODEGROUP_ROLE_ARN = os.environ.get("EKS_NODEGROUP_ROLE_ARN")
ENVIRONMENT = os.environ.get("ENVIRONMENT", "dev")
serializers.py
from django.contrib.auth import get_user_model
from rest_framework import serializers
from rest_auth.serializers import PasswordResetSerializer
class UserDetailsSerializer(serializers.ModelSerializer):
"""
Make username as a read_only field.
"""
class Meta:
model = get_user_model()
fields = (
"pk",
"email",
"username",
"first_name",
"last_name",
"password",
)
read_only_fields = ("email", "username")
class ProfileSerializer(UserDetailsSerializer):
"""
Serializer to update the user profile.
"""
affiliation = serializers.CharField(source="profile.affiliation")
github_url = serializers.URLField(
source="profile.github_url", allow_blank=True
)
google_scholar_url = serializers.URLField(
source="profile.google_scholar_url", allow_blank=True
)
linkedin_url = serializers.URLField(
source="profile.linkedin_url", allow_blank=True
)
class Meta(UserDetailsSerializer.Meta):
fields = (
"pk",
"email",
"username",
"first_name",
"last_name",
"affiliation",
"github_url",
"google_scholar_url",
"linkedin_url",
)
def update(self, instance, validated_data):
profile_data = validated_data.pop("profile", {})
affiliation = profile_data.get("affiliation")
github_url = profile_data.get("github_url")
google_scholar_url = profile_data.get("google_scholar_url")
linkedin_url = profile_data.get("linkedin_url")
instance = super(ProfileSerializer, self).update(
instance, validated_data
)
profile = instance.profile
if profile_data and affiliation:
profile.affiliation = affiliation
profile.github_url = github_url
profile.google_scholar_url = google_scholar_url
profile.linkedin_url = linkedin_url
profile.save()
return instance
class CustomPasswordResetSerializer(PasswordResetSerializer):
def get_email_options(self):
super().get_email_options()
return {
'subject_template_name': 'account/email/password_reset_key_subject.txt',
'email_template_name': 'account/password_reset_email.html',
'html_email_template_name': 'account/password_reset_email.html',
}
I've been stuck to this issue for about 1 week and I'm losing my confidence.
open source project is here, incase you want to check.
UPDATE - Now I'm getting another problem in which my email looks like this, I'm not getting the variable passed here.
enter image description here
And it should look like this
enter image description here
password_reset_email.html
{% load i18n %}{% blocktrans with site_name=current_site.name site_domain=current_site.domain %}Hello from {{ site_name }}!
You're receiving this e-mail because you or someone else has requested a password for your user account at {{ site_domain }}.
It can be safely ignored if you did not request a password reset. Click the link below to reset your password.{% endblocktrans %}
{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}
{% if username %}{% blocktrans %}In case you forgot, your username is {{ username }}.{% endblocktrans %}
{% endif %}{% blocktrans with site_name=current_site.name site_domain=current_site.domain %}Thank you for using {{ site_name }}!
{{ site_domain }}{% endblocktrans %}
UPDATE - I solved this issue by changing the extension from html to txt. It's strange I know but worked for me.
I was able to solve this answer by simply putting this logging code to settings.py file.
LOGGING = {
'version': 1,
'disable_existing_loggers': True,
'formatters': {
'verbose': {
'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
},
},
'handlers': {
'console': {
'level': 'NOTSET',
'class': 'logging.StreamHandler',
'formatter': 'verbose'
}
},
'loggers': {
'': {
'handlers': ['console'],
'level': 'NOTSET',
},
'django.request': {
'handlers': ['console'],
'propagate': False,
'level': 'ERROR'
}
}
}
The org in which I was contributing they were using docker file to setup the environment and they have edited the logging file according to them.
By adding that code to the settings file I was able to receive the error logs.
Related
I have built a server with Django and I am receiving a 400 Bad Request within Postman when I check the POST method. However, it is displaying the JSON data within the Postman as well.
Originally, I thought it was a frontend issue, because my console log was stating
AxiosError {message: 'Request failed with status code 400', name: 'AxiosError', code: 'ERR_BAD_REQUEST', config: {…}, request: XMLHttpRequest, …}
As I stated before, the error is showing in Postman so I'm assuming it's actually a server issue.
Im real "finicky" when it comes to file colors, and if it is any color than the default color, I feel like there is errors within the file. Could these orange/beige files contain the problem? If I click on one of those files Im met with:
The file is not displayed in the editor because it is either binary or uses an unsupported text encoding.
Because I am new to django, I don't want to do something that's going to create an even bigger problem than what I already have.
Below will be my settings.py
"""
Django settings for django_rest_api project.
Generated by 'django-admin startproject' using Django 4.1.4.
For more information on this file, see
https://docs.djangoproject.com/en/4.1/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.1/ref/settings/
"""
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "django-insecure-2r=5^!2(nj*^*m*sa_39h(xldjpau&$wmn&pc5=^frws#w&25="
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
"corsheaders",
"rest_framework",
"todo_api",
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
"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",
]
CORS_ALLOW_ALL_ORIGINS = True
ROOT_URLCONF = "django_rest_api.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"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",
],
},
},
]
WSGI_APPLICATION = "django_rest_api.wsgi.application"
# Database
# https://docs.djangoproject.com/en/4.1/ref/settings/#databases
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": "todo_api",
"USER": "",
"PASSWORD" : '',
"HOST": "localhost"
}
}
# Password validation
# https://docs.djangoproject.com/en/4.1/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.1/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.1/howto/static-files/
STATIC_URL = "static/"
# Default primary key field type
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
Below is my views.py
from django.shortcuts import render
from rest_framework import generics
from .serializer import TodoSerializer
from .models import Todo
# Create your views here.
class TodoList(generics.ListCreateAPIView):
queryset = Todo.objects.all().order_by('id')
serializer_class = TodoSerializer
class TodoDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Todo.objects.all().order_by('id')
serializer_class = TodoSerializer
Im not exactly sure what information everyone needs to provide a proper solution for this, but hopefully I have provided more than enough.
I think it is worth noting that I am using postgreql and my database is working properly, and I can access Django admin and manually enter data from there as well.
Anytime I turn debug to false in my settings.py my site gives a server error. This is what my server shows and the site doesn't work again but when debug is true it works perfectly, I don't know what's wrong anyone with ideas on what might be going wrong
Performing system checks...
System check identified no issues (0 silenced).
October 21, 2022 - 23:47:07
Django version 4.1.2, using settings 'dlcfogbomoso.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
[21/Oct/2022 23:47:09] "GET / HTTP/1.1" 500 145
[21/Oct/2022 23:54:18] "GET / HTTP/1.1" 500 145
This is my settings.py file check it out for any error(s):
from pathlib import Path
import os
from decouple import config
from django.core.management.utils import get_random_secret_key
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent. Parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "Django-insecure-)=l1an%f&lb0+7z#!5l!ang_l!76ahs4eb-$((lt7vo1-mv0(*"
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False
ALLOWED_HOSTS = ["localhost", "127.0.0.1"]
# Application definition
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"whitenoise.runserver_nostatic",
"django.contrib.staticfiles",
"myapp",
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware",
"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",
]
ROOT_URLCONF = "dlcfogbomoso.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR, "templates"],
"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",
],
},
},
]
WSGI_APPLICATION = "dlcfogbomoso.wsgi.application"
# Database
# https://docs.djangoproject.com/en/4.1/ref/settings/#databases
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": "dlcfogbomoso",
"USER": "postgres",
"PASSWORD": "admin",
"HOST": "localhost"
}
}
# Password validation
# https://docs.djangoproject.com/en/4.1/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.1/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.1/howto/static-files/
STATIC_URL = "/static/"
MEDIA_ROOT = "/media/"
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "static"),
)
STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
# Default primary key field type
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
Please what am I doing wrong?
Not a definitive answer, but help. too long for comment
Go into your settings.py and add the code block below. This overrides the default Logging settings to output errors to the console even when debug is set as False. If you already have a LOGGING dict in the settings, just comment it out
Note: defaults are commented out, I just disabled the filters & disabled the existing default loggers
LOGGING = {
'version': 1,
'disable_existing_loggers': True,
# 'disable_existing_loggers': False,
'filters': {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse',
},
'require_debug_true': {
'()': 'django.utils.log.RequireDebugTrue',
},
},
'formatters': {
'django.server': {
'()': 'django.utils.log.ServerFormatter',
'format': '[{server_time}] {message}',
'style': '{',
}
},
'handlers': {
'console': {
'level': 'INFO',
#'filters': ['require_debug_true'],
'class': 'logging.StreamHandler',
},
'django.server': {
'level': 'INFO',
'class': 'logging.StreamHandler',
'formatter': 'django.server',
},
'mail_admins': {
'level': 'ERROR',
#'filters': ['require_debug_false'],
'class': 'django.utils.log.AdminEmailHandler'
}
},
'loggers': {
'django': {
'handlers': ['console', 'mail_admins'],
'level': 'INFO',
},
'django.server': {
'handlers': ['django.server'],
'level': 'INFO',
'propagate': False,
},
}
}
I integrated djang0-allauth with my app but something is not fully working.
Every time I try to login/sign by visiting http://127.0.0.1:8000/accounts/google/login/ and following the google auth flow, I am eventually sent to http://127.0.0.1:8000/accounts/social/signup/ where I am stuck in some sort of loop of sing-in and sing-up.
I guess I didn't set-up my settings properly? Or maybe I need to do something with the adapters.py
Just for context, I have a custom user model which maybe is also creating issues?
settings
"""
Django settings for mywebsite project.
Generated by 'django-admin startproject' using Django 3.2.5.
For more information on this file, see
https://docs.djangoproject.com/en/3.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.2/ref/settings/
"""
from pathlib import Path
import os
import django_on_heroku
import django_heroku
import cloudinary
import cloudinary_storage
import dj_database_url
from decouple import config
import cloudinary.uploader
import cloudinary.api
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', False)
#env docs https://apple.stackexchange.com/questions/356441/how-to-add-permanent-environment-variable-in-zsh
LOCAL = os.environ.get('ARE_WE_LOCAL', False)
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
DEBUG_PROPAGATE_EXCEPTIONS = True
ALLOWED_HOSTS = ['localhost', '127.0.0.1', 'produceit.herokuapp.com', 'ateam.productions', 'miliu.co']
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.sites',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'mywebsite',
'urlshortener.apps.UrlshortenerConfig',
'action.apps.ActionConfig',
'file_upload.apps.FileUploadConfig',
'myusermodel.apps.MyusermodelConfig',
'django_extensions',
'bootstrap_modal_forms',
'widget_tweaks',
'cloudinary',
'cloudinary_storage',
'guardian',
'allauth',
'allauth.account',
'allauth.socialaccount',
'allauth.socialaccount.providers.google',
'whitenoise.runserver_nostatic', # new
# https://dev.to/mdrhmn/django-google-authentication-using-django-allauth-18f8
]
MIDDLEWARE = [
#'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
'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',
]
ROOT_URLCONF = 'mywebsite.urls'
PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
# Other settings...
TEMPLATE_DIRS = (
os.path.join(PROJECT_ROOT, "templates"),
)
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'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',
],
},
},
]
WSGI_APPLICATION = 'mywebsite.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
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/3.2/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
#https://learndjango.com/tutorials/django-static-files
STATIC_URL = '/static/'
STATICFILES_DIRS = (str(BASE_DIR.joinpath('static')),)
STATIC_ROOT = str(BASE_DIR.joinpath('staticfiles'))
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' # new
# https://docs.djangoproject.com/en/3.2/howto/static-files/
#STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
#STATIC_URL = '/static/'
#STATICFILES_DIRS = [ os.path.join(BASE_DIR, "static"),]
#STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
# Cloudinary stuff
CLOUDINARY_API_KEY=os.environ.get('CLOUDINARY_API_KEY')
CLOUDINARY_API_SECRET=os.environ.get('CLOUDINARY_API_SECRET')
CLOUDINARY_STORAGE = {
'CLOUD_NAME': 'ateamproductions',
'API_KEY': CLOUDINARY_API_KEY,
'API_SECRET': CLOUDINARY_API_SECRET,
}
cloudinary.config(
cloud_name="ateamproductions",
api_key=CLOUDINARY_API_KEY,
api_secret=CLOUDINARY_API_SECRET
)
DEFAULT_FILE_STORAGE = 'cloudinary_storage.storage.MediaCloudinaryStorage'
# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
# DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
django_heroku.settings(locals())
#django_on_heroku.settings(locals())
# SECURE_SSL_REDIRECT=True
# SESSION_COOKIE_SECURE=True
# CSRF_COOKIE_SECURE=True
# SECURE_HSTS_SECONDS = 31536000
# SECURE_HSTS_INCLUDE_SUBDOMAINS=True
# SECURE_HSTS_PRELOAD=True
# import django_heroku
# django_heroku.settings(locals())
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
'allauth.account.auth_backends.AuthenticationBackend',
'guardian.backends.ObjectPermissionBackend',
]
SITE_ID = 3
LOGIN_REDIRECT_URL = '/'
ACCOUNT_ADAPTER = 'myusermodel.adapter.MyAccountAdapter'
# Additional configuration settings
SOCIALACCOUNT_QUERY_EMAIL = True
ACCOUNT_LOGOUT_ON_GET = True
ACCOUNT_UNIQUE_EMAIL = True
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_AUTHENTICATION_METHOD = 'email'
AUTH_USER_MODEL = 'myusermodel.CustomUser'
SOCIALACCOUNT_PROVIDERS = {
'google': {
'SCOPE': [
'profile',
'email',
],
'AUTH_PARAMS': {
'access_type': 'online',
}
}
}
#django
# Debugging in heroku live
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': ('%(asctime)s [%(process)d] [%(levelname)s] ' +
'pathname=%(pathname)s lineno=%(lineno)s ' +
'funcname=%(funcName)s %(message)s'),
'datefmt': '%Y-%m-%d %H:%M:%S'
},
'simple': {
'format': '%(levelname)s %(message)s'
}
},
'handlers': {
'null': {
'level': 'DEBUG',
'class': 'logging.NullHandler',
},
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'verbose'
}
},
'loggers': {
'testlogger': {
'handlers': ['console'],
'level': 'INFO',
}
}
}
COMPRESS_ENABLED = os.environ.get('COMPRESS_ENABLED', False)
SMS_BACKEND = 'sms.backends.dummy.SmsBackend'
TWILIO_ACCOUNT_SID = os.environ.get('TWILIO_ACCOUNT_SID', False)
TWILIO_AUTH_TOKEN = os.environ.get('TWILIO_AUTH_TOKEN', False)
TWILIO_PHONE = os.environ.get('TWILIO_PHONE', False)
custom user model
from django.contrib.auth.base_user import BaseUserManager
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.utils.translation import ugettext_lazy as _
class CustomUserManager(BaseUserManager):
"""
Custom user model manager where email is the unique identifiers
for authentication instead of usernames.
"""
def create_user(self, email, password, **extra_fields):
"""
Create and save a User with the given email and password.
"""
if not email:
raise ValueError(_('The Email must be set'))
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, password, **extra_fields):
"""
Create and save a SuperUser with the given email and password.
"""
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_active', True)
if extra_fields.get('is_staff') is not True:
raise ValueError(_('Superuser must have is_staff=True.'))
if extra_fields.get('is_superuser') is not True:
raise ValueError(_('Superuser must have is_superuser=True.'))
return self.create_user(email, password, **extra_fields)
class CustomUser(AbstractUser):
username = None
email = models.EmailField(_('email address'), unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = CustomUserManager()
def __str__(self):
return self.email
EDIT
The problem seems to be restricted to when I try to login with accounts that already exist in the DB but were not created throught he allauth flow.
I created a django project tha uses a customUser for authentication, following this blog post.
I now would like to attach another app to the project that is a REST API that leverages that authentication.
In this new app I create a model for the data that the uses will consume and I add as foreign key in the model the custom user model previously created.
#project/api/models.py
from django.contrib.postgres.fields import ArrayField
from django.db import models
from accounts.models import CustomUser
class Signal(models.Model):
name = models.CharField(max_length=30, blank=True, null=True)
data = ArrayField(models.FloatField(), unique=True)
threshold = models.FloatField(blank=True, null=True)
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
def __str__(self) -> str:
return f"{self.name}"
while the project/api/views.py file is
from django.template.defaultfilters import pluralize
from rest_framework.decorators import api_view
from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
from rest_framework.response import Response
from . import serializers
from .algorithm.compute_crossing import count_crossing_pos as count_cross
from .models import Signal
class SignalViewset(ListCreateAPIView):
permission_classes = [IsAuthenticated]
queryset = Signal.objects.all()
serializer_class = serializers.SignalSerializer
def get_queryset(self):
return super().get_queryset().filter(user=self.request.user)
class SignalDetail(RetrieveUpdateDestroyAPIView):
permission_classes = [IsAuthenticated]
queryset = Signal.objects.all()
serializer_class = serializers.SignalSerializer
def get_queryset(self):
return super().get_queryset().filter(user=self.request.user)
#api_view(http_method_names=["POST"])
def send_data(request: Request) -> Response():
"""send signal data with threshold in request payload
and compute crossing times around given threshold
:param request: [request payload]
:type request: [type]
"""
if request.user.is_authenticated:
count = count_cross(request.data.get("data"), request.data.get("threshold"))
return Response(
{
"status": "success",
"info": "signal crosses the given threshold {} tim{}".format(
count, pluralize(count, "e,es")
),
"count": str(count),
},
status=200,
)
else:
count = count_cross(request.data.get("data"), request.data.get("threshold"))
return Response(
{
"status": "success",
"info": "you are an AnonymousUser but I will give you an answer nonetheless \n \n signal crosses the given threshold {} tim{}".format(
count, pluralize(count, "e,es")
),
"count": str(count),
},
status=200,
)
Everytime I access the send_data endpoint I go into the else statement as request.user.is_authenticated is False.
how do I connect the rest api with the authentication (accounts) app?
my settings.py file is:
from pathlib import Path
from decouple import config
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
SYSTEM_ENV = config("SYSTEM_ENV")
ALLOWED_HOSTS = [
"*",
]
# Application definition
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"api",
"rest_framework",
"rest_framework.authtoken",
"dj_rest_auth",
"django.contrib.sites",
"allauth",
"allauth.account",
"dj_rest_auth.registration",
"accounts",
]
AUTH_USER_MODEL = "accounts.CustomUser" # new
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",
]
ROOT_URLCONF = "signal_crossing.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [str(BASE_DIR.joinpath("templates"))],
"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",
],
},
},
]
WSGI_APPLICATION = "signal_crossing.wsgi.application"
# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
if SYSTEM_ENV == "PRODUCTION" or SYSTEM_ENV == "STAGING":
print("docker")
DEBUG = False
SECRET_KEY = config("SECRET_KEY")
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql_psycopg2",
"NAME": "postgres",
"USER": "postgres",
"PASSWORD": "postgres",
"HOST": "db",
"PORT": 5432,
}
}
elif SYSTEM_ENV == "GITHUB_WORKFLOW":
DEBUG = True
SECRET_KEY = "TESTING_KEY"
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql_psycopg2",
"NAME": "github_actions",
"USER": "postgres",
"PASSWORD": "postgres",
"HOST": "127.0.0.1",
"PORT": "5432",
}
}
elif SYSTEM_ENV == "DEVELOPMENT":
DEBUG = True
SECRET_KEY = "DEVELOP_KEY"
# DATABASES = {
# "default": {
# "ENGINE": "django.db.backends.postgresql_psycopg2",
# "NAME": config("DB_NAME"),
# "USER": config("POSTGRES_LOCAL_USER"),
# "PASSWORD": config("POSTGRES_LOCAL_PASSWORD"),
# "HOST": "localhost",
# "PORT": "5432",
# }
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}
# Password validation
# https://docs.djangoproject.com/en/3.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/3.2/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/
STATIC_URL = "/static/"
# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
SITE_ID = 1
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": [
# 'rest_framework.authentication.TokenAuthentication',
"dj_rest_auth.jwt_auth.JWTCookieAuthentication",
],
}
REST_USE_JWT = True
JWT_AUTH_COOKIE = "my-app-auth"
AUTHENTICATION_BACKENDS = [
"django.contrib.auth.backends.ModelBackend",
# allauth specific authentication methods, such as login by e-mail
"allauth.account.auth_backends.AuthenticationBackend",
# Needed to login by username in Django admin, regardless of allauth
"django.contrib.auth.backends.ModelBackend",
]
# ACCOUNT_AUTHENTICATION_METHOD = "username"
# LOGIN_URL = "/login/"
# LOGIN_REDIRECT_URL = "/"
# LOGOUT_REDIRECT_URL = "/"
DJANGO_SETTINGS_MODULE = "signal_crossing.settings"
LOGIN_REDIRECT_URL = "home"
LOGOUT_REDIRECT_URL = "home"
I have an issue regarding setting up Django and Vuejs in order to make them work together. My issue is regarding csrftoken and how this it is passed between Django and Vuejs.
Therefore, my setup is as follow:
Django is running on http://localhost:8000
Vuejs is running on http://localhost8080
I am using django rest framework and SessionAuthentication.
settings.py
"""
Django settings for core project.
Generated by 'django-admin startproject' using Django 3.1.2.
For more information on this file, see
https://docs.djangoproject.com/en/3.1/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.1/ref/settings/
"""
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "8g+_gwm=s^kw69y3q55_p&n(_y^^fa!8a^(f7c)#d&md2617o9"
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ["*"]
# Cors setup
# CORS_ORIGIN_ALLOW_ALL = False
# For CSRF
CORS_ALLOWED_ORIGINS = [
"http://localhost:8080",
"http://127.0.0.1:8080",
]
CSRF_TRUSTED_ORIGINS = [
"http://localhost:8080",
"http://127.0.0.1:8080",
]
# For Cookie
CORS_ORIGIN_WHITELIST = ("http://localhost:8080", "http://127.0.0.1:8080")
CORS_ALLOW_CREDENTIALS = True
# CSRF_USE_SESSIONS = False
CSRF_COOKIE_HTTPONLY = False
SESSION_COOKIE_SAMESITE = "None"
CSRF_COOKIE_SAMESITE = None
SESSION_COOKIE_HTTPONLY = False
# Application definition
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"rest_framework",
"corsheaders",
"blog.apps.BlogConfig",
]
MIDDLEWARE = [
"corsheaders.middleware.CorsMiddleware",
"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",
]
ROOT_URLCONF = "core.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"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",
],
},
},
]
WSGI_APPLICATION = "core.wsgi.application"
# Database
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}
# Password validation
# https://docs.djangoproject.com/en/3.1/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/3.1/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.1/howto/static-files/
STATIC_URL = "/static/"
# Django Rest Framework Authentication
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": [
"rest_framework.authentication.SessionAuthentication",
],
"DEFAULT_PERMISSION_CLASSES": [
"rest_framework.permissions.IsAuthenticated",
],
}
serializers.py
class LoginSerializer(serializers.Serializer):
username = serializers.CharField()
password = serializers.CharField()
def validate(self, attrs):
user = authenticate(username=attrs.get("username"), password=attrs.get("password"))
if not user:
raise serializers.ValidationError("Incorect email or password")
return {"user": user}
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ["id", "username", "email"]
views.py
class LoginView(APIView):
permission_classes = [permissions.AllowAny]
def post(self, request):
serializer = LoginSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data.get("user")
login(request, user)
return Response(UserSerializer(user, context={"request": request}).data)
And this is the resource that I am trying to access:
views.py
class PostList(APIView):
""" Simple post view. """
def get(self, request):
post = Post.objects.all()
serializer = PostSerializer(post, many=True)
return Response(serializer.data)
def post(self, request):
serializer = PostSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Whenever I try to access this from frontend, I get the following error: Status Code: 403 Forbidden
Login.vuejs
<template>
<div class="home">
<h1>{{ message }}</h1>
<h2>Posts</h2>
<ul>
<li v-for="post in posts" :key="post.id">
{{ post.title }}
</li>
</ul>
<p>
<button #click="getPosts">Get Posts</button>
<button #click="createPost">Create Post</button>
<button #click="login">Login</button>
</p>
</div>
</template>
<script>
// # is an alias to /src
import axios from "axios";
// import Cookies from "js-cookie";
axios.defaults.xsrfCookieName = "csrftoken";
axios.defaults.xsrfHeaderName = "X-CSRFToken";
export default {
name: "Home",
data() {
return {
message: "",
posts: [],
};
},
methods: {
login: function() {
const baseUrl = "http://127.0.0.1:8000/rest-api/auth/";
axios
.post(baseUrl, { username: "madalin", password: "test" })
.then((response) => {
console.log(response);
});
},
createPost: function() {
const baseUrl = "http://127.0.0.1:8000/rest-api/posts/";
axios
.post(baseUrl, {
title: "Post title vuejs",
body: "This is a simple post body",
})
.then((response) => {
console.log(response);
});
},
getPosts: function() {
const baseUrl = "http://127.0.0.1:8000/rest-api/posts/";
axios
.get(baseUrl, {
withCredentials: true,
})
.then((response) => {
this.posts = response.data;
});
},
},
};
</script>
Now, whne I click on login, the response header is as follow:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: http://127.0.0.1:8080
Allow: POST, OPTIONS
Content-Length: 63
Content-Type: application/json
Date: Tue, 20 Oct 2020 22:22:51 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.8.5
Set-Cookie: csrftoken=6psCovwjDLVYzoZUDpiRDMjS6cQ6d8N9ubT3wNVjUZFAhmHinEFecYOHuWP2gC3J; expires=Tue, 19 Oct 2021 22:22:51 GMT; Max-Age=31449600; Path=/
Set-Cookie: sessionid=1txxggzki1r4s3cm0pc6faiityo36wep; expires=Tue, 03 Nov 2020 22:22:51 GMT; Max-Age=1209600; Path=/; SameSite=None
Vary: Accept, Cookie, Origin
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
As per my understanding, the csrftoken from response header should be send forward to Django with each new request. Request which is comming from axios.
Is there anything else that I can do/check?
I am struggling with this issue for the last 2 weeks at least, any help will be very appreciate.
Thank you,
I have managed to figure out what is the right setup in order to use SessionAuthentication with Django Rest Framework.
I will post the answer here maybe will help someone.
Step 1 - Make sure you have the following setup in your settings.py file
# For CORS and CSRF
CORS_ALLOW_CREDENTIALS = True
CORS_ALLOWED_ORIGINS = [
"http://localhost:8080",
"http://127.0.0.1:8080",
"http://localhost:8000",
"http://127.0.0.1:8000",
]
CSRF_TRUSTED_ORIGINS = [
"http://localhost:8080",
"http://127.0.0.1:8080",
"http://localhost:8000",
"http://127.0.0.1:8000",
]
# For Cookie
CSRF_COOKIE_HTTPONLY = True
SESSION_COOKIE_HTTPONLY = True
# Since the frontend is on `http://localhost:8080` and the backend is on `http://localhost:8000`, they are two different origins and we need to set samesite to false
# UPDATE: Starting with django 3.1 this must be set to 'None'
SESSION_COOKIE_SAMESITE = 'None'
CSRF_COOKIE_SAMESITE = 'None'
# When you test this make sure both applications are on the same domain. Like `http://127.0.0.1:8000` and `http://127.0.0.1:8080`
Step 2 - Create the login and logout views
from django.contrib.auth import login, logout
from rest_framework import permissions, status
from rest_framework.response import Response
from rest_framework.views import APIView
class LoginView(APIView):
permission_classes = [permissions.AllowAny]
def post(self, request):
serializer = LoginSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data.get("user")
login(request, user)
return Response(UserSerializer(user, context={"request": request}).data)
class LogoutView(APIView):
permission_classes = [permissions.AllowAny]
def get(self, request):
logout(request=request)
return Response({"message": "You have been logout succesfully"})
Step 3 - Make sure that every request from frontend is made with credentials included
import axios from "axios";
const API = axios.create({
baseURL: `http://127.0.0.1:8000/rest-api/`,
headers: {
Accept: "application/json",
"Content-type": "application/json"
},
timeout: 10000,
withCredentials: true
});
export default {
login(payload) {
return API.post("auth/", payload);
},
logout() {
return API.get("logout/");
},
}