Перейти к содержимому

Значения полей списков: чтение и обновление

Руководство по программной работе с field_values элементов списка — REST API, JavaScript WebPart, C# SDK (WebPart, Event Receiver, Timer Job).

Пошаговая форма WebPart и удобный API PortalListItem (item["title"], UpdateAsync): Кастомная форма: все типы полей.

См. также: API списков (эндпоинты, типы полей, фильтрация).

  1. Схема полейGET /lists/{listId}/fields или GetFieldsAsync. У каждого поля есть id (UUID) и internal_name (title, status…).

  2. Значения в ответах — объект field_values с ключами UUID. Для доступа по имени используйте GetListItemAsync / PortalListItem.

  3. Запись (POST/PATCH, CreateItemAsync/UpdateItemAsync) — ключи могут быть UUID или internal_name; сервер нормализует в UUID. PortalListItem пишет по internal_name.

Сырой вид ответа:

{
"id": 12,
"guid": "uuid-элемента",
"field_values": {
"uuid-поля-title": "Заголовок",
"uuid-поля-status": "Новая"
}
}
  1. id элемента в ответе API — публичный номер (12). Для GetItem / PATCH можно передать номер или guid.

  2. Обновление — merge: только переданные поля; затем сервер проверяет все обязательные поля схемы.

  3. Фильтр (filter, QueryItemsAsync) — в column допустим internal_name ("title").

  4. Версии — при включённом версионировании у версии полный снимок fieldValues (UUID-ключи).

