fairdm.api.filters#

FairDM API filter backends.

Module Contents#

Classes#

FairDMVisibilityFilter

Queryset-level visibility filter for FairDM API list endpoints.

DatasetFilterSet

Narrows a list to the records of one dataset, named by its short identifier.

SampleFilterSet

Narrows a list to the records made on one sample, named by its short identifier.

ChangedSinceFilterSet

Narrows a list to the records changed after, and before, a moment.

IdentifierFilter

Narrows a list to the contributor that holds an identifier.

PersonFilterSet

Narrows the people list to an organization’s members, or to the holder of an identifier.

OrganizationFilterSet

Narrows the organizations list by type, country, parent or identifier.

ContributorRecordsFilterSet

Narrows the project list or the dataset list to the records a contributor is credited on.

FairDMFilterBackend

Django-filter backend that gives every list its changed-since filters and its parents.

API#

class FairDMVisibilityFilter#

Bases: rest_framework.filters.BaseFilterBackend

Queryset-level visibility filter for FairDM API list endpoints.

Restricts list querysets to objects the requesting user can see:

  • Projects and datasets with visibility=PUBLIC are always included. Samples and measurements are included when their dataset is public and published: a public dataset that is not published shows its own record and keeps its data back.

  • Records the user holds at least the view level on, directly or from the dataset or project above, are also included. Rows that django-guardian stores for a project, dataset, sample or measurement grant nothing.

  • For any other model, records where the user holds a stored guardian ‘view’ permission.

Both sets are combined in one query to avoid N+1 queries.

For models with no known visibility mechanism (such as Organization), the filter returns the full queryset, making all records publicly accessible. The people list leaves accounts out in its own queryset. Override filter_queryset() in a viewset subclass for stricter filtering.

This replaces ObjectPermissionsFilter from djangorestframework-guardian, which requires explicit guardian entries for all objects and so hides publicly-visible records that have no guardian permission rows.

static hidden_contributors()#

Select the contributors the contributor list leaves out.

Returns: The primary keys of superusers and of the anonymous account, as Person.objects.real() leaves them out of the portal’s own lists.

filter_queryset(request: rest_framework.request.Request, queryset, view: rest_framework.views.APIView)#

Limit the queryset to public records plus those the user may view.

class DatasetFilterSet(*args, **kwargs)#

Bases: django_filters.FilterSet

Narrows a list to the records of one dataset, named by its short identifier.

A database number names no dataset and is refused, as is an identifier of a dataset the caller may not see.

Initialization

Offer only the datasets the requesting user may see, and no content-type filter.

dataset#

‘ModelChoiceFilter(…)’

static drops(filter_) → bool#

Say whether the API removes a filter when it builds the filter set for a request.

Args: filter_: A filter of the filter set.

Returns: True for a relation filter that does not match on the short identifier.

visible(queryset)#

Limit a queryset of filter choices to what the requesting user may see.

Args: queryset: The records the filter would otherwise offer.

Returns: The records the list filter would let the requesting user see.

classmethod match_relations_on_uuid() → None#

Make every relation filter of this class that can match on uuid do so.

The filters are replaced by copies, so a filter set the portal’s own pages share is left as it was. Call it on a class built for the API. A relation whose model has no uuid keeps its filter here and loses it when the filter set is built.

classmethod related_model(filter_) → type[django.db.models.Model] | None#

Return the model a relation filter chooses among.

Args: filter_: A relation filter of this class.

Returns: The model at the end of the filter’s field path, or None when the path does not end on a relation.

class SampleFilterSet(*args, **kwargs)#

Bases: fairdm.api.filters.DatasetFilterSet

Narrows a list to the records made on one sample, named by its short identifier.

Initialization

Offer only the samples the requesting user may see.

sample#

‘ModelChoiceFilter(…)’

class ChangedSinceFilterSet(data=None, queryset=None, *, request=None, prefix=None)#

Bases: django_filters.FilterSet

Narrows a list to the records changed after, and before, a moment.

Each value is an ISO 8601 date or date-time, compared with the record’s modified time as given. A date alone means the start of that day, and a time without an offset is read in the portal’s time zone. A value that cannot be read is refused with a 400 naming the parameter.

