-
Notifications
You must be signed in to change notification settings - Fork 47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Move related items from one attribute to another via CLI command (merge_attributes) #991
base: dev-2.2.0
Are you sure you want to change the base?
Conversation
this has low-prio if it's not relevant for any other RDMO Instance.. |
I will have a look. Btw: locally you can also use the |
return replace_attribute_on_elements(source, target, REPLACE_ATTRIBUTE_MODEL_HELPERS, save) | ||
|
||
|
||
class Command(BaseCommand): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be at the top of the file.
f"{affect_elements_msg}\n" | ||
f"{affected_projects_msg}" | ||
)) | ||
except ValueError as e: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this meant to catch all ValueErrors in the whole code? Exceptions should be more specific to functions or a few lines of code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no 😅 , thought add a custom exception at some point, but now I'm raising only CommandErrors
in the handle
method
return msg | ||
|
||
|
||
def replace_attribute_on_elements(source, target, model_helpers_with_attributes, save): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also not needed, the containing code should be just in handle
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, moved most of the code to handle
|
||
ModelHelper = namedtuple('ModelHelper', ['model', 'lookup_field', 'field_introspection', 'replacement_function']) | ||
|
||
REPLACE_ATTRIBUTE_MODEL_HELPERS = [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This dict can be replaced with one:
if is_a_view:
...
else:
...
in then main loop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've replaced these helpers with
related_model_fields = [i for i in Attribute._meta.get_fields() \
if i.is_relation and not i.many_to_many and i.related_model is not Attribute]
and handle the View
separate and explicit.
seems agreeable to you?
return instance | ||
|
||
|
||
def replace_attribute_on_element_instances(model, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is also not needed, it is called only one time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, refactored it .. there is still a function called one time, replace_attribute_in_view_template
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, but now that you can read it from top to bottom, it is much better readable.
Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
09a7fe3
to
4c24589
Compare
|
||
if save and all(a['saved'] for i in results.values() for a in i): | ||
try: | ||
source.delete() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a thought: if the attribute is deleted afterwards, it could have been moved to a different place in the tree without touching the foreign_keys, right? Then only the rewriting of the templates would be needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what you mean by "it could have been moved to a different place in the tree without touching the foreign_keys" , maybe I'm missing some knowledge about logic of the tree and foreign_keys here but I think it's the essential part of this feature..
The function replace_attribute_on_related_model_instances
could maybe better be called assign_related_model_instances_to_attribute
(to the target
) . Or it should, in addition, set the related fields on the source
to None
(which seems redundant before source.delete()
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can move Attributes in the RDMO management. This changes their URI, but all the relations are kept because the use the id
field in the database.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah like that, but that is just a rename of the URI then right?
However, in this use-case I have an existing URI foo
(that has related elements already) and bar
which is sort of a duplicate with its own related elements. When I want to delete bar
and assign all its related elements to foo
, I can't just rename bar
to foo
in this case..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah ok, you want to merge the old URI to into the new one that already has elements! Now everything makes sense. I would make a --delete
switch or so. Makes more sense to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would just use --delete
this is pretty common in cli tools.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would add --delete
and set --dry-run
as default to true as args
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but if --dry-run
is default and a store_true
you could not unset it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
by using store_false
maybe?
by GPT:
from django.core.management.base import BaseCommand
class Command(BaseCommand):
help = 'A custom command that uses a store_false argument with a default of True'
def add_arguments(self, parser):
# Adding a `store_false` argument that defaults to True
parser.add_argument(
'--no-feature',
action='store_false',
dest='feature_enabled',
default=True,
help='Disable the feature (default: feature is enabled)'
)
def handle(self, *args, **options):
feature_enabled = options['feature_enabled']
if feature_enabled:
self.stdout.write(self.style.SUCCESS('Feature is enabled'))
else:
self.stdout.write(self.style.WARNING('Feature is disabled'))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm, then it would be --no-dry-run
..
I have now --save
, but I'll change that to --delete
that will save the updated instances and delete the source attribute afterwards.
We have tried this out yesterday and have some changes to the feature request.
|
The uri prefix is not needed in the view. In fact, we added this later. So I guess many views will only use the |
…d --view and update output messages Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
@@ -26,16 +26,24 @@ def add_arguments(self, parser): | |||
help='The URI of the target attribute that will be used to replace the source' | |||
) | |||
parser.add_argument( | |||
'--save', | |||
'--delete', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why both with the same argument, I can see a case where I want to move everthing from one attribute to another one, but keep the old. Does that make sense?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, the args are now:
--source SOURCE The URI of the source attribute that will be replaced by the target and will be deleted
--target TARGET The URI of the target attribute that will be used to replace the source
--save If specified, the changes will be saved. If not specified, the command will not make any changes in the database.
--delete If specified, the source attribute will be deleted. If not specified, the command will not delete the source attribute.
--view If specified, the changes will be applied to the affected Views as well.
…elete and --view and update tests and output messages Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
Description
Related issue: #990
Motivation and Context
How has this been tested?
Screenshots (if appropriate)
CLI shell command:
Part of the help message:
Command:
logs:
[2024-06-06 15:31:11,702] INFO: Attribute https://foo-merge.com/terms/domain/blocks/c5 on Question(id=1) was replaced with https://foo-merge.com/terms/domain/blocks/c4. [2024-06-06 15:31:11,711] INFO: Attribute https://foo-merge.com/terms/domain/blocks/c5 on Question(id=18) was replaced with https://foo-merge.com/terms/domain/blocks/c4. [2024-06-06 15:31:11,724] INFO: Attribute https://foo-merge.com/terms/domain/blocks/c5 on Value(id=1) was replaced with https://foo-merge.com/terms/domain/blocks/c4. [2024-06-06 15:31:11,733] INFO: Attribute https://foo-merge.com/terms/domain/blocks/c5 on Value(id=116) was replaced with https://foo-merge.com/terms/domain/blocks/c4. [2024-06-06 15:31:11,740] INFO: Attribute https://foo-merge.com/terms/domain/blocks/c5 on Value(id=242) was replaced with https://foo-merge.com/terms/domain/blocks/c4. [2024-06-06 15:31:11,747] INFO: Attribute https://foo-merge.com/terms/domain/blocks/c5 on Value(id=243) was replaced with https://foo-merge.com/terms/domain/blocks/c4. [2024-06-06 15:31:11,754] INFO: Attribute https://foo-merge.com/terms/domain/blocks/c5 on Value(id=244) was replaced with https://foo-merge.com/terms/domain/blocks/c4. [2024-06-06 15:31:11,763] INFO: Attribute https://foo-merge.com/terms/domain/blocks/c5 on Value(id=245) was replaced with https://foo-merge.com/terms/domain/blocks/c4. [2024-06-06 15:31:11,769] INFO: Attribute https://foo-merge.com/terms/domain/blocks/c5 on Value(id=246) was replaced with https://foo-merge.com/terms/domain/blocks/c4. [2024-06-06 15:31:11,776] INFO: Attribute https://foo-merge.com/terms/domain/blocks/c5 on Value(id=247) was replaced with https://foo-merge.com/terms/domain/blocks/c4. [2024-06-06 15:31:11,783] INFO: Attribute https://foo-merge.com/terms/domain/blocks/c5 on Value(id=248) was replaced with https://foo-merge.com/terms/domain/blocks/c4. [2024-06-06 15:31:11,790] INFO: Attribute https://foo-merge.com/terms/domain/blocks/c5 on Value(id=249) was replaced with https://foo-merge.com/terms/domain/blocks/c4. [2024-06-06 15:31:11,798] INFO: Attribute https://foo-merge.com/terms/domain/blocks/c5 on Value(id=359) was replaced with https://foo-merge.com/terms/domain/blocks/c4. [2024-06-06 15:31:11,805] INFO: Attribute https://foo-merge.com/terms/domain/blocks/c5 on Value(id=456) was replaced with https://foo-merge.com/terms/domain/blocks/c4. [2024-06-06 15:31:11,813] INFO: Attribute https://foo-merge.com/terms/domain/blocks/c5 on Value(id=465) was replaced with https://foo-merge.com/terms/domain/blocks/c4. [2024-06-06 15:31:11,821] INFO: Attribute https://foo-merge.com/terms/domain/blocks/c5 in View(id=1) template was replaced with https://foo-merge.com/terms/domain/blocks/c4. [2024-06-06 15:31:11,839] INFO: Source attribute https://foo-merge.com/terms/domain/blocks/c5 was deleted.
printed messages:
Types of Changes
Checklist