ТипЗначение в fieldValues / field_values
text, multiline_text, choiceстрока
numberчисло
date"YYYY-MM-DD"
datetimeISO 8601
booleantrue / false
personмассив `[{ “principalType”: “user”
lookup`{ “itemId”: “12”
link{ "url": "https://...", "description": "..." }

# Схема полей
GET /api/v1/lists/{listId}/fields
# Найти элемент по заголовку
GET /api/v1/lists/{listId}/items?filter={"logic":"and","conditions":[{"column":"title","operator":"eq","value":"GlobalSettings"}]}&limit=1
# Один элемент (itemId = 12 или guid)
GET /api/v1/lists/{listId}/items/12

Создать:

POST /api/v1/lists/{listId}/items
Content-Type: application/json
{
"fieldValues": {
"uuid-поля-title": "Новая задача",
"uuid-поля-status": "Новая",
"uuid-поля-due": "2026-07-15"
}
}

Обновить одно поле (merge):

PATCH /api/v1/lists/{listId}/items/12
Content-Type: application/json
{
"fieldValues": {
"uuid-поля-status": "Готово"
}
}

Сложные типы:

{
"fieldValues": {
"uuid-assignees": [
{
"principalType": "user",
"id": "uuid-пользователя",
"display": "Иван Иванов"
},
{
"principalType": "group",
"id": "uuid-группы",
"display": "Редакторы HR"
}
],
"uuid-room": {
"itemId": "uuid-элемента-справочника",
"display": "Переговорная 301"
}
}
}

// Чтение
const fields = await ctx.lists.getFields(listId);
const titleField = fields.find(f => f.internal_name === 'title');
const titleFieldId = titleField.id;
const items = await ctx.lists.getItems(listId, {
filter: { logic: 'and', conditions: [{ column: 'title', operator: 'eq', value: 'A' }] },
top: 1,
});
const item = items[0];
const title = item.field_values?.[titleFieldId];
// Запись (через REST)
await PortalApi.patch(`/lists/${listId}/items/${item.id}`, {
fieldValues: { [statusFieldId]: 'Готово' },
});

В фильтрах — column: "title" (internal_name). При записи в fieldValues допустимы UUID и internal_name.


Права проверяются от имени пользователя страницы.

Рекомендуемый путьPortalListItem (подробно: кастомная форма; типы геттеров: § Типы за var):

using Portal.Contracts.Lists;
using Portal.WebPart.Sdk;
var item = await ctx.Lists.GetListItemAsync(listId, "12", ct); // PortalListItem
var title = item.GetString("title"); // string?
item["status"] = "Готово";
await item.UpdateAsync(ct);
var created = await ctx.Lists.NewListItemAsync(listId, ct);
created["title"] = "Новая задача";
await created.CreateAsync(ct);
var found = await ctx.Lists.QueryListItemsAsync(listId,
ListItemQueryBuilder.ForList(listId)
.WhereField("title", f => f.Eq("GlobalSettings"))
.Take(1)
.Build(), ct);

Больше примеров фильтров (AND/OR, даты, person, lookup, пагинация): Выборка элементов списка.

HandleActionAsync:

var item = await ctx.Lists.GetListItemAsync(listId, itemId, ct);
item["status"] = "Готово";
await item.UpdateAsync(ct);
return await RenderAsync(ctx, ct);

Низкоуровнево по-прежнему доступны GetItemAsync + UUID-ключи и PortalItemJson (версии). См. SDK WebPart.


Права — от пользователя события (context.User).

Рекомендуемый путьPortalListItem:

using Portal.Contracts.Lists;
using Portal.EventReceiver.Sdk;
public async Task<object?> HandleAsync(EventContext context, IReceiverApi api, CancellationToken ct)
{
// Текущий элемент события — без разбора Details вручную
var item = await context.GetListItemAsync(api, ct);
if (item is null) return new { skipped = true };
var currentTitle = item.GetString("title");
item["status"] = "Готово";
await item.UpdateAsync(ct);
return new { ok = true, was = currentTitle, itemRef = context.GetItemRef() };
}

Для listItem.deleted элемент уже удалён — берите снимок: await context.GetListItemSnapshotAsync(api, ct).
Справка: SDK Event Receiver § текущий элемент.

Низкоуровнево (UUID / версии):

using System.Text.Json;
var listId = context.GetListId()!.Value;
var itemRef = context.GetItemRef()!;
var fieldsJson = (JsonElement)await api.Lists.GetFieldsAsync(listId.ToString(), ct);
var titleFieldId = fieldsJson.EnumerateArray()
.First(f => f.GetProperty("internal_name").GetString() == "title")
.GetProperty("id").GetString()!;
var raw = (JsonElement)await api.Lists.GetItemAsync(listId.ToString(), itemRef, ct);
var currentTitle = raw.GetProperty("field_values").GetProperty(titleFieldId).GetString();
var v1 = (JsonElement)await api.Lists.GetItemVersionAsync(listId.ToString(), itemRef, 1, ct);
var titleV1 = v1.GetProperty("fieldValues").GetProperty(titleFieldId).GetString();
await api.Lists.UpdateItemAsync(listId.ToString(), itemRef, new Dictionary<string, object?>
{
[titleFieldId] = currentTitle, // или ["status"] = "Готово"
}, ct);

См. SDK Event Receiver.


Тот же API, что у Event Receiver (GetListItemAsync / PortalListItem). Права — от системной учётки portal-system (полный доступ).

using Portal.Contracts.Lists;
using Portal.TimerJob.Sdk;
public async Task<object?> ExecuteAsync(TimerJobContext context, ITimerJobApi api, CancellationToken ct)
{
var listId = Guid.Parse(context.Config.GetProperty("settingsListId").GetString()!);
var item = (await api.Lists.QueryListItemsAsync(listId,
ListItemQueryBuilder.ForList(listId)
.WhereField("title", f => f.Eq("GlobalSettings"))
.Take(1)
.Build(), ct)).First();
var oldValue = item.GetString("config_value");
item["config_value"] = "новое значение";
await item.UpdateAsync(ct);
return new { ok = true, oldValue };
}

См. SDK Timer Jobs.


При включённом версионировании списка (versioningEnabled / Настройки списка → Версионирование) у каждой версии хранится полный снимок fieldValues с теми же UUID-ключами, что у текущего элемента.

Подробности REST и формат ответа: API списков — Версии элементов.

GET /api/v1/lists/{listId}/items/12/versions
const res = await PortalApi.get(`/lists/${listId}/items/${itemId}/versions`);
const { versioningEnabled, versions, fields } = res.data;
if (!versioningEnabled) return;
const v2 = versions.find(v => v.versionNumber === 2);
const titleThen = v2?.fieldValues?.[titleFieldId];
// Одна версия — сразу снимок fieldValues
var v2 = await ctx.Lists.GetItemVersionAsync(listId, "12", versionNumber: 2, ct);
var titleThen = PortalItemJson.GetFieldString(v2, titleFieldId);
var dueThen = PortalItemJson.ReadDateTimeLocal(v2, dueFieldId);
// Вся история
var history = await ctx.Lists.GetItemVersionsAsync(listId, "12", ct);
if (!PortalItemJson.IsVersioningEnabled(history)) return;
foreach (var version in PortalItemJson.EnumerateVersions(history))
{
var n = PortalItemJson.GetVersionNumber(version);
var status = PortalItemJson.GetFieldString(version, statusFieldId);
}
// Версия из ответа истории без повторного запроса
if (PortalItemJson.TryFindVersion(history, 1, out var v1))
{
var createdTitle = PortalItemJson.GetFieldString(v1, titleFieldId);
}

Хелперы PortalItemJson.TryGetFieldValue / GetFieldString / ReadLookupGuid / ReadDateTimeLocal принимают и текущий элемент (field_values), и снимок версии (fieldValues).

var v1 = (JsonElement)await api.Lists.GetItemVersionAsync(listId, itemRef, 1, ct);
var titleV1 = v1.GetProperty("fieldValues").GetProperty(titleFieldId).GetString();
var history = (JsonElement)await api.Lists.GetItemVersionsAsync(listId, itemRef, ct);
var versions = history.GetProperty("versions");

Timer Job выполняется от системной учётки portal-system (полный доступ).


СпособЧитатьСоздатьОбновитьВерсии
REST APIPATCH (merge)GET .../versions
JS portalContextчерез PortalApi.postчерез PortalApi.patchчерез PortalApi.get
WebPart C#UpdateItemAsyncGetItemVersion(s)Async
Event Receiver
Timer Job✅ (portal-system)

Паттерн (рекомендуемый): GetListItemAsync / NewListItemAsyncitem["internal_name"]CreateAsync / UpdateAsync.
Низкоуровневый: схема → UUID → field_values[fieldId] (для истории версий — PortalItemJson).

Подробные кейсы: Кейсы работы с сущностями, кастомная форма.