def create_reltype(): parent_ct = get_ct(RelatedModel) child_ct = get_ct(AnotherRelatedModel) RelationshipType.objects.get_or_create( name="Parent Of", inverse_name="Child Of", from_type=parent_ct, to_type=child_ct, )
def to_representation(self, obj): data = super(TypedAttachmentSerializer, self).to_representation(obj) has_parent = ( self.parent and self.parent.parent and hasattr(self.parent.parent.Meta, 'model') ) if has_parent: # This is being serialized with its parent object, don't need to # reference the parent again. pass else: # Include pointer to parent object. Collapse content_type and # object_id into a single attribute: the identifier for the content # type plus '_id' e.g. if contenttype's name is 'visit' then the # attribute is 'visit_id'. This lets us pretend the generic # foreign key is a regular one in client. For the value, Use # get_object_id insted of obj.object_id, in case the the content # object is an IdentifiedModel parent_obj = getattr(obj, self.Meta.object_field) if parent_obj is not None: idname = get_ct(parent_obj).identifier data[idname + '_id'] = get_object_id(parent_obj) # In detail views, include full parent object (without _id # suffix) if self.is_detail: from wq.db import rest data[idname] = rest.router.serialize(parent_obj) return data
def extra_routes(cls): routes = [] ct = get_ct(cls.model) for pct in get_related_parents(ct): if not pct.is_registered(): continue if pct.urlbase == "": purlbase = "" else: purlbase = pct.urlbase + "/" routes.append( Route( ("^" + purlbase + r"(?P<related_" + pct.identifier + ">[^\/\?]+)/{prefix}{trailing_slash}$"), mapping={"get": "list"}, name="{basename}-for-related-%s" % pct.identifier, initkwargs={"suffix": "List"}, ) ) for cct in get_related_children(ct): if not cct.is_registered(): continue cbase = cct.urlbase routes.append( Route( url="^%s-by-{prefix}" % cbase, mapping={"get": "list"}, name="%s-by-%s" % (cct.identifier, ct.identifier), initkwargs={"target": cbase, "suffix": "List"}, ) ) return routes
def get_value(self, dictionary): # Handle attachments that are submitted together with their parent # Ideal case: an array of dicts; this can be handled by the default # implementation. HTML JSON forms will use this approach. if self.field_name in dictionary: return super(TypedAttachmentListSerializer, self).get_value(dictionary) # Deprecated/"classic" form style, where each attachment is submitted # as form fields with names in the format [model]_[typeid] e.g. # annotation_23=30.5 will become {'type': 23, 'value': '30.5'} # Retrieve form values into more usable array/dict format attachments = [] ct = get_ct(self.child.Meta.model) i = 0 for atype in self.child.expected_types: fields = { afield: "%s-%s-%s" % (ct.identifier, get_object_id(atype) if atype else "", afield) for afield in self.child.attachment_fields } found = False for key in fields.values(): if key in dictionary: found = True if found: attachment = self.child.create_dict(atype, dictionary, fields, i) if attachment: attachments.append(attachment) i += 1 # Return extracted values to default implementation return attachments
def to_representation(self, obj): if hasattr(obj, 'content_type_id') and hasattr(obj, 'content_object'): ctype = ContentType.objects.get(pk=obj.content_type_id) if isinstance(obj, Identifier): match_str = "%s (%s)" % (obj.name, obj.slug) elif isinstance(obj, Annotation): match_str = obj.value else: match_str = str(obj) obj = obj.content_object else: ctype = get_ct(obj) match_str = str(obj) if not ctype.is_registered(): raise ImproperlyConfigured( "Register %s to include it in search results" % ctype.model_class()) obj_id = get_object_id(obj) url = ctype.urlbase if url: url += '/' url += str(obj_id) return { 'id': obj_id, 'url': url, 'type': str(ctype), 'label': str(obj), 'match': match_str, }
def to_representation(self, obj): if hasattr(obj, 'content_type_id') and hasattr(obj, 'content_object'): ctype = ContentType.objects.get(pk=obj.content_type_id) if isinstance(obj, Identifier): match_str = "%s (%s)" % (obj.name, obj.slug) elif isinstance(obj, Annotation): match_str = obj.value else: match_str = str(obj) obj = obj.content_object else: ctype = get_ct(obj) match_str = str(obj) if not ctype.is_registered(): raise ImproperlyConfigured( "Register %s to include it in search results" % ctype.model_class() ) obj_id = get_object_id(obj) url = ctype.urlbase if url: url += '/' url += str(obj_id) return { 'id': obj_id, 'url': url, 'type': str(ctype), 'label': str(obj), 'match': match_str, }
def extra_routes(cls): routes = [] ct = get_ct(cls.model) for pct in get_related_parents(ct): if not pct.is_registered(): continue if pct.urlbase == '': purlbase = '' else: purlbase = pct.urlbase + '/' routes.append(Route( ( '^' + purlbase + r'(?P<related_' + pct.identifier + '>[^\/\?]+)/{prefix}{trailing_slash}$' ), mapping={'get': 'list'}, name="{basename}-for-related-%s" % pct.identifier, initkwargs={'suffix': 'List'}, )) for cct in get_related_children(ct): if not cct.is_registered(): continue cbase = cct.urlbase routes.append(Route( url='^%s-by-{prefix}' % cbase, mapping={'get': 'list'}, name="%s-by-%s" % (cct.identifier, ct.identifier), initkwargs={'target': cbase, 'suffix': 'List'}, )) return routes
def to_representation(self, obj): data = super(TypedAttachmentSerializer, self).to_representation(obj) has_parent = (self.parent and self.parent.parent and hasattr(self.parent.parent.Meta, 'model')) if has_parent: # This is being serialized with its parent object, don't need to # reference the parent again. pass else: # Include pointer to parent object. Collapse content_type and # object_id into a single attribute: the identifier for the content # type plus '_id' e.g. if contenttype's name is 'visit' then the # attribute is 'visit_id'. This lets us pretend the generic # foreign key is a regular one in client. For the value, Use # get_object_id insted of obj.object_id, in case the the content # object is an IdentifiedModel parent_obj = getattr(obj, self.object_field) idname = get_ct(parent_obj).identifier data[idname + '_id'] = get_object_id(parent_obj) # In detail views, include full parent object (without _id suffix) if self.is_detail: from wq.db import rest data[idname] = rest.router.serialize(parent_obj) return data
def list(self, request, *args, **kwargs): response = super(RelatedModelViewSet, self).list( request, *args, **kwargs ) ct = get_ct(self.model) for pct in get_related_parents(ct): self.get_parent(pct, 'related_%s' % pct.identifier, response) return response
def get_choices(run): def make_list(cls, name): rows = cls.objects.all() ct = get_ct(cls) result = [{ 'id': '%s/new' % ctid(ct), 'label': "New %s" % name, }] result += [{ 'id': '%s/%s' % (ctid(ct), row.pk), 'label': str(row), } for row in rows] return {'name': name, 'choices': result} meta_choices = set() def add_meta_choice(ct, field): mid = '%s:%s' % (ctid(ct), field) mlabel = ('%s %s' % (ct.model, field)).title() meta_choices.add((mid, mlabel)) for field in Site._meta.fields: if field.name not in ('slug', 'name'): add_meta_choice(get_ct(Site), field.name) for field in Event._meta.fields: if field.name not in ('id', 'site'): add_meta_choice(get_ct(Event), field.name) for m in Identifier.objects.filter(resolved=True, field__isnull=False): assert (m.type == 'meta') add_meta_choice(m.content_type, m.field) meta_choices = sorted(meta_choices, key=lambda d: d[1]) choices = [{ 'name': 'Metadata', 'choices': [{ 'id': key, 'label': label } for key, label in sorted(meta_choices)], }, make_list(Parameter, "Parameter")] return choices
def setUp(self): self.parent_ct = get_ct(RelatedModel) self.child_ct = get_ct(AnotherRelatedModel) self.reltype = RelationshipType.objects.get( name="Parent Of", inverse_name="Child Of", from_type=self.parent_ct, to_type=self.child_ct, ) self.parent = RelatedModel.objects.create(name="Parent1") self.child = AnotherRelatedModel.objects.create(name="Child1") Relationship.objects.create( type=self.reltype, from_content_type=self.parent_ct, from_object_id=self.parent.pk, to_content_type=self.child_ct, to_object_id=self.child.pk, )
def make_list(cls, name): rows = cls.objects.all() ct = get_ct(cls) result = [{ 'id': '%s/new' % ctid(ct), 'label': "New %s" % name, }] result += [{ 'id': '%s/%s' % (ctid(ct), row.pk), 'label': str(row), } for row in rows] return {'name': name, 'choices': result}
def to_native(self, loc): has_parent = self.parent and hasattr(self.parent.opts, 'model') if self.as_geometry and has_parent: return json.loads(loc.geometry.geojson) data = super(LocationSerializer, self).to_native(loc) if has_parent: pass else: # Include pointer to parent object (see annotate/serializers.py) idname = get_ct(loc.content_object).identifier + '_id' data[idname] = get_object_id(loc.content_object) return data
def get_object_id(self, obj): # Try to use the same identifier that the webservice uses for # this parameter/site/etc. if get_ct(obj).is_identified: idents = obj.identifiers.filter( authority=self.webservice.authority) else: idents = [] if len(idents) > 0: return idents[0].slug else: # No authority-specific IDs found, use default ID for object return get_object_id(obj)
def to_representation(self, loc): has_parent = (self.parent and self.parent.parent and hasattr(self.parent.parent.Meta, 'model')) if self.as_geometry and has_parent: return json.loads(loc.geometry.geojson) data = super(LocationSerializer, self).to_representation(loc) if has_parent: pass else: # Include pointer to parent object (see annotate/serializers.py) idname = get_ct(loc.content_object).identifier + '_id' data[idname] = get_object_id(loc.content_object) return data
def get_object_id(self, obj): # Try to use the same identifier that the webservice uses for # this parameter/site/etc. if get_ct(obj).is_identified: idents = obj.identifiers.filter( authority=self.webservice.authority ) else: idents = [] if len(idents) > 0: return idents[0].slug else: # No authority-specific IDs found, use default ID for object return get_object_id(obj)
def filter_queryset(self, request, queryset, view): ctype = get_ct(view.model) filter = {} for key, val in list(view.kwargs.items()) + list(request.GET.items()): if not key.startswith('related_'): continue if isinstance(val, list): val = val[0] for pct in get_related_parents(ctype): if key == 'related_' + pct.identifier: pclass = pct.model_class() parent = get_by_identifier(pclass.objects, val) objs = view.model.objects.filter_by_related(parent) filter['pk__in'] = objs.values_list('pk', flat=True) return queryset.filter(**filter)
def right_dict(self): key = self._cache_prefix + str(self.pk) cache = type(self)._dict_cache if key not in cache: from wq.db.rest.models import get_object_id, get_ct obj = self.right oid = get_object_id(obj) ct = get_ct(obj) cache[key] = { 'item_id': get_object_id(obj), 'item_label': str(obj), 'item_url': '%s/%s' % (ct.urlbase, oid), 'item_page': ct.identifier } return cache[key]
def update_columns(instance, user, post): matched = get_columns(instance) for col in matched: if col['type'] != 'unknown': continue val = post.get('rel_%s' % col['rel_id'], None) if not val: continue vtype, vid = val.split('/') if vtype == 'parameters': cls = Parameter elif vtype == 'metacolumns': cls = MetaColumn else: continue if vid == 'new': obj = cls.objects.find(col['value']) obj.contenttype = CONTENT_TYPES[Parameter] obj.save() ident = obj.primary_identifier else: obj = cls.objects.get_by_identifier(vid) ident = obj.identifiers.create( name=col['value'] ) reltype, is_new = RelationshipType.objects.get_or_create( from_type=get_ct(instance), to_type=CONTENT_TYPES[cls], name='Contains Column', inverse_name='Column In' ) rel = instance.relationships.get(pk=col['rel_id']) rel.type = reltype rel.right = obj rel.save() new_metadata.send( sender=update_columns, instance=instance, object=obj, identifier=ident, ) return read_columns(instance)
def to_native(self, obj): if hasattr(obj, 'content_type_id') and hasattr(obj, 'content_object'): ctype = ContentType.objects.get(pk=obj.content_type_id) obj = obj.content_object else: ctype = get_ct(obj) url = ctype.urlbase if url: url += '/' url += unicode(get_object_id(obj)) return { 'url': url, 'type': unicode(ctype), 'label': unicode(obj) }
def to_representation(self, obj): if hasattr(obj, 'content_type_id') and hasattr(obj, 'content_object'): ctype = ContentType.objects.get(pk=obj.content_type_id) obj = obj.content_object else: ctype = get_ct(obj) obj_id = get_object_id(obj) url = ctype.urlbase if url: url += '/' url += str(obj_id) return { 'id': obj_id, 'url': url, 'type': str(ctype), 'label': str(obj) }
def to_native(self, obj): data = super(TypedAttachmentSerializer, self).to_native(obj) has_parent = self.parent and hasattr(self.parent.opts, 'model') if has_parent: # This is being serialized with its parent object, don't need to # reference the parent again. pass else: # Include pointer to parent object. Collapse content_type and # object_id into a single attribute: the identifier for the content # type plus '_id' e.g. if contenttype's name is 'visit' then the # attribute is 'visit_id'. This lets us pretend the generic # foreign key is a regular one in client. For the value, Use # get_object_id insted of obj.object_id, in case the the content # object is an IdentifiedModel parent_obj = getattr(obj, self.object_field) idname = get_ct(parent_obj).identifier + '_id' data[idname] = get_object_id(parent_obj) return data
def field_from_native(self, data, files, field_name, into): # Handle attachments that are submitted together with their parent # Ideal case: an array of dicts, this can be handled by the default # implementation if field_name in data: return super(TypedAttachmentSerializer, self).field_from_native( data, files, field_name, into ) # Common case: form submission. In this case each attachment should # be submitted as form fields with names in the format [model]_[typeid] # e.g. annotation_23=30.5 will become {'type': 23, 'value': '30.5'} # Retrieve form values into more usable array/dict format attachments = [] ct = get_ct(self.opts.model) i = 0 for atype in self.expected_types: fields = { afield: '%s-%s-%s' % ( ct.identifier, get_object_id(atype) if atype else '', afield ) for afield in self.attachment_fields } found = False for key in fields.values(): if key in data: found = True if found: attachment = self.create_dict(atype, data, fields, i) if attachment: attachments.append(attachment) i += 1 # Send modified object to default implementation return super(TypedAttachmentSerializer, self).field_from_native( {field_name: attachments}, files, field_name, into )
def list(self, request, *args, **kwargs): response = super().list(request, *args, **kwargs) content_type = get_ct(self.model) for parent_content_type, fields in content_type.get_foreign_keys( ).items(): if len(fields) == 1: parent = self.get_parent(parent_content_type, fields[0], response) if not parent: continue # got the grandparent, not the parent response.data['parent_url'] = parent_content_type.urlbase response.data[ 'parent_label'] = parent_content_type.name + ' list' for grandparent_content_type, fields in parent_content_type.get_foreign_keys( ).items(): if len(fields) == 1: grandparent_model_class = grandparent_content_type.model_class( ) parent_model_class = parent_content_type.model_class() grandparent_field_name = '' for field in parent_model_class._meta.fields: if type(field.rel).__name__ == 'ManyToOneRel': if field.rel.to == grandparent_model_class: grandparent_field_name = field.name grandparent_id = parent_model_class.objects.values( ).get(id=response.data['parent_id']).get( grandparent_field_name + '_id') response.data[ 'parent_url'] = grandparent_content_type.urlbase + '/' + str( grandparent_id ) + '/' + parent_content_type.urlbase # the parent_label doesn't work response.data['parent_label'] += ' for ' + str( getattr(parent, grandparent_field_name)) return response
def parse_column(instance, name, head, body, body_type): matches = list(Identifier.objects.filter_by_identifier(name)) if len(matches) > 0: matches.sort( key=lambda ident: PRIORITY.get(ident.content_type.name, 0) ) column = matches[0].content_object ctype = matches[0].content_type else: column = UnknownItem.objects.find(name) ctype = CONTENT_TYPES[UnknownItem] reltype, is_new = RelationshipType.objects.get_or_create( from_type=get_ct(instance), to_type=ctype, name='Contains Column', inverse_name='Column In' ) rel = instance.relationships.create( type=reltype, to_content_type=ctype, to_object_id=column.pk, ) Range.objects.create( relationship=rel, type='head', start_row=head[0], start_column=head[1], end_row=head[2], end_column=head[3] ) Range.objects.create( relationship=rel, type=body_type, start_row=body[0], start_column=body[1], end_row=body[2], end_column=body[3] )
def get_value(self, dictionary): # Handle attachments that are submitted together with their parent # Ideal case: an array of dicts; this can be handled by the default # implementation. HTML JSON forms will use this approach. if self.field_name in dictionary: return super(TypedAttachmentListSerializer, self).get_value(dictionary) # Deprecated/"classic" form style, where each attachment is submitted # as form fields with names in the format [model]_[typeid] e.g. # annotation_23=30.5 will become {'type': 23, 'value': '30.5'} # Retrieve form values into more usable array/dict format attachments = [] ct = get_ct(self.child.Meta.model) i = 0 for atype in self.child.expected_types: fields = { afield: '%s-%s-%s' % (ct.identifier, get_object_id(atype) if atype else '', afield) for afield in self.child.attachment_fields } found = False for key in fields.values(): if key in dictionary: found = True if found: attachment = self.child.create_dict(atype, dictionary, fields, i) if attachment: attachments.append(attachment) i += 1 # Return extracted values to default implementation return attachments
def list(self, request, *args, **kwargs): response = super(RelatedModelViewSet, self).list(request, *args, **kwargs) ct = get_ct(self.model) for pct in get_related_parents(ct): self.get_parent(pct, "related_%s" % pct.identifier, response) return response
def metaname(cls): return ctid(get_ct(cls)) + '_meta'
def read_row_identifiers(instance, user): coltypes = get_meta_columns(instance) ids = {} for mtype in coltypes: ids[mtype] = Counter() for row in instance.load_io(): for mtype, cols in coltypes.items(): counter = ids[mtype] meta = OrderedDict() for col in cols: meta[col['field_name']] = row[col['colnum']] key = tuple(meta.items()) counter[key] += 1 idgroups = [] unknown_ids = 0 for mtype in ids: cls = META_CLASSES[mtype] idinfo = { 'type_id': mtype, 'type_label': mtype.capitalize(), 'ids': [] } for key, count in ids[mtype].items(): meta = OrderedDict(key) try: obj = cls.objects.get_by_natural_key(meta['id']) except cls.DoesNotExist: obj = None info = { 'value': meta['id'], 'count': count, 'meta': [{ 'name': k, 'value': v } for k, v in meta.items() if k != 'id'] } if obj is not None: info['match'] = str(obj) # FIXME: Confirm that metadata hasn't changed else: info['ident_id'] = unknown_ids unknown_ids += 1 info['unknown'] = True choices = instance.get_id_choices(cls, meta) info['choices'] = [{ 'id': get_object_id(obj), 'label': str(obj), } for obj in choices] info['choices'].insert(0, { 'id': 'new', 'label': "New %s" % idinfo['type_label'], }) idinfo['ids'].append(info) idinfo['ids'].sort(key=lambda info: info['value']) idgroups.append(idinfo) if not unknown_ids: # Create relationships after all IDs are resolved. # FIXME: parse_columns() always creates relationships, using # UnknownItem to stand in for unknown column identifiers. # Use UnknownItem here as well? from_type = get_ct(instance) for idinfo in idgroups: cls = META_CLASSES[idinfo['type_id']] to_type = get_ct(cls) reltype, is_new = RelationshipType.objects.get_or_create( from_type=from_type, to_type=to_type, name='Contains Identifier', inverse_name='Identifier In' ) for info in idinfo['ids']: obj = cls.objects.get_by_natural_key(info['value']) rel, isnew = instance.relationships.get_or_create( type=reltype, to_content_type=to_type, to_object_id=obj.pk, from_content_type=from_type, from_object_id=instance.pk, ) # FIXME: create equivalent of Range objects here? return { 'unknown_count': unknown_ids, 'types': idgroups, }
Parameter = swapper.load_model('vera', 'Parameter') Result = swapper.load_model('vera', 'Result') META_CLASSES = { 'site': Site, 'event': Event, 'report': Report, 'parameter': Parameter, 'result': Result, } EVENT_KEY = [val for val, cls in Event.get_natural_key_info()] EventKey = namedtuple('EventKey', EVENT_KEY) CONTENT_TYPES = { Parameter: get_ct(Parameter), MetaColumn: get_ct(MetaColumn), UnknownItem: get_ct(UnknownItem), } DATE_FIELDS = { 'DateTimeField': datetime.datetime, 'DateField': datetime.date, } if hasattr(settings, 'WQ_DEFAULT_REPORT_STATUS'): DEFAULT_STATUS = settings.WQ_DEFAULT_REPORT_STATUS else: DEFAULT_STATUS = None PRIORITY = {