[英]Django API OneToOne relationship using Auth, User model, Views, Serializers
I'm trying to connect the HighScore model to my User model. 我正在尝试将HighScore模型连接到我的用户模型。 This way I can save a HighScore instance for each User.
这样,我可以为每个用户保存一个HighScore实例。 No matter what I do, I get a 500 internal server error.
无论我做什么,都会收到500个内部服务器错误。
I've tried creating a custom user model using AbstractUser. 我尝试使用AbstractUser创建自定义用户模型。 I've tried setting up OneToOne using settings.AUTH_USER_MODEL, and I've tried doing User = get_user_model() and all come back with a 500 internal server error.
我尝试使用settings.AUTH_USER_MODEL设置OneToOne,并且尝试执行User = get_user_model(),但都返回500内部服务器错误。
# models.py
from django.conf import settings
from django.db import models
# Create your models here.
class HighScore(models.Model):
# user = models.OneToOneField(
# settings.AUTH_USER_MODEL,
# on_delete=models.CASCADE,
# primary_key=True,
# )
value = models.IntegerField(default=0)
def __str__(self):
return "{}".format(self.value)
# urls.py
from django.urls import path
from .views import ListHighScoresView, CreateHighScoresView, HighScoresDetailView, LoginView, RegisterUsersView
urlpatterns = [
path("highscores/", ListHighScoresView.as_view(), name="high-scores-all"),
path("highscores/create/", CreateHighScoresView.as_view(), name="high-scores-create"),
path("highscores/<int:pk>/", HighScoresDetailView.as_view(), name="high-scores-detail"),
path("auth/login/", LoginView.as_view(), name="auth-login"),
path("auth/register/", RegisterUsersView.as_view(), name="auth-register"),
]
# serializers.py
from rest_framework import serializers
from .models import HighScore
from django.contrib.auth.models import User
class HighScoreSerializer(serializers.ModelSerializer):
class Meta:
model = HighScore
fields = ("id", "value")
def update(self, instance, validated_data):
instance.value = validated_data.get("value", instance.value)
# instance.user = validated_data.get("user", instance.user)
instance.save()
return instance
class TokenSerializer(serializers.Serializer):
token = serializers.CharField(max_length=255)
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ("username", "email")
# migration 0001_initial.py
# Generated by Django 2.0.3 on 2019-09-11 07:55
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0009_alter_user_last_name_max_length'),
]
operations = [
migrations.CreateModel(
name='HighScore',
fields=[
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL)),
('value', models.IntegerField(default=0)),
],
),
]
# views.py
from django.shortcuts import render
from django.contrib.auth.models import User
from django.contrib.auth import authenticate, login
from rest_framework_jwt.settings import api_settings
from rest_framework.response import Response
from rest_framework.generics import GenericAPIView, RetrieveUpdateDestroyAPIView, ListAPIView
from rest_framework.views import APIView
from rest_framework import permissions, status
from .decorators import validate_request_data
from .models import HighScore
from .serializers import HighScoreSerializer, TokenSerializer, UserSerializer
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
class CreateHighScoresView(GenericAPIView):
""" GET and POST highscores/ """
queryset = HighScore.objects.all()
serializer_class = HighScoreSerializer
permission_classes = (permissions.IsAuthenticated,)
@validate_request_data
def post(self, request, *args, **kwargs):
new_high_score = HighScore.objects.create(
# user=request.user,
value=request.data["value"],
)
return Response(
data=HighScoreSerializer(new_high_score).data,
status=status.HTTP_201_CREATED
)
class HighScoresDetailView(RetrieveUpdateDestroyAPIView):
""" GET, PUT, DELETE highscores/:id/ """
queryset = HighScore.objects.all()
serializer_class = HighScoreSerializer
def get(self, request, *args, **kwargs):
try:
new_high_score = self.queryset.get(pk=kwargs["pk"])
return Response(HighScoreSerializer(new_high_score).data)
except HighScore.DoesNotExist:
return Response(
data={
"message": "Yo, that High Score with id: {} does not exist".format(kwargs["pk"])
},
status=status.HTTP_404_NOT_FOUND
)
@validate_request_data
def put(self, request, *args, **kwargs):
try:
new_high_score = self.queryset.get(pk=kwargs["pk"])
serializer = HighScoreSerializer()
updated_high_score = serializer.update(new_high_score, request.data)
return Response(HighScoreSerializer(updated_high_score).data)
except HighScore.DoesNotExist:
return Response(
data={
"message": "Yo, that High Score with id: {} does not exist".format(kwargs["pk"])
},
status=status.HTTP_404_NOT_FOUND
)
def delete(self, request, *args, **kwargs):
try:
new_high_score = self.queryset.get(pk=kwargs["pk"])
new_high_score.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
except HighScore.DoesNotExist:
return Response(
data={
"message": "Yo, that High Score with id: {} does not exist".format(kwargs["pk"])
},
status=status.HTTP_404_NOT_FOUND
)
class ListHighScoresView(ListAPIView):
""" Provides a GET method handler. """
queryset = HighScore.objects.all()
serializer_class = HighScoreSerializer
permission_classes = (permissions.IsAuthenticated,)
class LoginView(APIView):
""" POST auth/login/ """
# This permission class will overide the global permission class setting
permission_classes = (permissions.AllowAny,)
queryset = User.objects.all()
def post(self, request, *args, **kwargs):
username = request.data.get("username", "")
password = request.data.get("password", "")
user = authenticate(request, username=username, password=password)
if user is not None:
# Login saves the user's ID in the session, using Django's session framework.
login(request, user)
serializer = TokenSerializer(
data={
# Using drf jwt utility functions to generate a token
"token": jwt_encode_handler(
jwt_payload_handler(user)
)
}
)
serializer.is_valid()
username = user.username
email = user.email
token = serializer.data["token"]
return Response(
data={
"username": username,
"email": email,
"token": token
},
status=status.HTTP_201_CREATED
)
return Response(status=status.HTTP_401_UNAUTHORIZED)
class RegisterUsersView(APIView):
""" Post auth/register/ """
permission_classes = (permissions.AllowAny,)
def post(self, request, *args, **kwargs):
username = request.data.get("username", "")
password = request.data.get("password", "")
email = request.data.get("email", "")
if not username and not password and not email:
return Response(
data={
"message": "Yo, gotta have a username, password, and email to register."
},
status=status.HTTP_400_BAD_REQUEST
)
new_user = User.objects.create_user(
username=username, password=password, email=email
)
user = authenticate(request, username=username, password=password)
login(request, user)
serializer = TokenSerializer(
data={
# Using drf jwt utility functions to generate a token.
"token": jwt_encode_handler(
jwt_payload_handler(user)
)
}
)
serializer.is_valid()
token = serializer.data["token"]
return Response(
data={
"username": username,
"email": email,
"token": token
},
status=status.HTTP_201_CREATED
)
#settings.py
import os
import datetime
import django_heroku
from django.conf import settings
from django.http import HttpResponseRedirect
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
DEBUG = False
ALLOWED_HOSTS = [
'127.0.0.1',
'.herokuapp.com'
]
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'corsheaders',
'rest_framework',
'edjudicator_game',
]
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',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
]
SECURE_SSL_REDIRECT = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
ROOT_URLCONF = 'edjudicator_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 = 'edjudicator_api.wsgi.application'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'c',
'USER': 'a',
'PASSWORD': 'b',
'HOST': 'localhost',
'PORT': '5432',
},
}
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',
},
]
LOGIN_REDIRECT_URL = '/'
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'America/Denver'
USE_I18N = True
USE_L10N = True
USE_TZ = True
PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
REST_FRAMEWORK = {
'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning',
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
'rest_framework.authentication.BasicAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly',
],
}
JWT_AUTH = {
'JWT_ENCODE_HANDLER':
'rest_framework_jwt.utils.jwt_encode_handler',
'JWT_DECODE_HANDLER':
'rest_framework_jwt.utils.jwt_decode_handler',
'JWT_PAYLOAD_HANDLER':
'rest_framework_jwt.utils.jwt_payload_handler',
'JWT_PAYLOAD_GET_USER_ID_HANDLER':
'rest_framework_jwt.utils.jwt_get_user_id_from_payload_handler',
'JWT_RESPONSE_PAYLOAD_HANDLER':
'rest_framework_jwt.utils.jwt_response_payload_handler',
'JWT_SECRET_KEY': SECRET_KEY,
'JWT_GET_USER_SECRET_KEY': None,
'JWT_PUBLIC_KEY': None,
'JWT_PRIVATE_KEY': None,
'JWT_ALGORITHM': 'HS256',
'JWT_VERIFY': True,
'JWT_VERIFY_EXPIRATION': True,
'JWT_LEEWAY': 0,
'JWT_EXPIRATION_DELTA': datetime.timedelta(hours=4),
'JWT_AUDIENCE': None,
'JWT_ISSUER': None,
'JWT_ALLOW_REFRESH': False,
'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7),
'JWT_AUTH_HEADER_PREFIX': 'Bearer',
'JWT_AUTH_COOKIE': None,
}
django_heroku.settings(locals())
class SSLMiddleware(object):
def process_request(self, request):
if not any([settings.DEBUG, request.is_secure(), request.META.get("HTTP_X_FORWARDED_PROTO", "") == 'https']):
url = request.build_absolute_uri(request.get_full_path())
secure_url = url.replace("http://", "https://")
return HttpResponseRedirect(secure_url)
# error stack
2019-09-11T07:52:36.173427+00:00 heroku[router]: at=info method=POST path="/api/v1/auth/login/" host=edjudicatorback.herokuapp.com request_id=dcdade1d-4581-4914-88bb-a90d40bce845 fwd="4.34.47.42" dyno=web.1 connect=1ms service=436ms status=201 bytes=883 protocol=https
2019-09-11T07:52:36.176354+00:00 app[web.1]: 10.143.94.115 - - [11/Sep/2019:01:52:36 -0600] "POST /api/v1/auth/login/ HTTP/1.1" 201 257 "https://edjudicator.herokuapp.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36"
2019-09-11T07:52:42.632366+00:00 heroku[router]: at=info method=GET path="/api/v1/highscores/" host=edjudicatorback.herokuapp.com request_id=2ae69eaf-3a2f-4818-a811-3bfcd4a6029b fwd="4.34.47.42" dyno=web.1 connect=1ms service=123ms status=500 bytes=18715 protocol=https
2019-09-11T07:52:42.526114+00:00 app[web.1]: Internal Server Error: /api/v1/highscores/
2019-09-11T07:52:42.526128+00:00 app[web.1]: Traceback (most recent call last):
2019-09-11T07:52:42.526139+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute
2019-09-11T07:52:42.526142+00:00 app[web.1]: return self.cursor.execute(sql, params)
2019-09-11T07:52:42.526144+00:00 app[web.1]: psycopg2.errors.UndefinedColumn: column edjudicator_game_highscore.user_id does not exist
2019-09-11T07:52:42.526148+00:00 app[web.1]: LINE 1: SELECT "edjudicator_game_highscore"."user_id", "edjudicator_...
2019-09-11T07:52:42.526151+00:00 app[web.1]: ^
2019-09-11T07:52:42.526153+00:00 app[web.1]:
2019-09-11T07:52:42.526155+00:00 app[web.1]:
2019-09-11T07:52:42.526161+00:00 app[web.1]: The above exception was the direct cause of the following exception:
2019-09-11T07:52:42.526163+00:00 app[web.1]:
2019-09-11T07:52:42.526166+00:00 app[web.1]: Traceback (most recent call last):
2019-09-11T07:52:42.526168+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/django/core/handlers/exception.py", line 35, in inner
2019-09-11T07:52:42.526170+00:00 app[web.1]: response = get_response(request)
2019-09-11T07:52:42.526178+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/django/core/handlers/base.py", line 128, in _get_response
2019-09-11T07:52:42.526180+00:00 app[web.1]: response = self.process_exception_by_middleware(e, request)
2019-09-11T07:52:42.526183+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/django/core/handlers/base.py", line 126, in _get_response
2019-09-11T07:52:42.526185+00:00 app[web.1]: response = wrapped_callback(request, *callback_args, **callback_kwargs)
2019-09-11T07:52:42.526187+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
2019-09-11T07:52:42.526190+00:00 app[web.1]: return view_func(*args, **kwargs)
2019-09-11T07:52:42.526192+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/django/views/generic/base.py", line 69, in view
2019-09-11T07:52:42.526194+00:00 app[web.1]: return self.dispatch(request, *args, **kwargs)
2019-09-11T07:52:42.526197+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/rest_framework/views.py", line 505, in dispatch
2019-09-11T07:52:42.526199+00:00 app[web.1]: response = self.handle_exception(exc)
2019-09-11T07:52:42.526201+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/rest_framework/views.py", line 465, in handle_exception
2019-09-11T07:52:42.526203+00:00 app[web.1]: self.raise_uncaught_exception(exc)
2019-09-11T07:52:42.526205+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/rest_framework/views.py", line 476, in raise_uncaught_exception
2019-09-11T07:52:42.526207+00:00 app[web.1]: raise exc
2019-09-11T07:52:42.526210+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/rest_framework/views.py", line 502, in dispatch
2019-09-11T07:52:42.526212+00:00 app[web.1]: response = handler(request, *args, **kwargs)
2019-09-11T07:52:42.526214+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/rest_framework/generics.py", line 199, in get
2019-09-11T07:52:42.526216+00:00 app[web.1]: return self.list(request, *args, **kwargs)
2019-09-11T07:52:42.526217+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/rest_framework/mixins.py", line 46, in list
2019-09-11T07:52:42.526219+00:00 app[web.1]: return Response(serializer.data)
2019-09-11T07:52:42.526220+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/rest_framework/serializers.py", line 757, in data
2019-09-11T07:52:42.526222+00:00 app[web.1]: ret = super().data
2019-09-11T07:52:42.526224+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/rest_framework/serializers.py", line 261, in data
2019-09-11T07:52:42.526226+00:00 app[web.1]: self._data = self.to_representation(self.instance)
2019-09-11T07:52:42.526227+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/rest_framework/serializers.py", line 675, in to_representation
2019-09-11T07:52:42.526229+00:00 app[web.1]: self.child.to_representation(item) for item in iterable
2019-09-11T07:52:42.526231+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/django/db/models/query.py", line 272, in __iter__
2019-09-11T07:52:42.526232+00:00 app[web.1]: self._fetch_all()
2019-09-11T07:52:42.526234+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/django/db/models/query.py", line 1179, in _fetch_all
2019-09-11T07:52:42.526235+00:00 app[web.1]: self._result_cache = list(self._iterable_class(self))
2019-09-11T07:52:42.526237+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/django/db/models/query.py", line 53, in __iter__
2019-09-11T07:52:42.526239+00:00 app[web.1]: results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
2019-09-11T07:52:42.526240+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1066, in execute_sql
2019-09-11T07:52:42.526242+00:00 app[web.1]: cursor.execute(sql, params)
2019-09-11T07:52:42.526243+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/django/db/backends/utils.py", line 100, in execute
2019-09-11T07:52:42.526245+00:00 app[web.1]: return super().execute(sql, params)
2019-09-11T07:52:42.526246+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/django/db/backends/utils.py", line 68, in execute
2019-09-11T07:52:42.526248+00:00 app[web.1]: return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
2019-09-11T07:52:42.526250+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/django/db/backends/utils.py", line 77, in _execute_with_wrappers
2019-09-11T07:52:42.526251+00:00 app[web.1]: return executor(sql, params, many, context)
2019-09-11T07:52:42.526253+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute
2019-09-11T07:52:42.526254+00:00 app[web.1]: return self.cursor.execute(sql, params)
2019-09-11T07:52:42.526256+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/django/db/utils.py", line 89, in __exit__
2019-09-11T07:52:42.526265+00:00 app[web.1]: raise dj_exc_value.with_traceback(traceback) from exc_value
2019-09-11T07:52:42.526267+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute
2019-09-11T07:52:42.526268+00:00 app[web.1]: return self.cursor.execute(sql, params)
2019-09-11T07:52:42.526270+00:00 app[web.1]: django.db.utils.ProgrammingError: column edjudicator_game_highscore.user_id does not exist
2019-09-11T07:52:42.526271+00:00 app[web.1]: LINE 1: SELECT "edjudicator_game_highscore"."user_id", "edjudicator_...
2019-09-11T07:52:42.526273+00:00 app[web.1]: ^
2019-09-11T07:52:42.526325+00:00 app[web.1]:
2019-09-11T07:52:42.633754+00:00 app[web.1]: 10.143.94.115 - - [11/Sep/2019:01:52:42 -0600] "GET /api/v1/highscores/ HTTP/1.1" 500 18385 "https://edjudicator.herokuapp.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36"
All I'm trying to do is have the HighScore model have a OneToOne relationship with the User. 我要做的就是让HighScore模型与用户建立OneToOne关系。 That way when the User logs in I can send the POST request from my frontend to create a HighScore for that User.
这样,当用户登录时,我可以从前端发送POST请求以为该用户创建HighScore。 Any and all help will be sooo much appreciated!!!
任何和所有帮助将非常感谢!!!
EDIT: I needed to reset my database. 编辑:我需要重置我的数据库。 Dropped my psql database using
drop database <database name>
then create database <db name> with owner <user_name>
also did heroku restart
plus heroku pg:reset DATABASE
and ran migrations on both to get them working. 使用
drop database <database name>
我的psql数据库,然后create database <db name> with owner <user_name>
也heroku restart
heroku pg:reset DATABASE
并同时运行heroku pg:reset DATABASE
并同时运行了迁移,以使它们正常工作。 Thank you all! 谢谢你们!
You don't need to create a frontend for this, you can simply use a post save signal
to do it: 您不需要为此创建前端,只需使用
post save signal
即可:
class HighScore(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
primary_key=True,
)
value = models.IntegerField(default=0)
@receiver(post_save, sender=User)
def create_user_score(sender, instance, created, **kwargs):
if created:
HighScore.objects.create(user=instance)
The error tells you what is going on: you simply haven't added the new column to the database. 该错误告诉您正在发生的事情:您只是没有将新列添加到数据库中。
You need to migrate. 您需要迁移。 Run
makemigrations
on your local machine, commit the result, push to Heroku, then run migrate
on Heroku. 运行
makemigrations
在本地计算机上,提交的结果,推到Heroku上,然后运行migrate
在Heroku。
Note, you really shouldn't be developing directly on Heroku anyway. 注意,您实际上绝对不应该直接在Heroku上进行开发。 Run the dev server locally.
在本地运行开发服务器。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.