Spec-Zone.ru › Django 1.10

Функции базы данных

Приведённые ниже классы позволяют пользователям использовать функции, предоставляемые основной базой данных, в качестве аннотаций, агрегаций или фильтров в Django. Функции также являются выражениями, поэтому их можно использовать и комбинировать с другими выражениями, такими как функции агрегации.

В примерах каждой функции мы будем использовать следующую модель:

class Author(models.Model):
    name = models.CharField(max_length=50)
    age = models.PositiveIntegerField(null=True, blank=True)
    alias = models.CharField(max_length=50, null=True, blank=True)
    goes_by = models.CharField(max_length=50, null=True, blank=True)

Обычно не рекомендуется разрешать null=True для CharField, так как это позволяет полю иметь два «пустых значения», но это важно для примера Coalesce ниже.

Cast

class Cast(expression, output_field) [source]
Новое в Django 1.10.

Принудительно устанавливает тип результата expression на тип из output_field.

Пример использования:

>>> from django.db.models import FloatField
>>> from django.db.models.functions import Cast
>>> Value.objects.create(integer=4)
>>> value = Value.objects.annotate(as_float=Cast('integer', FloatField())).get()
>>> print(value.as_float)
4.0

Coalesce

class Coalesce(*expressions, **extra) [source]

Принимает список из как минимум двух имён полей или выражений и возвращает первое не-нулевое значение (обратите внимание, что пустая строка не считается нулевым значением). Каждый аргумент должен быть одного типа, поэтому смешивание текста и чисел приведёт к ошибке базы данных.

Примеры использования:

>>> # Get a screen name from least to most public
>>> from django.db.models import Sum, Value as V
>>> from django.db.models.functions import Coalesce
>>> Author.objects.create(name='Margaret Smith', goes_by='Maggie')
>>> author = Author.objects.annotate(
...    screen_name=Coalesce('alias', 'goes_by', 'name')).get()
>>> print(author.screen_name)
Maggie

>>> # Prevent an aggregate Sum() from returning None
>>> aggregated = Author.objects.aggregate(
...    combined_age=Coalesce(Sum('age'), V(0)),
...    combined_age_default=Sum('age'))
>>> print(aggregated['combined_age'])
0
>>> print(aggregated['combined_age_default'])
None

Предупреждение

Значение Python, переданное в Coalesce в MySQL, может быть преобразовано в неверный тип, если его не явно не привести к нужному типу базы данных:

>>> from django.db.models import DateTimeField
>>> from django.db.models.functions import Cast, Coalesce
>>> from django.utils import timezone
>>> now = timezone.now()
>>> Coalesce('updated', Cast(now, DateTimeField()))

Concat

class Concat(*expressions, **extra) [source]

Принимает список из как минимум двух текстовых полей или выражений и возвращает конкатенированный текст. Каждый аргумент должен быть типа text или char. Если вы хотите конкатенировать TextField() с CharField(), убедитесь, что вы указали Django, что output_field должен быть TextField(). Это также необходимо при конкатенации Value, как в примере ниже.

Эта функция никогда не вернёт нулевое значение. В тех бэкендах, где нулевой аргумент приводит к тому, что всё выражение становится нулевым, Django будет гарантировать, что каждая нулевая часть сначала будет преобразована в пустую строку.

Пример использования:

>>> # Get the display name as "name (goes_by)"
>>> from django.db.models import CharField, Value as V
>>> from django.db.models.functions import Concat
>>> Author.objects.create(name='Margaret Smith', goes_by='Maggie')
>>> author = Author.objects.annotate(
...    screen_name=Concat('name', V(' ('), 'goes_by', V(')'),
...    output_field=CharField())).get()
>>> print(author.screen_name)
Margaret Smith (Maggie)

Greatest

class Greatest(*expressions, **extra) [source]
Новое в Django 1.9.

Принимает список из как минимум двух имён полей или выражений и возвращает наибольшее значение. Каждый аргумент должен быть одного типа, поэтому смешивание текста и чисел приведёт к ошибке базы данных.

Пример использования:

class Blog(models.Model):
    body = models.TextField()
    modified = models.DateTimeField(auto_now=True)

class Comment(models.Model):
    body = models.TextField()
    modified = models.DateTimeField(auto_now=True)
    blog = models.ForeignKey(Blog, on_delete=models.CASCADE)

