RelatedObjectDoesNotExist - у пользователя нет профиля - PullRequest
0 голосов
/ 02 августа 2020

Я здесь новенький, привет. Создание моего первого приложения Django пока шло отлично. Теперь у меня есть небольшая проблема, которую я не могу решить самостоятельно.

Когда я пытаюсь создать нового пользователя, связанный профиль не создается.

RelatedObjectDoesNotExist at /login/
User has no profile.
Request Method: POST
Request URL:    http://127.0.0.1:8000/login/
Django Version: 3.0.7
Exception Type: RelatedObjectDoesNotExist
Exception Value:    
User has no profile.
Exception Location: /Users/dmszanowski/PycharmProjects/django_to_dos/venv/lib/python3.8/site-packages/django/db/models/fields/related_descriptors.py in __get__, line 420

На самом деле признателен за вашу помощь.

вывод

[02/Aug/2020 02:20:14] "GET / HTTP/1.1" 200 5034
[02/Aug/2020 02:20:14] "GET /static/list/main.css HTTP/1.1" 304 0
[02/Aug/2020 02:20:16] "GET /register/ HTTP/1.1" 200 6400
[02/Aug/2020 02:20:33] "POST /register/ HTTP/1.1" 200 6571
[02/Aug/2020 02:20:43] "POST /register/ HTTP/1.1" 302 0
[02/Aug/2020 02:20:43] "GET /login/ HTTP/1.1" 200 5944
Internal Server Error: /login/
Traceback (most recent call last):
  File "/Users/dmszanowski/PycharmProjects/django_to_dos/venv/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/Users/dmszanowski/PycharmProjects/django_to_dos/venv/lib/python3.8/site-packages/django/core/handlers/base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/Users/dmszanowski/PycharmProjects/django_to_dos/venv/lib/python3.8/site-packages/django/core/handlers/base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Users/dmszanowski/PycharmProjects/django_to_dos/django_project/users/views.py", line 30, in login_view
    login(request, user)
  File "/Users/dmszanowski/PycharmProjects/django_to_dos/venv/lib/python3.8/site-packages/django/contrib/auth/__init__.py", line 131, in login
    user_logged_in.send(sender=user.__class__, request=request, user=user)
  File "/Users/dmszanowski/PycharmProjects/django_to_dos/venv/lib/python3.8/site-packages/django/dispatch/dispatcher.py", line 173, in send
    return [
  File "/Users/dmszanowski/PycharmProjects/django_to_dos/venv/lib/python3.8/site-packages/django/dispatch/dispatcher.py", line 174, in <listcomp>
    (receiver, receiver(signal=self, sender=sender, **named))
  File "/Users/dmszanowski/PycharmProjects/django_to_dos/django_project/users/signals.py", line 21, in got_online
    user.profile.is_online = True
  File "/Users/dmszanowski/PycharmProjects/django_to_dos/venv/lib/python3.8/site-packages/django/db/models/fields/related_descriptors.py", line 420, in __get__
    raise self.RelatedObjectDoesNotExist(
django.contrib.auth.models.User.profile.RelatedObjectDoesNotExist: User has no profile.
[02/Aug/2020 02:21:17] "POST /login/ HTTP/1.1" 500 90315

apps.py

from django.apps import AppConfig


class UsersConfig(AppConfig):
    name = 'users'

    def ready(self):
        import users.signals

forms.py

from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Fieldset, ButtonHolder, Submit


class UserRegisterForm(UserCreationForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.layout = Layout(
            Fieldset('Register', 'username', 'email', 'password1', 'password2', css_class='text-white'),
            ButtonHolder(Submit('submit', 'Submit', css_class='btn-dark mb-3')))

    class Meta:
        model = User
        fields = ['username', 'email', 'password1', 'password2']

models.py

from django.contrib.auth.models import User
from django.db import models
import os
from PIL import Image
from .validators import validate_image_file_extension
from .storage import OverwriteFile


class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    is_private = models.BooleanField(default=0)
    is_online = models.BooleanField(default=0)
    image = models.ImageField(default='profile_pics/default.jpg', upload_to='profile_pics', blank=True, storage=OverwriteFile(), validators=[validate_image_file_extension])

    def __str__(self):
        return f'{self.user.username}'

    def save(self, *args, **kwargs):
        # image_path = os.path.join('profile_pics/', self.image.path)
        img = Image.open(self.image.path)
        if img.height > 300 or img.width > 300:
            output_size = (300, 300)
            img.thumbnail(output_size)
        img = img.convert('RGB')
        if 'default.jpg' not in self.image.name:
            os.remove(self.image.path)
            self.image.name = 'profile_pics/' + str(self.user_id) + "." + self.image.name.split(".", 2)[1]
        img.save(self.image.path, "JPEG")

signal.py

from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth.models import User
from .models import Profile


@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)


@receiver(post_save, sender=User)
def save_profile(sender, instance, **kwargs):
    instance.profile.save()

storage.py

from django.core.files.storage import FileSystemStorage
from django.conf import settings
import os


class OverwriteFile(FileSystemStorage):
    def get_available_name(self, name, max_length=None):
        if self.exists(name):
            os.remove(os.path.join(settings.MEDIA_ROOT, name))
        return name

views.py

from django.shortcuts import render, redirect
from django.contrib import messages
from .forms import UserRegisterForm
from .models import User, Profile


def register_view(request):
    if request.method == 'POST':
        user_register_form = UserRegisterForm(request.POST)
        if user_register_form.is_valid():
            user = user_register_form.save()
            Profile.objects.create(**{'user': user})
            messages.success(request, f'Your account has been created! You are now able to log in')
            return redirect('login')
    else:
        user_register_form = UserRegisterForm()
    return render(request, 'users/register.html', {'user_register_form': user_register_form})

validators.py

import os
from django.core.exceptions import ValidationError


def validate_image_file_extension(value):
    ext = os.path.splitext(value.name)[1]
    valid_ext = ['.png', '.jpg', '.jpeg']
    if not ext.lower() in valid_ext:
        raise ValidationError('Unsupported image file extension. Allowed vales %(value)s', params={'value': valid_ext})

settings.py

INSTALLED_APPS = [
    'users.apps.UsersConfig',
    'list.apps.ListConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'crispy_forms',
]

STATICFILES_DIRS = (
    os.path.join('static'),
)
STATIC_URL = '/static/'

CRISPY_TEMPLATE_PACK = 'bootstrap4'

LOGIN_REDIRECT_URL = ''
LOGIN_URL = 'login'

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'

Ответы [ 2 ]

0 голосов
/ 02 августа 2020

Я разобрался. Я случайно удалил super().save() из своего Profile Model. После повторного добавления он работает отлично!

fixed models.py

from django.contrib.auth.models import User
from django.db import models
import os
from PIL import Image
from .validators import validate_image_file_extension
from .storage import OverwriteFile


class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    is_private = models.BooleanField(default=0)
    is_online = models.BooleanField(default=0)
    image = models.ImageField(default='profile_pics/default.jpg', upload_to='profile_pics', blank=True, storage=OverwriteFile(), validators=[validate_image_file_extension])

    def __str__(self):
        return f'{self.user.username}'

    def save(self, *args, **kwargs):
        super().save()
        img = Image.open(self.image.path)
        if img.height > 300 or img.width > 300:
            output_size = (300, 300)
            img.thumbnail(output_size)
        img = img.convert('RGB')
        if 'default.jpg' not in self.image.name:
            os.remove(self.image.path)
            self.image.name = 'profile_pics/' + str(self.user_id) + "." + self.image.name.split(".", 2)[1]
        img.save(self.image.path, "JPEG")
0 голосов
/ 02 августа 2020

Дело в том, что объект profile по умолчанию не приходит. Вы должны добавить что-то вроде этого:

if form.is_valid():
    user = form.save()
    Profile.objects.create(**{'user': user})

и да, добавьте это в свой файл views.py (который вы не предоставили). Также замените любое имя формы, которое вы используете, на 'form'.

Ссылка

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...