Initialization

modified_after#

‘IsoDateTimeFilter(…)’

modified_before#

‘IsoDateTimeFilter(…)’

class IdentifierFilter(*args, **kwargs)#

Bases: django_filters.CharFilter

Narrows a list to the contributor that holds an identifier.

The value is an identifier as stored, such as an ORCID iD, or the address it resolves to: the address of a known scheme is taken off the front, with or without a trailing slash and with http or https. A value is also matched with its spaces removed, as an ISNI is written in groups of four and stored without them.

Initialization

Match identifiers__value, which the filter set’s own models carry.

Args: *args: Passed to CharFilter. **kwargs: Passed to CharFilter.

static bare(value: str) → str#

Take the scheme address off the front of an identifier.

Args: value: The value sent, which may be an identifier or its address.

Returns: The identifier, trimmed and without a known scheme address or trailing slash.

filter(qs, value)#

Keep the contributors holding the identifier.

Args: qs: The queryset to narrow. value: The value sent.

Returns: The contributors that hold it, or all of them when no value was sent.

class PersonFilterSet(data=None, queryset=None, *, request=None, prefix=None)#

Bases: django_filters.FilterSet

Narrows the people list to an organization’s members, or to the holder of an identifier.

organization is the short identifier of an organization. It keeps the people with a verified affiliation to it that has not ended, and refuses a database number.

Initialization

organization#

‘ModelChoiceFilter(…)’

identifier#

‘IdentifierFilter(…)’

class Meta#
model#

None

fields: list[str]#

[]

narrow_to_members(queryset, name, organization)#

Keep the people with a verified, current affiliation to the organization.

Args: queryset: The people to narrow. name: The name of the filter. organization: The organization chosen.

Returns: The people with an affiliation to it of at least the member level and no end date.

class OrganizationFilterSet(data=None, queryset=None, *, request=None, prefix=None)#

Bases: django_filters.FilterSet

Narrows the organizations list by type, country, parent or identifier.

type is the stored code and country the two-letter code. parent_organization is the short identifier of an organization, and a database number is refused. top_level true keeps the organizations that are part of no other, and false those that are part of one.

Initialization

type#

‘ChoiceFilter(…)’

country#

‘CharFilter(…)’

parent_organization#

‘ModelChoiceFilter(…)’

top_level#

‘BooleanFilter(…)’

identifier#

‘IdentifierFilter(…)’

class Meta#
model#

None

fields: list[str]#

[]

narrow_to_top_level(queryset, name, value)#

Keep the organizations with no parent, or those with one.

Args: queryset: The organizations to narrow. name: The name of the filter. value: True for organizations with no parent, false for those with one.

Returns: The narrowed organizations.

class ContributorRecordsFilterSet(data=None, queryset=None, *, request=None, prefix=None)#

Bases: django_filters.FilterSet

Narrows the project list or the dataset list to the records a contributor is credited on.

contributor is the short identifier of a person the people list shows, or of an organization. The answer holds public records only, whoever asks, and only records the contributor is credited on: a project an organization owns without a credit is left out. An identifier that names nobody gives an empty list.

Initialization

contributor#

‘CharFilter(…)’

narrow_to_credited(queryset, name, value)#

Keep the public records the contributor is credited on.

Args: queryset: The projects or the datasets to narrow. name: The name of the filter. value: The short identifier sent.

Returns: The projects or datasets credited to the contributor, which may be none.

class FairDMFilterBackend#

Bases: django_filters.rest_framework.DjangoFilterBackend

Django-filter backend that gives every list its changed-since filters and its parents.

Every list takes modified_after and modified_before. A sample list also takes its dataset, and a measurement list its dataset and sample.

The filters a registered type declares match related records by database number, and are shared with the portal’s own pages. Here every relation filter matches by short identifier, a number is refused, and a filter on a relation with no identifier is left out.

generated_filtersets: dict[tuple, type]#

None

get_filterset_class(view, queryset=None)#

Build the list’s filter set: the type’s own, the parent filters and changed-since.

Args: view: The view being filtered. queryset: The queryset being filtered.

Returns: The filter set to use. The portal’s own filter set for the type is left as it is; the filters are added to a class built here.