>>> from django.db.models.functions import Greatest
>>> blog = Blog.objects.create(body='Greatest is the best.')
>>> comment = Comment.objects.create(body='No, Least is better.', blog=blog)
>>> comments = Comment.objects.annotate(last_updated=Greatest('modified', 'blog__modified'))
>>> annotated_comment = comments.get()

annotated_comment.last_updated будет самым последним из blog.modified и comment.modified.

Предупреждение

Поведение Greatest при наличии одного или более выражений, которые могут быть null, отличается в разных базах данных:

  • PostgreSQL: Greatest вернёт наибольшее не-нулевое выражение или null, если все выражения null.
  • SQLite, Oracle и MySQL: Если какое-либо выражение null, Greatest вернёт null.

Поведение PostgreSQL можно эмулировать, используя Coalesce, если вам известно разумное минимальное значение, которое можно задать в качестве значения по умолчанию.

Least

class Least(*expressions, **extra) [source]
Новое в Django 1.9.

Принимает список из как минимум двух имён полей или выражений и возвращает наименьшее значение. Каждый аргумент должен быть одного типа, поэтому смешивание текста и чисел приведёт к ошибке базы данных.

Предупреждение

Поведение Least при наличии одного или более выражений, которые могут быть null, отличается в разных базах данных:

  • PostgreSQL: Least вернёт наименьшее не-нулевое выражение или null, если все выражения null.
  • SQLite, Oracle и MySQL: Если какое-либо выражение null, Least вернёт null.

Поведение PostgreSQL можно эмулировать, используя Coalesce, если вам известно разумное максимальное значение, которое можно задать в качестве значения по умолчанию.

Length

class Length(expression, **extra) [source]

Принимает одно текстовое поле или выражение и возвращает количество символов в значении. Если выражение имеет значение null, то длина также будет null.

Пример использования:

>>> # Get the length of the name and goes_by fields
>>> from django.db.models.functions import Length
>>> Author.objects.create(name='Margaret Smith')
>>> author = Author.objects.annotate(
...    name_length=Length('name'),
...    goes_by_length=Length('goes_by')).get()
>>> print(author.name_length, author.goes_by_length)
(14, None)

Также может быть зарегистрирован как преобразование. Например:

>>> from django.db.models import CharField
>>> from django.db.models.functions import Length
>>> CharField.register_lookup(Length, 'length')
>>> # Get authors whose name is longer than 7 characters
>>> authors = Author.objects.filter(name__length__gt=7)
Изменено в Django 1.9:

Добавлена возможность регистрации функции как преобразования.

Lower

class Lower(expression, **extra) [source]

Принимает одно текстовое поле или выражение и возвращает строку в нижнем регистре.

Также может быть зарегистрирован как преобразование, как описано в Length.

Пример использования:

>>> from django.db.models.functions import Lower
>>> Author.objects.create(name='Margaret Smith')
>>> author = Author.objects.annotate(name_lower=Lower('name')).get()
>>> print(author.name_lower)
margaret smith
Изменено в Django 1.9:

Добавлена возможность регистрации функции как преобразования.

Now

class Now [source]
Новое в Django 1.9.

Возвращает текущую дату и время сервера базы данных при выполнении запроса, обычно используя SQL CURRENT_TIMESTAMP.

Пример использования:

>>> from django.db.models.functions import Now
>>> Article.objects.filter(published__lte=Now())
<QuerySet [<Article: How to Django>]>

Пояснения для PostgreSQL

В PostgreSQL SQL CURRENT_TIMESTAMP возвращает время начала текущей транзакции. Поэтому для кросс-базовой совместимости, Now() использует STATEMENT_TIMESTAMP вместо. Если вам нужно время транзакции, используйте django.contrib.postgres.functions.TransactionNow.

Substr

class Substr(expression, pos, length=None, **extra) [source]

Возвращает подстроку длины length из поля или выражения, начиная с позиции pos. Позиция имеет индексацию с 1, поэтому позиция должна быть больше 0. Если length является None, то будет возвращена остальная часть строки.

Пример использования:

