#python #django
#python #django
Вопрос:
У меня есть функция для fetch API, где я создаю объект модели Django для каждого объекта в JSON и сохраняю данные в модели django. Проблема здесь в том, что каждый раз, когда я вызываю маршрут, он создает записи снова и снова, потому что я использую метод create , но я провел исследование, что лучший способ остановить это — использовать get_or_create . Итак, я попробовал этот метод, но, похоже, я что-то пропустил, потому что я получил сообщение об ошибке: feedback.models.Пациент.MultipleObjectsReturned: get() вернул более одного пациента — он вернул 7!
это мой код до того, как у меня будет 2 цикла for, поэтому я могу перебирать каждого пациента, а затем каждую роль и сохранять пациента с ролью:
# FetchApi for Patients def fetchapi_patients(request):
url = 'http://localhost:8000/core/users/roles/patient'
headers={"Authorization":"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Imhha2FuQGdvLmNvbSIsImV4cCI6MTYxMDAxMTM0MSwib3JpZ19pYXQiOjE2MTAwMDc3NDF9.k2204d094DNUbEfFt8M_7chukOSjWWwfesPOH5jIiP8"}
response = requests.get(url, headers=headers)
#Read the JSON
patients = response.json()
#Create a Django model object for each object in the JSON and store the data in django model (in database)
for patient in patients:
Patient.objects.create(first_name=patient['first_name'], last_name=patient['last_name'], email=patient['email'], coreapi_id=patient['ID'])
for role in patient['Roles']:
Role.objects.create(role_name=role['name'])
return JsonResponse({'patients': patients})
это когда я попытался использовать метод get_or_create:
for patient in patients:
patientDatabase, created = Patient.objects.get_or_create(first_name=patient['first_name'], last_name=patient['last_name'], email=patient['email'], coreapi_id=patient['ID'])
for role in patient['Roles']:
Role.objects.get_or_create(role_name=role['name'])
return JsonResponse({'patients': patients})
это мой models.py:
class Patient(models.Model):
coreapi_id = models.CharField(max_length=100)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
email = models.EmailField(max_length=100)
language = models.CharField(max_length=20)
created_date = models.DateTimeField(auto_now_add=True)
def str(self):
return self.email
class Role(models.Model):
role_id = models.ManyToManyField(Patient)
role_name = models.CharField(max_length=100)
def __str__(self):
return self.role_name
Ошибка обратной трассировки:
Traceback (most recent call last): File "/usr/lib/python3/dist-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request) File "/usr/lib/python3/dist-packages/django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request) File "/usr/lib/python3/dist-packages/django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs) File "/home/stela/feedbacksystem/feedback/views.py", line 88, in fetchapi_patients
patientDatabase, created = Patient.objects.get_or_create(first_name=patient['first_name'], last_name=patient['last_name'], email=patient['email'], coreapi_id=patient['ID']) File "/usr/lib/python3/dist-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs) File "/usr/lib/python3/dist-packages/django/db/models/query.py", line 538, in get_or_create
return self.get(**kwargs), False File "/usr/lib/python3/dist-packages/django/db/models/query.py", line 410, in get
raise self.model.MultipleObjectsReturned( feedback.models.Patient.MultipleObjectsReturned: get() returned more than one Patient -- it returned 7!
Я прочитал официальную документацию, но есть некоторые недоразумения, которые мне не очень понятны в методе get_or_create, например, я хочу проверять пользователей только по их электронной почте, потому что я прочитал, что это должно быть что-то «уникальное», поэтому get_or_create проверяет каждое поле в моей модели или ..? Я надеюсь, что мой вопрос понятен, если это не так, пожалуйста, дайте мне знать
Ответ №1:
Просто есть несколько объектов с одинаковым ( first_name
, last_name
, email
, coreapi_id
) и get_or_create
отказывается что-либо делать, поскольку это, вероятно, логическая проблема.
То же самое произошло бы с just .get()
(что .get_or_create()
действительно так и есть).
Если вы хотите, например, получить только пациента, используя coreapi_id
поле, но если пациента с такими данными не существует, создайте их, используя другие поля, вы захотите использовать defaults
аргумент:
patientDatabase, created = Patient.objects.get_or_create(
coreapi_id=patient["ID"],
defaults=dict(
first_name=patient["first_name"],
last_name=patient["last_name"],
email=patient["email"],
),
)
Комментарии:
1. Итак, в вашем примере моим уникальным полем будет ‘ID’, а остальные аргументы по умолчанию? Это имеет смысл, я попробовал ваш пример, но все равно получаю ту же ошибку. Также, когда я перебираю их роль, нужно ли мне также get_or_create?
2. Это зависит от вашей модели данных. В любом случае, если вы уже запускали
.create()
с одними и теми же параметрами несколько раз, ваша база данных, естественно, будет иметь несколько копий одной и той же строки. Вам нужно будет это очистить (вручную?) Первый.3. Какая глупая ошибка, это моя вина! Спасибо за быстрый ответ, я отметил ваш ответ
4. Хотя на мой предыдущий вопрос в комментариях к ролям мне нужно написать их отдельно и применить тот же метод, верно?
5. Во-первых, я нахожу очень странным, что вызывается поле «многие ко многим», связывающее роли с пациентами
role_id
. Я думаю, что так и должно бытьpatients
(предполагая, что у одного пациента может быть более одной роли; если нет, то объект Patient должен иметь внешний ключ к роли). После этогоRole.objects.get_or_create(role_name=role['name'])[0].patients.add(patient)
будет обеспечена связь.
Ответ №2:
метод get_ot_create должен использоваться только тогда, когда что-то уникально.
в вашем случае существует несколько объектов, которые не являются уникальными, поэтому он возвращает несколько объектов, но он должен возвращать только один объект