Несколько объектов модели сохраняются в db, хотя просмотр экранирует MyModel.DoesNotExist, нарушая работу приложения
Я получаю следующую ошибку, пытаясь получить профиль пользователя из mongodb:
New searches for user 555555555
[{'search_term': 'ibm'}, {'search_term': 'ry'}]
Internal Server Error: /users/555555555
Traceback (most recent call last):
File "/home/cchilders/.local/lib/python3.10/site-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/home/cchilders/.local/lib/python3.10/site-packages/django/core/handlers/base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/cchilders/.local/lib/python3.10/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/home/cchilders/projects/stocks_backend/users/views.py", line 50, in get_user_profile
user = UserProfile.objects.get(user_id=user_id)
File "/home/cchilders/.local/lib/python3.10/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/cchilders/.local/lib/python3.10/site-packages/django/db/models/query.py", line 433, in get
raise self.model.MultipleObjectsReturned(
users.models.UserProfile.MultipleObjectsReturned: get() returned more than one UserProfile -- it returned 2!
[21/Aug/2022 09:45:31] "POST /users/555555555 HTTP/1.1" 500 76920
Наличие нескольких профилей пользователей нарушает работу приложения, и для каждого пользователя должен быть только один. Я также получаю дубликаты в другой модели StockInfo.
Мое представление, похоже, сохраняет нового пользователя только тогда, когда для этого идентификатора пользователя не существует ни одного, поэтому я запутался
users/views.py:
from django.shortcuts import render
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
import json
from helpers.view_functions import parse_request_body
from .models import UserProfile
@csrf_exempt
def get_user_profile(request, user_id):
if request.method == 'GET':
try:
user = UserProfile.objects.get(user_id=user_id)
print("user found")
except UserProfile.DoesNotExist:
print("user does not exist exception")
profile = UserProfile()
profile.user_id = user_id
profile.searches = [
{'search_term': 'hd'},
{'search_term': 'wba'},
]
profile.display_settings = [
{'setting_name': 'showYieldChange', 'visible': True},
{'setting_name': 'showAllDividends', 'visible': True},
]
profile.save()
print("user saved in db")
user = UserProfile.objects.get(user_id=user_id)
except Exception as error:
print("got an unknown exception:")
print(error)
data = {
'user_id': user.user_id,
'searches': user.searches,
'display_settings': user.display_settings
}
json_data = json.dumps(data)
return HttpResponse({json_data}, content_type='application/json')
if request.method == 'POST':
body = parse_request_body(request)
searches = body['searches']
searches_objects = [{'search_term': x} for x in searches]
print("New searches for user {user_id}".format(user_id=user_id))
print(searches_objects)
user = UserProfile.objects.get(user_id=user_id)
user.searches = searches_objects
user.display_settings = body['display_settings']
user.save()
return HttpResponse("it worked")
если это имеет значение, то вот users/models.py:
from djongo import models
class RecentSearch(models.Model):
search_term = models.CharField(max_length=100)
class Meta:
abstract = True
class DisplaySetting(models.Model):
setting_name = models.CharField(max_length=150)
visible = models.BooleanField()
class Meta:
abstract = True
class UserProfile(models.Model):
user_id = models.CharField(max_length=255)
searches = models.ArrayField(model_container=RecentSearch, null=True)
display_settings = models.ArrayField(model_container=DisplaySetting, null=True)
objects = models.DjongoManager()
Является ли user = UserProfile.objects.get(user_id=user_id)
асинхронным и не возвращается вовремя для проверки в операторе try? Я бы не ожидал, что в Python возникнут условия гонки, поскольку я не использую никаких ключевых слов async.
Мне нужно, чтобы это представление никогда не сохраняло дублирующий профиль пользователя после создания первого профиля
В вашем django ПРИЛОЖЕНИИ (не проекте)
- создайте файл с именем
signals.py
.
- Перейдите к файлу "apps.py" и добавьте следующий
ready()
метод к классу.
class MyApplicationConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'myapplication'
def ready(self):
import myapplication.signals
^^^ Сам класс является лишь примером, метод ready является самоочевидным
- Затем мы перейдем к созданию сигнала -> зайдите в файл signals.py .
from django.dispatch import receiver
from django.db.models.signals import post_save
from django.contrib.auth.models import User
from myapplication.models import Userprofile
# ^ Nescessary imports to create a signal to be sent after User creation.
@receiver(post_save, sender=User)
def create_profile_signal(
sender, # The User class specified above
instance, # The actual user instance that was edited
created, # self explanatory
**kwargs # Nescessary kwargs.
):
if created: # Assign the current user's instance to the userprofile to create one.
profile = UserProfile.objects.create()
profile.user_id = instance.id
profile.searches = [
{'search_term': 'hd'},
{'search_term': 'wba'},
]
profile.display_settings = [
{'setting_name': 'showYieldChange', 'visible': True},
{'setting_name': 'showAllDividends', 'visible': True},
]
profile.save()
- Затем вам необходимо полностью перезапустить ваш проект django (остановить и запустить встроенный runerver), django не умеет распознавать вновь созданные файлы.
Что теперь? Каждый раз, когда пользователь регистрируется в вашем django проекте, автоматически создается userprofile. Вам не нужно делать это самостоятельно. Никаких хлопот с представлениями и прочим. Вы, конечно, можете также установить значения по умолчанию, как и раньше.
Вопрос от меня к вам:
Есть ли конкретная причина, по которой вы не используете поле OneToOne, привязанное к пользователю?