>>> # Set the alias to the first 5 characters of the name as lowercase
>>> from django.db.models.functions import Substr, Lower
>>> Author.objects.create(name='Margaret Smith')
>>> Author.objects.update(alias=Lower(Substr('name', 1, 5)))
1
>>> print(Author.objects.get(name='Margaret Smith').alias)
marga

Upper

class Upper(expression, **extra) [source]

Принимает одно текстовое поле или выражение и возвращает строку в верхнем регистре.

Также может быть зарегистрирован как преобразование, как описано в Length.

Пример использования:

>>> from django.db.models.functions import Upper
>>> Author.objects.create(name='Margaret Smith')
>>> author = Author.objects.annotate(name_upper=Upper('name')).get()
>>> print(author.name_upper)
MARGARET SMITH
Изменено в Django 1.9:

Добавлена возможность регистрации функции как преобразования.

Функции дат

Новое в Django 1.10.

В примерах каждой функции мы будем использовать следующую модель:

class Experiment(models.Model):
    start_datetime = models.DateTimeField()
    start_date = models.DateField(null=True, blank=True)
    end_datetime = models.DateTimeField(null=True, blank=True)
    end_date = models.DateField(null=True, blank=True)

Extract

class Extract(expression, lookup_name=None, tzinfo=None, **extra) [source]

Извлекает компонент даты в виде числа.

Принимает expression представляющий DateField или DateTimeField и lookup_name, и возвращает часть даты, на которую ссылается lookup_name как IntegerField. Django обычно использует функцию извлечения базы данных, поэтому вы можете использовать любую lookup_name, поддерживаемую вашей базой данных. Подкласс tzinfo, обычно предоставляемый pytz, может быть передан для извлечения значения в определённой часовой зоне.

Учитывая дату 2015-06-15 23:30:01.000321+00:00, встроенные lookup_name возвращают:

  • «год»: 2015
  • «месяц»: 6
  • «день»: 15
  • «день_недели»: 2
  • «час»: 23
  • «минута»: 30
  • «секунда»: 1

Если в Django активна другая часовая зона, например Australia/Melbourne, то дата преобразуется в эту часовую зону перед извлечением значения. Смещение часовой зоны для Мельбурна в примере даты выше составляет +10:00. Возвращаемые значения при активной этой часовой зоне будут такими же, за исключением:

  • «день»: 16
  • «день_недели»: 3
  • «час»: 9

week_day значения дней недели

Функция week_day lookup_type рассчитывается по-другому, чем в большинстве баз данных и в стандартных функциях Python. Эта функция вернет 1 для воскресенья, 2 для понедельника, и так далее, до 7 для субботы.

Эквивалентный расчет на Python:

>>> from datetime import datetime
>>> dt = datetime(2015, 6, 15)
>>> (dt.isoweekday() % 7) + 1
2

Каждый lookup_name выше имеет соответствующий Extract подкласс (перечисленный ниже), который обычно следует использовать вместо более громоздкого эквивалента, например, используйте ExtractYear(...) вместо Extract(..., lookup_name='year').

Пример использования:

>>> from datetime import datetime
>>> from django.db.models.functions import Extract
>>> start = datetime(2015, 6, 15)
>>> end = datetime(2015, 7, 2)
>>> Experiment.objects.create(
...    start_datetime=start, start_date=start.date(),
...    end_datetime=end, end_date=end.date())
>>> # Add the experiment start year as a field in the QuerySet.
>>> experiment = Experiment.objects.annotate(
...    start_year=Extract('start_datetime', 'year')).get()
>>> experiment.start_year
2015
>>> # How many experiments completed in the same year in which they started?
>>> Experiment.objects.filter(
...    start_datetime__year=Extract('end_datetime', 'year')).count()
1

DateField извлечение данных

class ExtractYear(expression, tzinfo=None, **extra) [source]
lookup_name = 'year'
class ExtractMonth(expression, tzinfo=None, **extra) [source]
lookup_name = 'month'
class ExtractDay(expression, tzinfo=None, **extra) [source]
lookup_name = 'day'
class ExtractWeekDay(expression, tzinfo=None, **extra) [source]
lookup_name = 'week_day'

Эти функции логически эквивалентны Extract('date_field', lookup_name). Каждый класс также является Transform зарегистрированным в DateField и DateTimeField как __(lookup_name), например, __year.

