Added changes to expand the scope of the document grouping functionality
This commit is contained in:
@@ -2,8 +2,8 @@ from django.contrib import admin
|
|||||||
|
|
||||||
from documents.models import MetadataType, DocumentType, Document, \
|
from documents.models import MetadataType, DocumentType, Document, \
|
||||||
MetadataSet, MetadataSetItem, DocumentMetadata, \
|
MetadataSet, MetadataSetItem, DocumentMetadata, \
|
||||||
DocumentTypeFilename, MetadataIndex, DocumentPage, MetadataGroup, \
|
DocumentTypeFilename, MetadataIndex, DocumentPage, DocumentGroup, \
|
||||||
MetadataGroupItem, DocumentPageTransformation, RecentDocument
|
DocumentGroupItem, DocumentPageTransformation, RecentDocument
|
||||||
|
|
||||||
from filesystem_serving.admin import DocumentMetadataIndexInline
|
from filesystem_serving.admin import DocumentMetadataIndexInline
|
||||||
|
|
||||||
@@ -65,15 +65,15 @@ class DocumentAdmin(admin.ModelAdmin):
|
|||||||
list_display = ('uuid', 'file_filename', 'file_extension')
|
list_display = ('uuid', 'file_filename', 'file_extension')
|
||||||
|
|
||||||
|
|
||||||
class MetadataGroupItemInline(admin.StackedInline):
|
class DocumentGroupItemInline(admin.StackedInline):
|
||||||
model = MetadataGroupItem
|
model = DocumentGroupItem
|
||||||
extra = 1
|
extra = 1
|
||||||
classes = ('collapse-open',)
|
classes = ('collapse-open',)
|
||||||
allow_add = True
|
allow_add = True
|
||||||
|
|
||||||
|
|
||||||
class MetadataGroupAdmin(admin.ModelAdmin):
|
class DocumentGroupAdmin(admin.ModelAdmin):
|
||||||
inlines = [MetadataGroupItemInline]
|
inlines = [DocumentGroupItemInline]
|
||||||
filter_horizontal = ['document_type']
|
filter_horizontal = ['document_type']
|
||||||
|
|
||||||
|
|
||||||
@@ -87,7 +87,6 @@ class RecentDocumentAdmin(admin.ModelAdmin):
|
|||||||
|
|
||||||
class MetadataSetAdmin(admin.ModelAdmin):
|
class MetadataSetAdmin(admin.ModelAdmin):
|
||||||
inlines = [MetadataSetItemInline]
|
inlines = [MetadataSetItemInline]
|
||||||
#filter_horizontal = ['document_type']
|
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(MetadataType, MetadataTypeAdmin)
|
admin.site.register(MetadataType, MetadataTypeAdmin)
|
||||||
|
|||||||
12
apps/documents/classes.py
Normal file
12
apps/documents/classes.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
class MetadataObject(object):
|
||||||
|
def __init__(self, dictionary):
|
||||||
|
self.dictionary = dictionary
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
if name in self.dictionary:
|
||||||
|
return self.dictionary.get(name)
|
||||||
|
else:
|
||||||
|
raise AttributeError(_(u'\'metadata\' object has no attribute \'%s\'') % name)
|
||||||
@@ -1,17 +1,16 @@
|
|||||||
'''Metadata handling commonalities
|
"""Metadata handling commonalities"""
|
||||||
'''
|
|
||||||
|
|
||||||
from urllib import unquote_plus
|
from urllib import unquote_plus
|
||||||
|
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from documents.models import DocumentMetadata, MetadataType
|
from documents.models import DocumentMetadata, MetadataType
|
||||||
|
|
||||||
|
|
||||||
def decode_metadata_from_url(url_dict):
|
def decode_metadata_from_url(url_dict):
|
||||||
'''Parses a URL query string to a list of metadata
|
"""Parse a URL query string to a list of metadata"""
|
||||||
'''
|
|
||||||
metadata_dict = {
|
metadata_dict = {
|
||||||
'id': {},
|
'id': {},
|
||||||
'value': {}
|
'value': {}
|
||||||
@@ -35,8 +34,9 @@ def decode_metadata_from_url(url_dict):
|
|||||||
|
|
||||||
|
|
||||||
def save_metadata_list(metadata_list, document):
|
def save_metadata_list(metadata_list, document):
|
||||||
'''Takes a list of metadata values and associates a document to it
|
"""
|
||||||
'''
|
Take a list of metadata values and associate a document to it
|
||||||
|
"""
|
||||||
for item in metadata_list:
|
for item in metadata_list:
|
||||||
save_metadata(item, document)
|
save_metadata(item, document)
|
||||||
|
|
||||||
@@ -57,9 +57,8 @@ def save_metadata_list(metadata_list, document):
|
|||||||
|
|
||||||
|
|
||||||
def save_metadata(metadata_dict, document):
|
def save_metadata(metadata_dict, document):
|
||||||
'''save metadata_dict
|
"""save metadata_dict"""
|
||||||
'''
|
# Use matched metadata now to create document metadata
|
||||||
#Use matched metadata now to create document metadata
|
|
||||||
document_metadata, created = DocumentMetadata.objects.get_or_create(
|
document_metadata, created = DocumentMetadata.objects.get_or_create(
|
||||||
document=document,
|
document=document,
|
||||||
metadata_type=get_object_or_404(
|
metadata_type=get_object_or_404(
|
||||||
@@ -67,24 +66,24 @@ def save_metadata(metadata_dict, document):
|
|||||||
pk=metadata_dict['id']
|
pk=metadata_dict['id']
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
#Handle 'plus sign as space' in the url
|
# Handle 'plus sign as space' in the url
|
||||||
|
|
||||||
#unquote_plus handles utf-8?!?
|
# unquote_plus handles utf-8?!?
|
||||||
#http://stackoverflow.com/questions/4382875/handling-iri-in-django
|
# http://stackoverflow.com/questions/4382875/handling-iri-in-django
|
||||||
#.decode('utf-8')
|
#.decode('utf-8')
|
||||||
document_metadata.value = unquote_plus(metadata_dict['value'])
|
document_metadata.value = unquote_plus(metadata_dict['value'])
|
||||||
document_metadata.save()
|
document_metadata.save()
|
||||||
|
|
||||||
|
|
||||||
def metadata_repr(metadata_list):
|
def metadata_repr(metadata_list):
|
||||||
'''Return a printable representation of a metadata list
|
"""Return a printable representation of a metadata list"""
|
||||||
'''
|
return u', '.join(metadata_repr_as_list(metadata_list))
|
||||||
return ', '.join(metadata_repr_as_list(metadata_list))
|
|
||||||
|
|
||||||
|
|
||||||
def metadata_repr_as_list(metadata_list):
|
def metadata_repr_as_list(metadata_list):
|
||||||
'''Turn a list of metadata into a list of printable representations
|
"""
|
||||||
'''
|
Turn a list of metadata into a list of printable representations
|
||||||
|
"""
|
||||||
output = []
|
output = []
|
||||||
for metadata_dict in metadata_list:
|
for metadata_dict in metadata_list:
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ from documents.conf.settings import STORAGE_BACKEND
|
|||||||
from documents.conf.settings import AVAILABLE_TRANSFORMATIONS
|
from documents.conf.settings import AVAILABLE_TRANSFORMATIONS
|
||||||
from documents.conf.settings import DEFAULT_TRANSFORMATIONS
|
from documents.conf.settings import DEFAULT_TRANSFORMATIONS
|
||||||
from documents.conf.settings import RECENT_COUNT
|
from documents.conf.settings import RECENT_COUNT
|
||||||
|
from documents.classes import MetadataObject
|
||||||
|
|
||||||
|
|
||||||
def get_filename_from_uuid(instance, filename):
|
def get_filename_from_uuid(instance, filename):
|
||||||
@@ -352,7 +353,10 @@ class MetadataGroupManager(models.Manager):
|
|||||||
metadata_groups = {}
|
metadata_groups = {}
|
||||||
metadata_dict = {}
|
metadata_dict = {}
|
||||||
for document_metadata in document.documentmetadata_set.all():
|
for document_metadata in document.documentmetadata_set.all():
|
||||||
metadata_dict['metadata_%s' % document_metadata.metadata_type.name] = document_metadata.value
|
metadata_dict[document_metadata.metadata_type.name] = document_metadata.value
|
||||||
|
eval_dict = {}
|
||||||
|
eval_dict['document'] = document
|
||||||
|
eval_dict['metadata'] = MetadataObject(metadata_dict)
|
||||||
|
|
||||||
if group_obj:
|
if group_obj:
|
||||||
groups_qs = MetadataGroup.objects.filter((Q(document_type=document.document_type) | Q(document_type=None)) & Q(enabled=True) & Q(pk=group_obj.pk))
|
groups_qs = MetadataGroup.objects.filter((Q(document_type=document.document_type) | Q(document_type=None)) & Q(enabled=True) & Q(pk=group_obj.pk))
|
||||||
@@ -363,7 +367,7 @@ class MetadataGroupManager(models.Manager):
|
|||||||
total_query = Q()
|
total_query = Q()
|
||||||
for item in group.metadatagroupitem_set.filter(enabled=True):
|
for item in group.metadatagroupitem_set.filter(enabled=True):
|
||||||
try:
|
try:
|
||||||
value_query = Q(**{'value__%s' % item.operator: eval(item.expression, metadata_dict)})
|
value_query = Q(**{'value__%s' % item.operator: eval(item.expression, eval_dict)})
|
||||||
if item.negated:
|
if item.negated:
|
||||||
query = (Q(metadata_type__id=item.metadata_type_id) & ~value_query)
|
query = (Q(metadata_type__id=item.metadata_type_id) & ~value_query)
|
||||||
else:
|
else:
|
||||||
@@ -390,10 +394,10 @@ class MetadataGroupManager(models.Manager):
|
|||||||
return metadata_groups, errors
|
return metadata_groups, errors
|
||||||
|
|
||||||
|
|
||||||
class MetadataGroup(models.Model):
|
class DocumentGroup(models.Model):
|
||||||
document_type = models.ManyToManyField(DocumentType, null=True, blank=True,
|
document_type = models.ManyToManyField(DocumentType, null=True, blank=True,
|
||||||
verbose_name=_(u'document type'), help_text=_(u'If left blank, all document types will be matched.'))
|
verbose_name=_(u'document type'), help_text=_(u'If left blank, all document types will be matched.'))
|
||||||
name = models.CharField(max_length=32, verbose_name=_(u'name'))
|
#name = models.CharField(max_length=32, verbose_name=_(u'name'))
|
||||||
label = models.CharField(max_length=32, verbose_name=_(u'label'))
|
label = models.CharField(max_length=32, verbose_name=_(u'label'))
|
||||||
enabled = models.BooleanField(default=True, verbose_name=_(u'enabled'))
|
enabled = models.BooleanField(default=True, verbose_name=_(u'enabled'))
|
||||||
|
|
||||||
@@ -433,14 +437,17 @@ OPERATOR_CHOICES = (
|
|||||||
(u'iregex', _(u'is in regular expression (case insensitive)')),
|
(u'iregex', _(u'is in regular expression (case insensitive)')),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
#LOCAL_SOURCE_CHOICES = (
|
||||||
|
# (u'
|
||||||
|
|
||||||
class MetadataGroupItem(models.Model):
|
class DocumentGroupItem(models.Model):
|
||||||
metadata_group = models.ForeignKey(MetadataGroup, verbose_name=_(u'metadata group'))
|
metadata_group = models.ForeignKey(DocumentGroup, verbose_name=_(u'metadata group'))
|
||||||
inclusion = models.CharField(default=INCLUSION_AND, max_length=16, choices=INCLUSION_CHOICES, help_text=_(u'The inclusion is ignored for the first item.'))
|
inclusion = models.CharField(default=INCLUSION_AND, max_length=16, choices=INCLUSION_CHOICES, help_text=_(u'The inclusion is ignored for the first item.'))
|
||||||
metadata_type = models.ForeignKey(MetadataType, verbose_name=_(u'metadata type'), help_text=_(u'This represents the metadata of all other documents.'))
|
foreign_metadata_type = models.ForeignKey(MetadataType, related_name='metadata_type_foreign', verbose_name=_(u'foreign metadata'), help_text=_(u'This represents the metadata of all other documents.'))
|
||||||
operator = models.CharField(max_length=16, choices=OPERATOR_CHOICES)
|
operator = models.CharField(max_length=16, choices=OPERATOR_CHOICES)
|
||||||
expression = models.CharField(max_length=128,
|
|
||||||
verbose_name=_(u'expression'), help_text=_(u'This expression will be evaluated against the current selected document. The document metadata is available as variables of the same name but with the "metadata_" prefix added their name.'))
|
local_metadata_type = models.ForeignKey(MetadataType, related_name='metadata_type_local', verbose_name=_(u'local metadata'), help_text=_(u'This represents the metadata of the current document.'))
|
||||||
|
expression = models.TextField(verbose_name=_(u'expression'), help_text=_(u'This expression will be evaluated against the current selected document. The document metadata is available as variables `metadata` and document properties under the variable `document`.'))
|
||||||
negated = models.BooleanField(default=False, verbose_name=_(u'negated'), help_text=_(u'Inverts the logic of the operator.'))
|
negated = models.BooleanField(default=False, verbose_name=_(u'negated'), help_text=_(u'Inverts the logic of the operator.'))
|
||||||
enabled = models.BooleanField(default=True, verbose_name=_(u'enabled'))
|
enabled = models.BooleanField(default=True, verbose_name=_(u'enabled'))
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ from django.template.defaultfilters import slugify
|
|||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from documents.conf.settings import AVAILABLE_INDEXING_FUNCTIONS
|
from documents.conf.settings import AVAILABLE_INDEXING_FUNCTIONS
|
||||||
|
from documents.classes import MetadataObject
|
||||||
|
|
||||||
from filesystem_serving.conf.settings import FILESERVING_ENABLE
|
from filesystem_serving.conf.settings import FILESERVING_ENABLE
|
||||||
from filesystem_serving.conf.settings import FILESERVING_PATH
|
from filesystem_serving.conf.settings import FILESERVING_PATH
|
||||||
@@ -25,13 +26,15 @@ def document_create_fs_links(document):
|
|||||||
if FILESERVING_ENABLE:
|
if FILESERVING_ENABLE:
|
||||||
if not document.exists():
|
if not document.exists():
|
||||||
raise Exception(_(u'Not creating metadata indexing, document not found in document storage'))
|
raise Exception(_(u'Not creating metadata indexing, document not found in document storage'))
|
||||||
metadata_dict = {'document': document}
|
eval_dict = {}
|
||||||
metadata_dict.update(dict([(metadata.metadata_type.name, SLUGIFY_FUNCTION(metadata.value)) for metadata in document.documentmetadata_set.all() if metadata.value]))
|
eval_dict['document'] = document
|
||||||
|
metadata_dict = dict([(metadata.metadata_type.name, SLUGIFY_FUNCTION(metadata.value)) for metadata in document.documentmetadata_set.all() if metadata.value])
|
||||||
|
eval_dict['metadata'] = MetadataObject(metadata_dict)
|
||||||
|
|
||||||
for metadata_index in document.document_type.metadataindex_set.all():
|
for metadata_index in document.document_type.metadataindex_set.all():
|
||||||
if metadata_index.enabled:
|
if metadata_index.enabled:
|
||||||
try:
|
try:
|
||||||
fabricated_directory = eval(metadata_index.expression, metadata_dict, AVAILABLE_INDEXING_FUNCTIONS)
|
fabricated_directory = eval(metadata_index.expression, eval_dict, AVAILABLE_INDEXING_FUNCTIONS)
|
||||||
target_directory = os.path.join(FILESERVING_PATH, fabricated_directory)
|
target_directory = os.path.join(FILESERVING_PATH, fabricated_directory)
|
||||||
try:
|
try:
|
||||||
os.makedirs(target_directory)
|
os.makedirs(target_directory)
|
||||||
@@ -48,7 +51,7 @@ def document_create_fs_links(document):
|
|||||||
#This should be a warning not an error
|
#This should be a warning not an error
|
||||||
#pass
|
#pass
|
||||||
except Exception, exc:
|
except Exception, exc:
|
||||||
raise Exception(_(u'Unable to create metadata indexing directory: %s') % exc)
|
warnings.append(_(u'Unable to create metadata indexing directory: %s') % exc)
|
||||||
|
|
||||||
return warnings
|
return warnings
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user