From fe2144f9e0c301c9c9f7bde5f27815a5ca8430c0 Mon Sep 17 00:00:00 2001 From: Matt Covalt Date: Fri, 20 Mar 2020 17:18:38 -0400 Subject: [PATCH 1/9] Add "django-crum" --- config/settings.py | 1 + requirements.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/config/settings.py b/config/settings.py index 43763b6..85e1f7c 100644 --- a/config/settings.py +++ b/config/settings.py @@ -67,6 +67,7 @@ "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", + "crum.CurrentRequestUserMiddleware", ] ROOT_URLCONF = "config.urls." + env("URL_CONF") SECRET_KEY = env("SECRET_KEY") diff --git a/requirements.txt b/requirements.txt index 1855e78..595d7e6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,6 @@ django[argon2]==3.0.3 # https://www.djangoproject.com/ django-cors-headers==3.2.1 # https://github.com/adamchainz/django-cors-headers +django-crum==0.7.5 # https://github.com/ninemoreminutes/django-crum django-environ==0.4.5 # https://github.com/joke2k/django-environ django-polymorphic==2.1.2 # https://github.com/django-polymorphic/django-polymorphic django-redis==4.11.0 # https://github.com/niwinz/django-redis From ccfec2175a640a34f327028916ee5ba153159ec3 Mon Sep 17 00:00:00 2001 From: Matt Covalt Date: Fri, 20 Mar 2020 17:19:56 -0400 Subject: [PATCH 2/9] Add created_by/updated_by --- chemreg/common/models.py | 24 ++++++- chemreg/common/signals.py | 17 +++++ chemreg/common/utils.py | 13 ++++ .../migrations/0006_createdby_updated_by.py | 63 +++++++++++++++++++ .../migrations/0004_createdby_updated_by.py | 39 ++++++++++++ 5 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 chemreg/common/signals.py create mode 100644 chemreg/common/utils.py create mode 100644 chemreg/compound/migrations/0006_createdby_updated_by.py create mode 100644 chemreg/users/migrations/0004_createdby_updated_by.py diff --git a/chemreg/common/models.py b/chemreg/common/models.py index 566314c..04cac61 100644 --- a/chemreg/common/models.py +++ b/chemreg/common/models.py @@ -1,17 +1,37 @@ +from django.conf import settings from django.db import models +from chemreg.common.utils import get_current_user_pk + class CommonInfo(models.Model): """Common information to be applied to all models. Attributes: created_at (datetime.datetime): When the model was created. + created_by (chemreg.user.models.User): Who created this model. updated_at (datetime.datetime): When the model was updated. + updated_by (chemreg.user.models.User): Who updated this model. """ - created_at = models.DateTimeField(auto_now_add=True) - updated_at = models.DateTimeField(auto_now=True) + created_at = models.DateTimeField(auto_now_add=True, editable=False) + created_by = models.ForeignKey( + settings.AUTH_USER_MODEL, + default=get_current_user_pk, + editable=False, + related_name="%(class)s_created_by_set", + null=True, + on_delete=models.PROTECT, + ) + updated_at = models.DateTimeField(auto_now=True, editable=False) + updated_by = models.ForeignKey( + settings.AUTH_USER_MODEL, + editable=False, + related_name="%(class)s_updated_by_set", + null=True, + on_delete=models.PROTECT, + ) class Meta: abstract = True diff --git a/chemreg/common/signals.py b/chemreg/common/signals.py new file mode 100644 index 0000000..f97e2b0 --- /dev/null +++ b/chemreg/common/signals.py @@ -0,0 +1,17 @@ +from django.db.models.signals import pre_save +from django.dispatch import receiver + +from chemreg.common.models import CommonInfo +from chemreg.common.utils import get_current_user_pk + + +@receiver(pre_save) +def set_updated_by(sender, instance, **kwargs): + """Signal to set the `CommonInfo.updated_by`. + + Arguments: + sender: the model class. + instance: the model instance. + """ + if isinstance(instance, CommonInfo): + instance.updated_by_id = get_current_user_pk() diff --git a/chemreg/common/utils.py b/chemreg/common/utils.py new file mode 100644 index 0000000..a3948cc --- /dev/null +++ b/chemreg/common/utils.py @@ -0,0 +1,13 @@ +from crum import get_current_user + + +def get_current_user_pk(): + """Retrieve the current user's primary key. + + Returns: + The primary key of the current request's user. + """ + current_user = get_current_user() + if not current_user: + return None + return current_user.pk diff --git a/chemreg/compound/migrations/0006_createdby_updated_by.py b/chemreg/compound/migrations/0006_createdby_updated_by.py new file mode 100644 index 0000000..8868389 --- /dev/null +++ b/chemreg/compound/migrations/0006_createdby_updated_by.py @@ -0,0 +1,63 @@ +# Generated by Django 3.0.3 on 2020-03-20 20:37 + +import chemreg.common.models +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("compound", "0005_illdefinedcompoundquerystructuretype"), + ] + + operations = [ + migrations.AddField( + model_name="basecompound", + name="created_by", + field=models.ForeignKey( + default=chemreg.common.utils.get_current_user_pk, + editable=False, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="basecompound_created_by_set", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="basecompound", + name="updated_by", + field=models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="basecompound_updated_by_set", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="querystructuretype", + name="created_by", + field=models.ForeignKey( + default=chemreg.common.utils.get_current_user_pk, + editable=False, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="querystructuretype_created_by_set", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="querystructuretype", + name="updated_by", + field=models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="querystructuretype_updated_by_set", + to=settings.AUTH_USER_MODEL, + ), + ), + ] diff --git a/chemreg/users/migrations/0004_createdby_updated_by.py b/chemreg/users/migrations/0004_createdby_updated_by.py new file mode 100644 index 0000000..009733a --- /dev/null +++ b/chemreg/users/migrations/0004_createdby_updated_by.py @@ -0,0 +1,39 @@ +# Generated by Django 3.0.3 on 2020-03-20 20:37 + +import chemreg.common.models +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ("users", "0003_remove_user_name"), + ] + + operations = [ + migrations.AddField( + model_name="user", + name="created_by", + field=models.ForeignKey( + default=chemreg.common.utils.get_current_user_pk, + editable=False, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="user_created_by_set", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="user", + name="updated_by", + field=models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="user_updated_by_set", + to=settings.AUTH_USER_MODEL, + ), + ), + ] From b74e5d1c0b7d64222f19944d1995ca1fb5ef8b7f Mon Sep 17 00:00:00 2001 From: Matt Covalt Date: Fri, 20 Mar 2020 17:21:07 -0400 Subject: [PATCH 3/9] Add tests --- chemreg/common/tests.py | 19 +++++++++++++++++++ chemreg/conftest.py | 5 +++++ 2 files changed, 24 insertions(+) diff --git a/chemreg/common/tests.py b/chemreg/common/tests.py index 2d6c64a..b33deae 100644 --- a/chemreg/common/tests.py +++ b/chemreg/common/tests.py @@ -1,5 +1,8 @@ from django.db import models +import pytest +from crum import impersonate + from chemreg.common.models import CommonInfo @@ -21,3 +24,19 @@ def test_commoninfo_attr(): def test_inherits_commoninfo(chemreg_model): """Test that all ChemReg models inherit CommonInfo.""" assert issubclass(chemreg_model, CommonInfo) + + +@pytest.mark.django_db +def test_user_link(user_factory): + """Test that created_by/updated_by are saved.""" + user_1 = user_factory() + assert user_1.created_by_id is None + assert user_1.updated_by_id is None + with impersonate(user_1): + user_2 = user_factory() + assert user_2.created_by_id == user_1.pk + assert user_2.updated_by_id == user_1.pk + with impersonate(user_2): + user_2.save() + assert user_2.created_by_id == user_1.pk + assert user_2.updated_by_id == user_2.pk diff --git a/chemreg/conftest.py b/chemreg/conftest.py index b9abbda..de4b1db 100644 --- a/chemreg/conftest.py +++ b/chemreg/conftest.py @@ -40,6 +40,11 @@ def user() -> settings.AUTH_USER_MODEL: return UserFactory() +@pytest.fixture +def user_factory() -> UserFactory: + return UserFactory + + def is_chemreg_model(model: models.Model) -> bool: """Sees if a model is from the `chemreg` application.""" return model.__module__.startswith("chemreg") From 4e4b4a94c759d6274db0c9ed1f24ec801b25d1ae Mon Sep 17 00:00:00 2001 From: Matt Covalt Date: Tue, 24 Mar 2020 10:52:50 -0400 Subject: [PATCH 4/9] Move migration up the chain --- ..._createdby_updated_by.py => 0005_createdby_updated_by.py} | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) rename chemreg/compound/migrations/{0008_createdby_updated_by.py => 0005_createdby_updated_by.py} (93%) diff --git a/chemreg/compound/migrations/0008_createdby_updated_by.py b/chemreg/compound/migrations/0005_createdby_updated_by.py similarity index 93% rename from chemreg/compound/migrations/0008_createdby_updated_by.py rename to chemreg/compound/migrations/0005_createdby_updated_by.py index 1aa1814..9f1b192 100644 --- a/chemreg/compound/migrations/0008_createdby_updated_by.py +++ b/chemreg/compound/migrations/0005_createdby_updated_by.py @@ -10,7 +10,10 @@ class Migration(migrations.Migration): dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ("compound", "0007_rm_cid_prefix_valid"), + ("compound", "0004_illdefinedcompound"), + ] + run_before = [ + ("compound", "0005_illdefinedcompoundquerystructuretype"), ] operations = [ From 44076d1617922b323136b47b9f83f6883906b9ef Mon Sep 17 00:00:00 2001 From: Matt Covalt Date: Wed, 25 Mar 2020 14:07:46 -0400 Subject: [PATCH 5/9] Update linting config to ignore "venv" directory --- pyproject.toml | 2 +- setup.cfg | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 6b55caf..77f2d6e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,2 +1,2 @@ [tool.black] -exclude = '/(\.eggs|\.git|\.hg|\.mypy_cache|\.tox|\.venv|_build|buck-out|build|dist|migrations|docs|node_modules)/' +exclude = '/(\.eggs|\.git|\.hg|\.mypy_cache|\.tox|\.venv|venv|_build|buck-out|build|dist|migrations|docs|node_modules)/' diff --git a/setup.cfg b/setup.cfg index f8108e5..cfc596c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,7 +4,7 @@ omit = *migrations*, *tests* [flake8] max-line-length = 88 -exclude = .eggs,.git,.hg,.mypy_cache,.tox,.venv,_build,buck-out,build,dist,*/migrations/*,*/static/CACHE/*,docs,node_modules +exclude = .eggs,.git,.hg,.mypy_cache,.tox,.venv,venv,_build,buck-out,build,dist,*/migrations/*,*/static/CACHE/*,docs,node_modules select = C,E,F,W,B,BLK,I ignore = E203,E501,W503 @@ -17,7 +17,7 @@ line_length=88 known_django = django,rest_framework known_first_party = chemreg sections = FUTURE,STDLIB,DJANGO,THIRDPARTY,FIRSTPARTY,LOCALFOLDER -skip_glob = .eggs,.git,.hg,.mypy_cache,.tox,.venv,_build,buck-out,build,dist,*/migrations/*,*/static/CACHE/*,docs,node_modules +skip_glob = .eggs,.git,.hg,.mypy_cache,.tox,.venv,venv,_build,buck-out,build,dist,*/migrations/*,*/static/CACHE/*,docs,node_modules [mypy] python_version = 3.7 From ad1afbfd9c4094ad24c40101943c4d239b2921e7 Mon Sep 17 00:00:00 2001 From: Matt Covalt Date: Wed, 25 Mar 2020 14:08:36 -0400 Subject: [PATCH 6/9] Apply global ordering via "CommonInfo" --- chemreg/common/models.py | 1 + chemreg/compound/models.py | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/chemreg/common/models.py b/chemreg/common/models.py index 04cac61..28a16fe 100644 --- a/chemreg/common/models.py +++ b/chemreg/common/models.py @@ -35,3 +35,4 @@ class CommonInfo(models.Model): class Meta: abstract = True + ordering = ["pk"] diff --git a/chemreg/compound/models.py b/chemreg/compound/models.py index 0b262d9..6e3e584 100644 --- a/chemreg/compound/models.py +++ b/chemreg/compound/models.py @@ -21,7 +21,7 @@ class BaseCompound(CommonInfo, PolymorphicModel): This model shouldn't exist on it's own. It will always be subclassed by a concrete compound. The `chemreg.compound.fields.StructureAliasField` can be used to reference the `structure` field on subclassed models. This - field can then have a more sesnsible name and varied validation logic + field can then have a more sensible name and varied validation logic applied to it. Attributes: @@ -38,9 +38,6 @@ class BaseCompound(CommonInfo, PolymorphicModel): ) structure = models.TextField() - class Meta: # without this pytest will throw a `UnorderedObjectListWarning` - ordering = ["created_at"] - class DefinedCompound(BaseCompound): """A defined compound. From 1f289934d022492fcc478cbb30316bab34d3fd73 Mon Sep 17 00:00:00 2001 From: Matt Covalt Date: Wed, 25 Mar 2020 14:09:05 -0400 Subject: [PATCH 7/9] Remove deprecated validators --- chemreg/compound/validators.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/chemreg/compound/validators.py b/chemreg/compound/validators.py index 57af8f1..29c9a6a 100644 --- a/chemreg/compound/validators.py +++ b/chemreg/compound/validators.py @@ -55,17 +55,3 @@ def validate_inchikey_computable(molfile: str) -> None: get_inchikey(molfile) except IndigoException: raise ValidationError("InChIKey not computable for provided structure.") - - -############## -# Deprecated # -############## -# These validators cannot be removed due to being linked to the model in a previous migration. - - -def validate_cid_prefix(x): - pass - - -def validate_inchikey_regex(x): - pass From 51a65bca04f06633195069db2f22bca9f3dc2724 Mon Sep 17 00:00:00 2001 From: Matt Covalt Date: Wed, 25 Mar 2020 14:14:11 -0400 Subject: [PATCH 8/9] Collapse migrations --- .../compound/migrations/0001_basecompound.py | 32 --- chemreg/compound/migrations/0001_initial.py | 207 ++++++++++++++++++ .../migrations/0002_definedcompound.py | 26 --- .../migrations/0003_query_structure_type.py | 28 --- .../migrations/0004_illdefinedcompound.py | 25 --- .../migrations/0005_createdby_updated_by.py | 66 ------ ...05_illdefinedcompoundquerystructuretype.py | 28 --- .../migrations/0006_computed_inchikey.py | 21 -- .../migrations/0007_rm_cid_prefix_valid.py | 28 --- chemreg/users/migrations/0001_initial.py | 45 +++- chemreg/users/migrations/0002_commoninfo.py | 26 --- .../users/migrations/0003_remove_user_name.py | 17 -- .../migrations/0004_createdby_updated_by.py | 39 ---- 13 files changed, 240 insertions(+), 348 deletions(-) delete mode 100644 chemreg/compound/migrations/0001_basecompound.py create mode 100644 chemreg/compound/migrations/0001_initial.py delete mode 100644 chemreg/compound/migrations/0002_definedcompound.py delete mode 100644 chemreg/compound/migrations/0003_query_structure_type.py delete mode 100644 chemreg/compound/migrations/0004_illdefinedcompound.py delete mode 100644 chemreg/compound/migrations/0005_createdby_updated_by.py delete mode 100644 chemreg/compound/migrations/0005_illdefinedcompoundquerystructuretype.py delete mode 100644 chemreg/compound/migrations/0006_computed_inchikey.py delete mode 100644 chemreg/compound/migrations/0007_rm_cid_prefix_valid.py delete mode 100644 chemreg/users/migrations/0002_commoninfo.py delete mode 100644 chemreg/users/migrations/0003_remove_user_name.py delete mode 100644 chemreg/users/migrations/0004_createdby_updated_by.py diff --git a/chemreg/compound/migrations/0001_basecompound.py b/chemreg/compound/migrations/0001_basecompound.py deleted file mode 100644 index a9d65fd..0000000 --- a/chemreg/compound/migrations/0001_basecompound.py +++ /dev/null @@ -1,32 +0,0 @@ -# Generated by Django 3.0.3 on 2020-02-24 15:47 - -import chemreg.compound.utils -import chemreg.compound.validators -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('contenttypes', '0002_remove_content_type_name'), - ] - - operations = [ - migrations.CreateModel( - name='BaseCompound', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('cid', models.CharField(default=chemreg.compound.utils.build_cid, max_length=50, unique=True, validators=[chemreg.compound.validators.validate_cid_prefix, chemreg.compound.validators.validate_cid_regex, chemreg.compound.validators.validate_cid_checksum])), - ('structure', models.TextField()), - ('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_compound.basecompound_set+', to='contenttypes.ContentType')), - ], - options={ - 'abstract': False, - }, - ), - ] diff --git a/chemreg/compound/migrations/0001_initial.py b/chemreg/compound/migrations/0001_initial.py new file mode 100644 index 0000000..ea29156 --- /dev/null +++ b/chemreg/compound/migrations/0001_initial.py @@ -0,0 +1,207 @@ +# Generated by Django 3.0.3 on 2020-03-25 17:38 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + +import computed_property.fields + +import chemreg.common.utils +import chemreg.compound.models +import chemreg.compound.utils +import chemreg.compound.validators + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ("contenttypes", "0002_remove_content_type_name"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name="BaseCompound", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("updated_at", models.DateTimeField(auto_now=True)), + ( + "cid", + models.CharField( + default=chemreg.compound.utils.build_cid, + max_length=50, + unique=True, + validators=[ + chemreg.compound.validators.validate_cid_regex, + chemreg.compound.validators.validate_cid_checksum, + ], + ), + ), + ("structure", models.TextField()), + ( + "created_by", + models.ForeignKey( + default=chemreg.common.utils.get_current_user_pk, + editable=False, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="basecompound_created_by_set", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "polymorphic_ctype", + models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_compound.basecompound_set+", + to="contenttypes.ContentType", + ), + ), + ( + "updated_by", + models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="basecompound_updated_by_set", + to=settings.AUTH_USER_MODEL, + ), + ), + ], + options={"ordering": ["pk"], "abstract": False,}, + ), + migrations.CreateModel( + name="DefinedCompound", + fields=[ + ( + "basecompound_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="compound.BaseCompound", + ), + ), + ( + "inchikey", + computed_property.fields.ComputedCharField( + compute_from="_inchikey", editable=False, max_length=29 + ), + ), + ], + options={"ordering": ["pk"], "abstract": False,}, + bases=("compound.basecompound",), + ), + migrations.CreateModel( + name="QueryStructureType", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("updated_at", models.DateTimeField(auto_now=True)), + ( + "name", + models.SlugField( + help_text="Query structure type name", + max_length=49, + unique=True, + verbose_name="name", + ), + ), + ( + "label", + models.CharField( + help_text="Query structure type label", + max_length=99, + unique=True, + verbose_name="label", + ), + ), + ( + "short_description", + models.CharField( + help_text="Query structure type short description", + max_length=499, + verbose_name="short description", + ), + ), + ( + "long_description", + models.TextField( + help_text="Query structure type long description", + verbose_name="long description", + ), + ), + ( + "created_by", + models.ForeignKey( + default=chemreg.common.utils.get_current_user_pk, + editable=False, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="querystructuretype_created_by_set", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "updated_by", + models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="querystructuretype_updated_by_set", + to=settings.AUTH_USER_MODEL, + ), + ), + ], + options={"ordering": ["pk"], "abstract": False,}, + ), + migrations.CreateModel( + name="IllDefinedCompound", + fields=[ + ( + "basecompound_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="compound.BaseCompound", + ), + ), + ( + "query_structure_type", + models.ForeignKey( + default=chemreg.compound.models.get_illdefined_qst, + on_delete=django.db.models.deletion.PROTECT, + to="compound.QueryStructureType", + ), + ), + ], + options={"verbose_name": "ill-defined compound",}, + bases=("compound.basecompound",), + ), + ] diff --git a/chemreg/compound/migrations/0002_definedcompound.py b/chemreg/compound/migrations/0002_definedcompound.py deleted file mode 100644 index de46b29..0000000 --- a/chemreg/compound/migrations/0002_definedcompound.py +++ /dev/null @@ -1,26 +0,0 @@ -# Generated by Django 3.0.3 on 2020-02-24 21:41 - -import chemreg.compound.validators -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('compound', '0001_basecompound'), - ] - - operations = [ - migrations.CreateModel( - name='DefinedCompound', - fields=[ - ('basecompound_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='compound.BaseCompound')), - ('inchikey', models.CharField(max_length=29, validators=[chemreg.compound.validators.validate_inchikey_regex])), - ], - options={ - 'abstract': False, - }, - bases=('compound.basecompound',), - ), - ] diff --git a/chemreg/compound/migrations/0003_query_structure_type.py b/chemreg/compound/migrations/0003_query_structure_type.py deleted file mode 100644 index d97179d..0000000 --- a/chemreg/compound/migrations/0003_query_structure_type.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 3.0.3 on 2020-03-02 15:23 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('compound', '0002_definedcompound'), - ] - - operations = [ - migrations.CreateModel( - name='QueryStructureType', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('name', models.SlugField(help_text='Query structure type name', max_length=49, unique=True, verbose_name='name')), - ('label', models.CharField(help_text='Query structure type label', max_length=99, unique=True, verbose_name='label')), - ('short_description', models.CharField(help_text='Query structure type short description', max_length=499, verbose_name='short description')), - ('long_description', models.TextField(help_text='Query structure type long description', verbose_name='long description')), - ], - options={ - 'abstract': False, - }, - ), - ] diff --git a/chemreg/compound/migrations/0004_illdefinedcompound.py b/chemreg/compound/migrations/0004_illdefinedcompound.py deleted file mode 100644 index bc95268..0000000 --- a/chemreg/compound/migrations/0004_illdefinedcompound.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 3.0.3 on 2020-03-03 15:00 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('compound', '0003_query_structure_type'), - ] - - operations = [ - migrations.CreateModel( - name='IllDefinedCompound', - fields=[ - ('basecompound_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='compound.BaseCompound')), - ('query_structure_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='compound.QueryStructureType')), - ], - options={ - 'abstract': False, - }, - bases=('compound.basecompound',), - ), - ] diff --git a/chemreg/compound/migrations/0005_createdby_updated_by.py b/chemreg/compound/migrations/0005_createdby_updated_by.py deleted file mode 100644 index 9f1b192..0000000 --- a/chemreg/compound/migrations/0005_createdby_updated_by.py +++ /dev/null @@ -1,66 +0,0 @@ -# Generated by Django 3.0.3 on 2020-03-20 20:37 - -import chemreg.common.models -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ("compound", "0004_illdefinedcompound"), - ] - run_before = [ - ("compound", "0005_illdefinedcompoundquerystructuretype"), - ] - - operations = [ - migrations.AddField( - model_name="basecompound", - name="created_by", - field=models.ForeignKey( - default=chemreg.common.utils.get_current_user_pk, - editable=False, - null=True, - on_delete=django.db.models.deletion.PROTECT, - related_name="basecompound_created_by_set", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="basecompound", - name="updated_by", - field=models.ForeignKey( - editable=False, - null=True, - on_delete=django.db.models.deletion.PROTECT, - related_name="basecompound_updated_by_set", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="querystructuretype", - name="created_by", - field=models.ForeignKey( - default=chemreg.common.utils.get_current_user_pk, - editable=False, - null=True, - on_delete=django.db.models.deletion.PROTECT, - related_name="querystructuretype_created_by_set", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="querystructuretype", - name="updated_by", - field=models.ForeignKey( - editable=False, - null=True, - on_delete=django.db.models.deletion.PROTECT, - related_name="querystructuretype_updated_by_set", - to=settings.AUTH_USER_MODEL, - ), - ), - ] diff --git a/chemreg/compound/migrations/0005_illdefinedcompoundquerystructuretype.py b/chemreg/compound/migrations/0005_illdefinedcompoundquerystructuretype.py deleted file mode 100644 index 1c90ff1..0000000 --- a/chemreg/compound/migrations/0005_illdefinedcompoundquerystructuretype.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 3.0.3 on 2020-03-17 20:19 - -import chemreg.compound.models -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('compound', '0004_illdefinedcompound'), - ] - - operations = [ - migrations.AlterModelOptions( - name='basecompound', - options={'ordering': ['created_at']}, - ), - migrations.AlterModelOptions( - name='illdefinedcompound', - options={'verbose_name': 'ill-defined compound'}, - ), - migrations.AlterField( - model_name='illdefinedcompound', - name='query_structure_type', - field=models.ForeignKey(default=chemreg.compound.models.get_illdefined_qst, on_delete=django.db.models.deletion.PROTECT, to='compound.QueryStructureType'), - ), - ] diff --git a/chemreg/compound/migrations/0006_computed_inchikey.py b/chemreg/compound/migrations/0006_computed_inchikey.py deleted file mode 100644 index 70118c3..0000000 --- a/chemreg/compound/migrations/0006_computed_inchikey.py +++ /dev/null @@ -1,21 +0,0 @@ -# Generated by Django 3.0.3 on 2020-03-18 20:54 - -import computed_property.fields -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ("compound", "0005_illdefinedcompoundquerystructuretype"), - ] - - operations = [ - migrations.AlterField( - model_name="definedcompound", - name="inchikey", - field=computed_property.fields.ComputedCharField( - compute_from="_inchikey", editable=False, max_length=29 - ), - ), - ] diff --git a/chemreg/compound/migrations/0007_rm_cid_prefix_valid.py b/chemreg/compound/migrations/0007_rm_cid_prefix_valid.py deleted file mode 100644 index c0d0a0e..0000000 --- a/chemreg/compound/migrations/0007_rm_cid_prefix_valid.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 3.0.3 on 2020-03-20 19:15 - -import chemreg.compound.utils -import chemreg.compound.validators -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("compound", "0006_computed_inchikey"), - ] - - operations = [ - migrations.AlterField( - model_name="basecompound", - name="cid", - field=models.CharField( - default=chemreg.compound.utils.build_cid, - max_length=50, - unique=True, - validators=[ - chemreg.compound.validators.validate_cid_regex, - chemreg.compound.validators.validate_cid_checksum, - ], - ), - ), - ] diff --git a/chemreg/users/migrations/0001_initial.py b/chemreg/users/migrations/0001_initial.py index c9d8905..2c34392 100644 --- a/chemreg/users/migrations/0001_initial.py +++ b/chemreg/users/migrations/0001_initial.py @@ -1,14 +1,22 @@ +# Generated by Django 3.0.3 on 2020-03-25 17:37 + import django.contrib.auth.models import django.contrib.auth.validators -from django.db import migrations, models +import django.db.models.deletion import django.utils.timezone +from django.conf import settings +from django.db import migrations, models + +import chemreg.common.utils class Migration(migrations.Migration): initial = True - dependencies = [("auth", "0008_alter_user_username_max_length")] + dependencies = [ + ("auth", "0011_update_proxy_permissions"), + ] operations = [ migrations.CreateModel( @@ -93,10 +101,17 @@ class Migration(migrations.Migration): default=django.utils.timezone.now, verbose_name="date joined" ), ), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("updated_at", models.DateTimeField(auto_now=True)), ( - "name", - models.CharField( - blank=True, max_length=255, verbose_name="Name of User" + "created_by", + models.ForeignKey( + default=chemreg.common.utils.get_current_user_pk, + editable=False, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="user_created_by_set", + to=settings.AUTH_USER_MODEL, ), ), ( @@ -110,6 +125,16 @@ class Migration(migrations.Migration): verbose_name="groups", ), ), + ( + "updated_by", + models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="user_updated_by_set", + to=settings.AUTH_USER_MODEL, + ), + ), ( "user_permissions", models.ManyToManyField( @@ -122,11 +147,7 @@ class Migration(migrations.Migration): ), ), ], - options={ - "verbose_name_plural": "users", - "verbose_name": "user", - "abstract": False, - }, - managers=[("objects", django.contrib.auth.models.UserManager())], - ) + options={"ordering": ["pk"], "abstract": False,}, + managers=[("objects", django.contrib.auth.models.UserManager()),], + ), ] diff --git a/chemreg/users/migrations/0002_commoninfo.py b/chemreg/users/migrations/0002_commoninfo.py deleted file mode 100644 index 5a25923..0000000 --- a/chemreg/users/migrations/0002_commoninfo.py +++ /dev/null @@ -1,26 +0,0 @@ -# Generated by Django 3.0.3 on 2020-02-17 23:25 - -from django.db import migrations, models -import django.utils.timezone - - -class Migration(migrations.Migration): - - dependencies = [("users", "0001_initial")] - - operations = [ - migrations.AlterModelOptions(name="user", options={}), - migrations.AddField( - model_name="user", - name="created_at", - field=models.DateTimeField( - auto_now_add=True, default=django.utils.timezone.now - ), - preserve_default=False, - ), - migrations.AddField( - model_name="user", - name="updated_at", - field=models.DateTimeField(auto_now=True), - ), - ] diff --git a/chemreg/users/migrations/0003_remove_user_name.py b/chemreg/users/migrations/0003_remove_user_name.py deleted file mode 100644 index f90e5a5..0000000 --- a/chemreg/users/migrations/0003_remove_user_name.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 3.0.3 on 2020-02-28 17:03 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0002_commoninfo'), - ] - - operations = [ - migrations.RemoveField( - model_name='user', - name='name', - ), - ] diff --git a/chemreg/users/migrations/0004_createdby_updated_by.py b/chemreg/users/migrations/0004_createdby_updated_by.py deleted file mode 100644 index 009733a..0000000 --- a/chemreg/users/migrations/0004_createdby_updated_by.py +++ /dev/null @@ -1,39 +0,0 @@ -# Generated by Django 3.0.3 on 2020-03-20 20:37 - -import chemreg.common.models -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("users", "0003_remove_user_name"), - ] - - operations = [ - migrations.AddField( - model_name="user", - name="created_by", - field=models.ForeignKey( - default=chemreg.common.utils.get_current_user_pk, - editable=False, - null=True, - on_delete=django.db.models.deletion.PROTECT, - related_name="user_created_by_set", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="user", - name="updated_by", - field=models.ForeignKey( - editable=False, - null=True, - on_delete=django.db.models.deletion.PROTECT, - related_name="user_updated_by_set", - to=settings.AUTH_USER_MODEL, - ), - ), - ] From efc873846b8c576dbbeb6b61bf673b722856b4e2 Mon Sep 17 00:00:00 2001 From: Matt Covalt Date: Wed, 25 Mar 2020 14:16:22 -0400 Subject: [PATCH 9/9] Install "ill-defined" QueryStructureType via data migration --- chemreg/compound/migrations/0001_initial.py | 21 +++++++++++++++++++++ chemreg/compound/models.py | 14 +++++++------- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/chemreg/compound/migrations/0001_initial.py b/chemreg/compound/migrations/0001_initial.py index ea29156..c63c51d 100644 --- a/chemreg/compound/migrations/0001_initial.py +++ b/chemreg/compound/migrations/0001_initial.py @@ -12,6 +12,23 @@ import chemreg.compound.validators +def fwd_create_illdefined_querystructuretype(apps, schema_editor): + QueryStructureType = apps.get_model("compound", "QueryStructureType") + db_alias = schema_editor.connection.alias + QueryStructureType.objects.using(db_alias).create( + name="ill-defined", + label="Ill defined", + short_description="Ill defined", + long_description="Ill defined", + ) + + +def rev_create_illdefined_querystructuretype(apps, schema_editor): + QueryStructureType = apps.get_model("compound", "QueryStructureType") + db_alias = schema_editor.connection.alias + QueryStructureType.objects.using(db_alias).filter(name="ill-defined").delete() + + class Migration(migrations.Migration): initial = True @@ -178,6 +195,10 @@ class Migration(migrations.Migration): ], options={"ordering": ["pk"], "abstract": False,}, ), + migrations.RunPython( + fwd_create_illdefined_querystructuretype, + rev_create_illdefined_querystructuretype, + ), migrations.CreateModel( name="IllDefinedCompound", fields=[ diff --git a/chemreg/compound/models.py b/chemreg/compound/models.py index 6e3e584..56e025c 100644 --- a/chemreg/compound/models.py +++ b/chemreg/compound/models.py @@ -97,13 +97,13 @@ def __str__(self): def get_illdefined_qst(): - qst, created = QueryStructureType.objects.get_or_create( - name="ill-defined", - defaults={"label": "Ill defined", "short_description": "Ill defined"}, - ) - if created: - qst.save() - return qst.pk + """Default value for `IllDefinedCompound.query_structure_type`. + + This object is created in a data migration. Calling `get_or_create` here will + cause migrations to fail if `QueryStructureType` has been modified: the new model + would be used to create the model prior to new columns made in the database. + """ + return QueryStructureType.objects.get(name="ill-defined").pk class IllDefinedCompound(BaseCompound):