check unique collisions to prevent those objects from being restored
This commit is contained in:
parent
bba5fab2ec
commit
cf2496b5a7
3 changed files with 30 additions and 5 deletions
|
@ -273,6 +273,25 @@ class ChangedObject(models.Model):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def get_unique_collisions(self, max_one=False):
|
||||||
|
result = set()
|
||||||
|
if not self.deleted:
|
||||||
|
return result
|
||||||
|
uniques = tuple(self.model_class._meta.unique_together)
|
||||||
|
uniques += tuple((field.name, )
|
||||||
|
for field in self.model_class._meta.get_fields() if field.unique and not field.primary_key)
|
||||||
|
for unique in uniques:
|
||||||
|
names = tuple((name if self.model_class._meta.get_field(name).related_model is None else name+'__pk')
|
||||||
|
for name in unique)
|
||||||
|
values = tuple(getattr(self.obj, self.model_class._meta.get_field(name).attname) for name in unique)
|
||||||
|
if None in values:
|
||||||
|
continue
|
||||||
|
if self.changeset.wrap_model(self.model_class).objects.filter(**dict(zip(names, values))).exists():
|
||||||
|
result |= set(unique)
|
||||||
|
if result and max_one:
|
||||||
|
return result
|
||||||
|
return result
|
||||||
|
|
||||||
def get_missing_dependencies(self, force_query=False, max_one=False):
|
def get_missing_dependencies(self, force_query=False, max_one=False):
|
||||||
result = set()
|
result = set()
|
||||||
if not self.deleted:
|
if not self.deleted:
|
||||||
|
@ -371,7 +390,7 @@ class ChangedObject(models.Model):
|
||||||
def restore(self):
|
def restore(self):
|
||||||
if self.deleted is False:
|
if self.deleted is False:
|
||||||
return
|
return
|
||||||
if self.get_missing_dependencies(force_query=True, max_one=True):
|
if self.get_missing_dependencies(force_query=True, max_one=True) or self.get_unique_collisions(max_one=True):
|
||||||
raise PermissionError
|
raise PermissionError
|
||||||
self.deleted = False
|
self.deleted = False
|
||||||
self.save(standalone=True)
|
self.save(standalone=True)
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
<a class="btn btn-default btn-xs pull-right" data-force-next-zoom href="{{ obj.edit_url }}">
|
<a class="btn btn-default btn-xs pull-right" data-force-next-zoom href="{{ obj.edit_url }}">
|
||||||
{% trans 'Edit' %}
|
{% trans 'Edit' %}
|
||||||
</a>
|
</a>
|
||||||
{% elif obj.deleted and can_edit and not obj.missing_dependencies %}
|
{% elif obj.deleted and can_edit and not obj.missing_dependencies and not obj.unique_collisions %}
|
||||||
<button type="submit" name="restore" value="{{ obj.pk }}" class="btn btn-warning btn-xs pull-right">
|
<button type="submit" name="restore" value="{{ obj.pk }}" class="btn btn-warning btn-xs pull-right">
|
||||||
{% trans 'Restore' %}
|
{% trans 'Restore' %}
|
||||||
</button>
|
</button>
|
||||||
|
@ -108,7 +108,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-{{ change.class }}"><i class="glyphicon glyphicon-{{ change.icon }}"></i></td>
|
<td class="text-{{ change.class }}"><i class="glyphicon glyphicon-{{ change.icon }}"></i></td>
|
||||||
<td{% if obj.deleted and change.icon != 'minus' %} class="text-muted"{% endif %}>
|
<td{% if obj.deleted and change.icon != 'minus' %} class="text-muted"{% endif %}>
|
||||||
{% if change.missing_dependency %}<i class="glyphicon glyphicon-alert pull-right text-warning"></i>{% endif %}
|
{% if change.missing_dependency or change.unique_collision %}<i class="glyphicon glyphicon-alert pull-right text-warning"></i>{% endif %}
|
||||||
{% if change.empty %}<em>{% else %}<u>{% endif %}{{ change.title }}{% if not change.empty %}</u>:{% else %}</em>{% endif %}
|
{% if change.empty %}<em>{% else %}<u>{% endif %}{{ change.title }}{% if not change.empty %}</u>:{% else %}</em>{% endif %}
|
||||||
{{ change.value }}
|
{{ change.value }}
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -48,8 +48,8 @@ def changeset_detail(request, pk):
|
||||||
changed_object.restore()
|
changed_object.restore()
|
||||||
messages.success(request, _('Object has been successfully restored.'))
|
messages.success(request, _('Object has been successfully restored.'))
|
||||||
except PermissionError:
|
except PermissionError:
|
||||||
messages.error(request, _('You cannot restore this object, because '
|
messages.error(request, _('You cannot restore this object, because it depends on '
|
||||||
'it depends on a deleted object.'))
|
'a deleted object or it would violate a unique contraint.'))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
messages.error(request, _('You can not edit changes on this change set.'))
|
messages.error(request, _('You can not edit changes on this change set.'))
|
||||||
|
@ -234,6 +234,7 @@ def changeset_detail(request, pk):
|
||||||
|
|
||||||
changes = []
|
changes = []
|
||||||
missing_dependencies = changed_object.get_missing_dependencies()
|
missing_dependencies = changed_object.get_missing_dependencies()
|
||||||
|
unique_collisions = changed_object.get_unique_collisions()
|
||||||
changed_object_data = {
|
changed_object_data = {
|
||||||
'model': obj.__class__,
|
'model': obj.__class__,
|
||||||
'model_title': obj.__class__._meta.verbose_name,
|
'model_title': obj.__class__._meta.verbose_name,
|
||||||
|
@ -244,6 +245,7 @@ def changeset_detail(request, pk):
|
||||||
'edit_url': edit_url,
|
'edit_url': edit_url,
|
||||||
'deleted': changed_object.deleted,
|
'deleted': changed_object.deleted,
|
||||||
'missing_dependencies': missing_dependencies,
|
'missing_dependencies': missing_dependencies,
|
||||||
|
'unique_collisions': unique_collisions,
|
||||||
'order': (changed_object.deleted and changed_object.is_created, not changed_object.is_created),
|
'order': (changed_object.deleted and changed_object.is_created, not changed_object.is_created),
|
||||||
}
|
}
|
||||||
changed_objects_data.append(changed_object_data)
|
changed_objects_data.append(changed_object_data)
|
||||||
|
@ -293,6 +295,10 @@ def changeset_detail(request, pk):
|
||||||
change_data.update({
|
change_data.update({
|
||||||
'missing_dependency': field.name in missing_dependencies,
|
'missing_dependency': field.name in missing_dependencies,
|
||||||
})
|
})
|
||||||
|
if name in unique_collisions:
|
||||||
|
change_data.update({
|
||||||
|
'unique_collision': field.name in unique_collisions,
|
||||||
|
})
|
||||||
order = 5
|
order = 5
|
||||||
if name == 'slug':
|
if name == 'slug':
|
||||||
order = 1
|
order = 1
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue