Hi All,
I’ve had to make a change to a model to ensure that a combination of attributes is unique.
class Case(models.Model):
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4())
# combination of species and ID to be unique
id = models.IntegerField()
species = models.ForeignKey(Species, on_delete=models.CASCADE)
# and several other attributes
class Meta:
constraints = [models.UniqueConstraint(fields=["id", "species"], name="unique_case")]
I’m in the unfortunate position where I have to load data from excel into my database. Pandas is great, humans inputting non-normalised, non-relational data, not so much.
For my Case model, I have some data in CSV format which looks like this:
Headers
ID, Species, name, problem
Data
1, rabbit, carmen, unwell
2, rabbit, bob, bad hair day
3, rabbit, tramper, jelly legs
My importer code effectively does this:
for row in excel:
build a dict of keys and values (case_dict in my code example below)
create or update a case
Here is what I have got:
species, _ = Species.objects.get_or_create(species='rabbit')
# case_data looks like this
case_dict = {
"name": "carmen",
"problem": "unwell"
}
case, created = Case.objects.filter(species=species).get_or_create(
id=data.number,
species=species,
defaults={
**case_dict,
},
)
If I run this code, the first case will be created, but I will receive an exception when attempting to create the second case. If I rerun the code, the second case will be created, and attempting to create the third case will throw an exception.
The exception summary (full exception at the end of this post):
Traceback (most recent call last):
File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 559, in get_or_create
return self.get(**kwargs), False
File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 415, in get
raise self.model.DoesNotExist(
cases.models.DoesNotExist: Case matching query does not exist.
#### Lots of text omitted - full stacktrace at the end of the post
django.db.utils.IntegrityError: duplicate key value violates unique constraint "cases_case_pkey"
DETAIL: Key (uuid)=(b57252e3-2c9e-4514-905c-c132f85fa6e4) already exists.
What’s confusing me is that one, the code only works one case at a time before throwing an exception, and two, I would expect that a case that already existed would be updated. I’m also confused as to why it is telling me that a case doesn’t exist, as I thought that if a case with the specific attributes from the spreadsheet didn’t exist, then and instance of case would be created.
One thought that crossed my mind is that id
is used by Django in a way with which I am not familiar, but I haven’t managed to determine if that is the case or not.
Well, it’s very late here and I should probably sleep on it. Any help would be most welcome.
Cheers,
C
Full stacktrace
! Updated Image: images/C1CI1.jpeg
ID: 1 SPECIES: rabbit
! Updated Image: images/C2CI1.jpeg
ID: 2 SPECIES: rabbit
! Updated Image: images/C3CI1.jpeg
ID: 3 SPECIES: rabbit
! Updated Image: images/C4CI1.jpeg
ID: 4 SPECIES: rabbit
! Updated Image: images/C5CI1.jpeg
ID: 5 SPECIES: rabbit
Traceback (most recent call last):
File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 559, in get_or_create
return self.get(**kwargs), False
File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 415, in get
raise self.model.DoesNotExist(
cases.models.DoesNotExist: Case matching query does not exist.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 86, in _execute
return self.cursor.execute(sql, params)
psycopg2.errors.UniqueViolation: duplicate key value violates unique constraint "cases_case_pkey"
DETAIL: Key (uuid)=(dc5a1adc-bb29-457d-a9f3-243746f3231c) already exists.
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "import_tool.py", line 3, in <module>
main()
File "/opt/project/populator/import_tool.py", line 102, in main
import_cases(case_data, media)
File "/opt/project/populator/importer/cases.py", line 77, in import_cases
case, created = Case.objects.filter(species=species).get_or_create(
File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 562, in get_or_create
return self._create_object_from_params(kwargs, params)
File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 604, in _create_object_from_params
raise e
File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 596, in _create_object_from_params
obj = self.create(**params)
File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 433, in create
obj.save(force_insert=True, using=self.db)
File "/usr/local/lib/python3.8/site-packages/django/db/models/base.py", line 745, in save
self.save_base(using=using, force_insert=force_insert,
File "/usr/local/lib/python3.8/site-packages/django/db/models/base.py", line 782, in save_base
updated = self._save_table(
File "/usr/local/lib/python3.8/site-packages/django/db/models/base.py", line 887, in _save_table
results = self._do_insert(cls._base_manager, using, fields, returning_fields, raw)
File "/usr/local/lib/python3.8/site-packages/django/db/models/base.py", line 924, in _do_insert
return manager._insert(
File "/usr/local/lib/python3.8/site-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 1204, in _insert
return query.get_compiler(using=using).execute_sql(returning_fields)
File "/usr/local/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1392, in execute_sql
cursor.execute(sql, params)
File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 100, in execute
return super().execute(sql, params)
File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 68, in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 77, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 86, in _execute
return self.cursor.execute(sql, params)
File "/usr/local/lib/python3.8/site-packages/django/db/utils.py", line 90, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 86, in _execute
return self.cursor.execute(sql, params)
django.db.utils.IntegrityError: duplicate key value violates unique constraint "cases_case_pkey"
DETAIL: Key (uuid)=(dc5a1adc-bb29-457d-a9f3-243746f3231c) already exists.