Так как у DateField нет компонента времени, только Extract подклассы, которые работают с частями даты, могут быть использованы с DateField:

>>> from datetime import datetime
>>> from django.utils import timezone
>>> from django.db.models.functions import (
...    ExtractYear, ExtractMonth, ExtractDay, ExtractWeekDay
... )
>>> start_2015 = datetime(2015, 6, 15, 23, 30, 1, tzinfo=timezone.utc)
>>> end_2015 = datetime(2015, 6, 16, 13, 11, 27, tzinfo=timezone.utc)
>>> Experiment.objects.create(
...    start_datetime=start_2015, start_date=start_2015.date(),
...    end_datetime=end_2015, end_date=end_2015.date())
>>> Experiment.objects.annotate(
...     year=ExtractYear('start_date'),
...     month=ExtractMonth('start_date'),
...     day=ExtractDay('start_date'),
...     weekday=ExtractWeekDay('start_date'),
... ).values('year', 'month', 'day', 'weekday').get(
...     end_date__year=ExtractYear('start_date'),
... )
{'year': 2015, 'month': 6, 'day': 15, 'weekday': 2}

DateTimeField извлечение данных

В дополнение к следующему, все функции извлечения для DateField , перечисленные выше, также могут быть использованы с DateTimeField.

class ExtractHour(expression, tzinfo=None, **extra) [source]
lookup_name = 'hour'
class ExtractMinute(expression, tzinfo=None, **extra) [source]
lookup_name = 'minute'
class ExtractSecond(expression, tzinfo=None, **extra) [source]
lookup_name = 'second'

Эти функции логически эквивалентны Extract('datetime_field', lookup_name). Каждый класс также является Transform зарегистрированным в DateTimeField как __(lookup_name), например, __minute.

DateTimeField примеры:

>>> from datetime import datetime
>>> from django.utils import timezone
>>> from django.db.models.functions import (
...    ExtractYear, ExtractMonth, ExtractDay, ExtractWeekDay,
...    ExtractHour, ExtractMinute, ExtractSecond,
... )
>>> start_2015 = datetime(2015, 6, 15, 23, 30, 1, tzinfo=timezone.utc)
>>> end_2015 = datetime(2015, 6, 16, 13, 11, 27, tzinfo=timezone.utc)
>>> Experiment.objects.create(
...    start_datetime=start_2015, start_date=start_2015.date(),
...    end_datetime=end_2015, end_date=end_2015.date())
>>> Experiment.objects.annotate(
...     year=ExtractYear('start_datetime'),
...     month=ExtractMonth('start_datetime'),
...     day=ExtractDay('start_datetime'),
...     weekday=ExtractWeekDay('start_datetime'),
...     hour=ExtractHour('start_datetime'),
...     minute=ExtractMinute('start_datetime'),
...     second=ExtractSecond('start_datetime'),
... ).values(
...     'year', 'month', 'day', 'weekday', 'hour', 'minute', 'second',
... ).get(end_datetime__year=ExtractYear('start_datetime'))
{'year': 2015, 'month': 6, 'day': 15, 'weekday': 2, 'hour': 23, 'minute': 30, 'second': 1}

Когда USE_TZ имеет значение True, datetime хранятся в базе данных в UTC. Если в Django активен другой часовой пояс, значение datetime преобразуется в этот часовой пояс перед извлечением. Нижеприведенный пример преобразует в часовой пояс Мельбурна (UTC +10:00), что изменяет значения дня, дня недели и часа, возвращаемые функцией:

>>> import pytz
>>> melb = pytz.timezone('Australia/Melbourne')  # UTC+10:00
>>> with timezone.override(melb):
...    Experiment.objects.annotate(
...        day=ExtractDay('start_datetime'),
...        weekday=ExtractWeekDay('start_datetime'),
...        hour=ExtractHour('start_datetime'),
...    ).values('day', 'weekday', 'hour').get(
...        end_datetime__year=ExtractYear('start_datetime'),
...    )
{'day': 16, 'weekday': 3, 'hour': 9}

Явное указание часового пояса в функции Extract ведет себя аналогичным образом и имеет приоритет над активным часовым поясом:

>>> import pytz
>>> melb = pytz.timezone('Australia/Melbourne')
>>> Experiment.objects.annotate(
...     day=ExtractDay('start_datetime', tzinfo=melb),
...     weekday=ExtractWeekDay('start_datetime', tzinfo=melb),
...     hour=ExtractHour('start_datetime', tzinfo=melb),
... ).values('day', 'weekday', 'hour').get(
...     end_datetime__year=ExtractYear('start_datetime'),
... )
{'day': 16, 'weekday': 3, 'hour': 9}

Trunc

class Trunc(expression, kind, output_field=None, tzinfo=None, **extra) [source]

Округляет дату до значимого компонента.

Если вам важно только то, произошло ли что-то в определенном году, часу или дне, а не точная секунда, то Trunc (и его подклассы) могут быть полезны для фильтрации или агрегации данных. Например, вы можете использовать Trunc для подсчета числа продаж по дням.

Trunc принимает один expression, представляющий DateField или DateTimeField, kind, представляющий часть даты, и output_field, которая является DateTimeField() или DateField(). Он возвращает datetime или date, в зависимости от output_field, с полями до kind, установленных в минимальное значение. Если output_field опущено, оно по умолчанию принимает значение output_field от expression. Подкласс tzinfo, обычно предоставляемый pytz, может быть передан для усечения значения в определенном часовом поясе.

Для datetime 2015-06-15 14:30:50.000321+00:00 встроенные функции kind возвращают:

  • “year”: 2015-01-01 00:00:00+00:00
  • “month”: 2015-06-01 00:00:00+00:00
  • “day”: 2015-06-15 00:00:00+00:00
  • “hour”: 2015-06-15 14:00:00+00:00
  • “minute”: 2015-06-15 14:30:00+00:00
  • “second”: 2015-06-15 14:30:50+00:00

Если в Django активен другой часовой пояс, например, Australia/Melbourne, то datetime преобразуется в новый часовой пояс перед усечением. Смещение часового пояса Мельбурна в примере даты выше составляет +10:00. Значения, возвращаемые при активации этого часового пояса, будут:

  • “year”: 2015-01-01 00:00:00+11:00
  • “month”: 2015-06-01 00:00:00+10:00
  • “day”: 2015-06-16 00:00:00+10:00
  • “hour”: 2015-06-16 00:00:00+10:00
  • “minute”: 2015-06-16 00:30:00+10:00
  • “second”: 2015-06-16 00:30:50+10:00

У года есть смещение +11:00, потому что результат перешел в летнее время.

Каждый kind выше имеет соответствующий Trunc подкласс (перечисленный ниже), который обычно следует использовать вместо более громоздкого эквивалента, например, используйте TruncYear(...) вместо Trunc(..., kind='year').

Подклассы определены как преобразования, но не зарегистрированы ни с какими полями, потому что очевидные имена поиска уже зарезервированы подклассами Extract.

Пример использования:

>>> from datetime import datetime
>>> from django.db.models import Count, DateTimeField
>>> from django.db.models.functions import Trunc
>>> Experiment.objects.create(start_datetime=datetime(2015, 6, 15, 14, 30, 50, 321))
>>> Experiment.objects.create(start_datetime=datetime(2015, 6, 15, 14, 40, 2, 123))
>>> Experiment.objects.create(start_datetime=datetime(2015, 12, 25, 10, 5, 27, 999))
>>> experiments_per_day = Experiment.objects.annotate(
...    start_day=Trunc('start_datetime', 'day', output_field=DateTimeField())
... ).values('start_day').annotate(experiments=Count('id'))
>>> for exp in experiments_per_day:
...     print(exp['start_day'], exp['experiments'])
...
2015-06-15 00:00:00 2
2015-12-25 00:00:00 1
>>> experiments = Experiment.objects.annotate(
...    start_day=Trunc('start_datetime', 'day', output_field=DateTimeField())
... ).filter(start_day=datetime(2015, 6, 15))
>>> for exp in experiments:
...     print(exp.start_datetime)
...
2015-06-15 14:30:50.000321
2015-06-15 14:40:02.000123

DateField усечение

class TruncYear(expression, output_field=None, tzinfo=None, **extra) [source]
kind = 'year'
class TruncMonth(expression, output_field=None, tzinfo=None, **extra) [source]
kind = 'month'

Эти функции логически эквивалентны Trunc('date_field', kind). Они усекают все части даты до kind, что позволяет группировать или фильтровать даты с меньшей точностью. expression может иметь output_field в формате DateField или DateTimeField.

Так как у DateField нет компонента времени, только Trunc подклассы, которые обрабатывают части даты, могут использоваться с DateField:

>>> from datetime import datetime
>>> from django.db.models import Count
>>> from django.db.models.functions import TruncMonth, TruncYear
>>> from django.utils import timezone
>>> start1 = datetime(2014, 6, 15, 14, 30, 50, 321, tzinfo=timezone.utc)
>>> start2 = datetime(2015, 6, 15, 14, 40, 2, 123, tzinfo=timezone.utc)
>>> start3 = datetime(2015, 12, 31, 17, 5, 27, 999, tzinfo=timezone.utc)
>>> Experiment.objects.create(start_datetime=start1, start_date=start1.date())
>>> Experiment.objects.create(start_datetime=start2, start_date=start2.date())
>>> Experiment.objects.create(start_datetime=start3, start_date=start3.date())
>>> experiments_per_year = Experiment.objects.annotate(
...    year=TruncYear('start_date')).values('year').annotate(
...    experiments=Count('id'))
>>> for exp in experiments_per_year:
...     print(exp['year'], exp['experiments'])
...
2014-01-01 1
2015-01-01 2

>>> import pytz
>>> melb = pytz.timezone('Australia/Melbourne')
>>> experiments_per_month = Experiment.objects.annotate(
...    month=TruncMonth('start_datetime', tzinfo=melb)).values('month').annotate(
...    experiments=Count('id'))
>>> for exp in experiments_per_month:
...     print(exp['month'], exp['experiments'])
...
2015-06-01 00:00:00+10:00 1
2016-01-01 00:00:00+11:00 1
2014-06-01 00:00:00+10:00 1

DateTimeField усечение

class TruncDate(expression, **extra) [source]
lookup_name = 'date'
output_field = DateField()

TruncDate преобразует expression в дату, а не используя встроенную SQL функцию усечения. Он также зарегистрирован как преобразование в DateTimeField как __date.

class TruncDay(expression, output_field=None, tzinfo=None, **extra) [source]
kind = 'day'
class TruncHour(expression, output_field=None, tzinfo=None, **extra) [source]
kind = 'hour'
class TruncMinute(expression, output_field=None, tzinfo=None, **extra) [source]
kind = 'minute'
class TruncSecond(expression, output_field=None, tzinfo=None, **extra) [source]
kind = 'second'

Эти функции логически эквивалентны Trunc('datetime_field', kind). Они усекают все части даты до kind и позволяют группировать или фильтровать datetime с меньшей точностью. expression должен иметь output_field в формате DateTimeField.

Пример использования:

>>> from datetime import date, datetime
>>> from django.db.models import Count
>>> from django.db.models.functions import (
...     TruncDate, TruncDay, TruncHour, TruncMinute, TruncSecond,
... )
>>> from django.utils import timezone
>>> import pytz
>>> start1 = datetime(2014, 6, 15, 14, 30, 50, 321, tzinfo=timezone.utc)
>>> Experiment.objects.create(start_datetime=start1, start_date=start1.date())
>>> melb = pytz.timezone('Australia/Melbourne')
>>> Experiment.objects.annotate(
...     date=TruncDate('start_datetime'),
...     day=TruncDay('start_datetime', tzinfo=melb),
...     hour=TruncHour('start_datetime', tzinfo=melb),
...     minute=TruncMinute('start_datetime'),
...     second=TruncSecond('start_datetime'),
... ).values('date', 'day', 'hour', 'minute', 'second').get()
{'date': datetime.date(2014, 6, 15),
 'day': datetime.datetime(2014, 6, 16, 0, 0, tzinfo=<DstTzInfo 'Australia/Melbourne' AEST+10:00:00 STD>),
 'hour': datetime.datetime(2014, 6, 16, 0, 0, tzinfo=<DstTzInfo 'Australia/Melbourne' AEST+10:00:00 STD>),
 'minute': 'minute': datetime.datetime(2014, 6, 15, 14, 30, tzinfo=<UTC>),
 'second': datetime.datetime(2014, 6, 15, 14, 30, 50, tzinfo=<UTC>)
}

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/1.10/ref/models/database-functions/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API