Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
En este artículo se muestra código de ejemplo que usa el SDK para trabajar con datos y metadatos de Dataverse. Antes de continuar, asegúrese de leer Introducción.
Operaciones Básico
Este es un ejemplo de código que funciona en la tabla de cuentas.
from azure.identity import InteractiveBrowserCredential
from PowerPlatform.Dataverse.client import DataverseClient
# Replace <myorg> with the name of a valid environment.
base_url = "https://<myorg>.crm.dynamics.com"
client = DataverseClient(base_url=base_url, credential=InteractiveBrowserCredential())
# Create a record
account_id = client.records.create("account", {"name": "Contoso Ltd"})
# Read a record
account = client.records.retrieve("account", account_id)
print(account["name"])
# Read with expand fetches a related record in the same HTTP request
account = client.records.retrieve(
"account", account_id,
select=["name"],
expand=["primarycontactid"],
)
contact = (account.get("primarycontactid") or {})
print(contact.get("fullname"))
# Update a record
client.records.update("account", account_id, {"telephone1": "555-0199"})
# Delete a record
client.records.delete("account", account_id)
Administrador de contextos
El Administrador de contextos controla la limpieza automática y la agrupación de conexiones HTTP. Use la sintaxis siguiente para aprovechar el Administrador de contextos.
with DataverseClient("https://<myorg>.crm.dynamics.com", credential) as client:
El código de trabajo siguiente muestra cómo usar el Administrador de contextos.
from azure.identity import InteractiveBrowserCredential
from PowerPlatform.Dataverse.client import DataverseClient
# Connect to Dataverse
credential = InteractiveBrowserCredential()
with DataverseClient("https://<myorg>.crm.dynamics.com", credential) as client:
# Create a contact
contact_id = client.records.create("contact", {"firstname": "John", "lastname": "Doe"})
# Read the contact back
contact = client.records.retrieve("contact", contact_id, select=["firstname", "lastname"])
print(f"Created: {contact['firstname']} {contact['lastname']}")
# Clean up
client.records.delete("contact", contact_id)
# Session closed, caches cleared automatically
Operaciones masivas
Estos son un par de ejemplos que realizan operaciones masivas.
# Bulk create
payloads = [
{"name": "Company A"},
{"name": "Company B"},
{"name": "Company C"}
]
ids = client.records.create("account", payloads)
# Bulk update (broadcast same change to all)
client.records.update("account", ids, {"industry": "Technology"})
# Bulk delete
client.records.delete("account", ids, use_bulk_delete=True)
En el ejemplo siguiente se crean varias cuentas. Pase una lista de cargas a create(logical_name, payloads) para invocar la acción enlazada a la colección de Microsoft.Dynamics.CRM.CreateMultiple. El método devuelve list[str] los identificadores de registro creados.
# Bulk create accounts (returns list of GUIDs)
payloads = [
{"name": "Contoso"},
{"name": "Fabrikam"},
{"name": "Northwind"},
]
ids = client.records.create("account", payloads)
assert isinstance(ids, list) and all(isinstance(x, str) for x in ids)
print({"created_ids": ids})
Para obtener más información sobre las operaciones masivas:
- Devuelve
None(igual que una actualización única) para mantener la semántica coherente. - La elección entre transmisión y procesamiento por registro se determina según si el parámetro
changeses un diccionario o una lista. - El atributo de clave principal se inserta automáticamente al construir destinos de acción UpdateMultiple .
- Si alguna carga omite @odata.type, el SDK lo marca automáticamente (búsqueda de nombres lógicos almacenados en caché).
- La respuesta solo incluye identificadores: el SDK devuelve esas cadenas GUID.
- La creación de un único registro devuelve una lista de un solo elemento de GUID.
- La búsqueda
@odata.typede metadatos se realiza una vez por conjunto de entidades (en memoria caché).
Upsert (crear y actualizar)
Una secuencia de acceso a datos común es comprobar primero si existe una fila de tabla. Si la fila existe, actualícela. De lo contrario, cree la fila. Puede hacer que esta secuencia sea más eficaz mediante una sola llamada API de la operación Upsert.
Para obtener más información, consulte Uso de Upsert para crear o actualizar un registro.
Important
La tabla debe tener una clave alternativa configurada en Dataverse para las columnas usadas en alternate_key. Defina claves alternativas en los metadatos de la tabla mediante el portal para creadores de Power Apps o una llamada a la API de Dataverse. Sin una clave alternativa configurada, Dataverse rechaza las solicitudes upsert con un error 400.
Use client.records.upsert() para crear o actualizar registros identificados por claves alternativas. Cuando la clave coincide con un registro existente, el método actualiza el registro. De lo contrario, crea el registro. Un solo elemento usa una petición PATCH, mientras que varios elementos usan la UpsertMultiple acción en bloque.
from PowerPlatform.Dataverse.models.upsert import UpsertItem
# Upsert a single record
client.records.upsert("account", [
UpsertItem(
alternate_key={"accountnumber": "ACC-001"},
record={"name": "Contoso Ltd", "telephone1": "555-0100"},
)
])
# Upsert multiple records (uses UpsertMultiple bulk action)
client.records.upsert("account", [
UpsertItem(
alternate_key={"accountnumber": "ACC-001"},
record={"name": "Contoso Ltd"},
),
UpsertItem(
alternate_key={"accountnumber": "ACC-002"},
record={"name": "Fabrikam Inc"},
),
])
# Composite alternate key (multiple columns identify the record)
client.records.upsert("account", [
UpsertItem(
alternate_key={"accountnumber": "ACC-001", "address1_postalcode": "98052"},
record={"name": "Contoso Ltd"},
)
])
# Plain dict syntax (no import needed)
client.records.upsert("account", [
{
"alternate_key": {"accountnumber": "ACC-001"},
"record": {"name": "Contoso Ltd"},
}
])
Marcos de datos
El SDK proporciona contenedores pandas para todas las operaciones CRUD a través del espacio de nombres client.dataframe. Estos contenedores usan las API de panda, DataFrame y Series para la entrada y salida.
Note
client.dataframe.get() está en desuso. Use los patrones GA mostrados en las secciones siguientes.
import pandas as pd
from PowerPlatform.Dataverse.models.filters import col
# Query records as a single DataFrame (GA builder pattern)
df = (client.query.builder("account")
.select("name", "telephone1")
.where(col("statecode") == 0)
.execute()
.to_dataframe())
print(f"Found {len(df)} accounts")
# Limit results with top for large tables
df = client.query.builder("account").select("name").top(100).execute().to_dataframe()
# Create records from a DataFrame (returns a Series of GUIDs)
new_accounts = pd.DataFrame([
{"name": "Contoso", "telephone1": "555-0100"},
{"name": "Fabrikam", "telephone1": "555-0200"},
])
new_accounts["accountid"] = client.dataframe.create("account", new_accounts)
# Update records from a DataFrame (id_column identifies the GUID column)
new_accounts["telephone1"] = ["555-0199", "555-0299"]
client.dataframe.update("account", new_accounts, id_column="accountid")
# Clear a field by setting clear_nulls=True (by default, NaN/None fields are skipped)
df = pd.DataFrame([{"accountid": new_accounts["accountid"].iloc[0], "websiteurl": None}])
client.dataframe.update("account", df, id_column="accountid", clear_nulls=True)
# Delete records by passing a Series of GUIDs
client.dataframe.delete("account", new_accounts["accountid"])
# SQL query directly to DataFrame (supports JOINs, aggregates, GROUP BY)
df = client.dataframe.sql(
"SELECT a.name, COUNT(c.contactid) as contacts "
"FROM account a "
"JOIN contact c ON a.accountid = c.parentcustomerid "
"GROUP BY a.name"
)
Carga de archivos en Dataverse
En el ejemplo siguiente se muestra cómo cargar un archivo denominado document.pdf en la columna Archivo denominado new_Document de un registro de cuenta. El SDK para Python controla automáticamente la fragmentación de archivos para los archivos de más de 128 MB.
# Upload a file to a record
client.files.upload(
"account",
account_id,
"new_Document",
"/path/to/document.pdf",
)
Tip
Si la columna de archivo no existe, el SDK lo crea automáticamente.
Operaciones por lotes
Use client.batch para enviar varias operaciones en una solicitud HTTP. El espacio de nombres por lotes refleja client.records, client.tables y client.query.
# Build a batch request and add operations
batch = client.batch.new()
batch.records.create("account", {"name": "Contoso"})
batch.records.create("account", [{"name": "Fabrikam"}, {"name": "Woodgrove"}])
batch.records.update("account", account_id, {"telephone1": "555-0100"})
batch.records.delete("account", old_id)
batch.records.retrieve("account", account_id, select=["name"], expand=["primarycontactid"]) # single record with expand
batch.records.list( # multi-record, single page
"account",
filter="statecode eq 0",
select=["name"],
orderby=["name asc"],
top=50,
)
result = batch.execute()
for item in result.responses:
if item.is_success:
print(f"[OK] {item.status_code} entity_id={item.entity_id}")
else:
print(f"[ERR] {item.status_code}: {item.error_message}")
Conjunto de cambios transaccionales
Todas las operaciones de un conjunto de cambios se completan o se revierten todas juntas.
batch = client.batch.new()
with batch.changeset() as cs:
lead_ref = cs.records.create("lead", {"firstname": "Ada"})
contact_ref = cs.records.create("contact", {"firstname": "Ada"})
cs.records.create("account", {
"name": "Babbage & Co.",
"originatingleadid@odata.bind": lead_ref,
"primarycontactid@odata.bind": contact_ref,
})
result = batch.execute()
print(f"Created {len(result.entity_ids)} records atomically")
Metadatos de tabla y consultas SQL en un lote
batch = client.batch.new()
batch.tables.create("new_Product", {"new_Price": "decimal", "new_InStock": "bool"})
batch.tables.add_columns("new_Product", {"new_Rating": "int"})
batch.tables.get("new_Product")
batch.query.sql("SELECT TOP 5 name FROM account")
result = batch.execute()
Continuar ante un error
Intente todas las operaciones incluso cuando se produzca un error.
result = batch.execute(continue_on_error=True)
print(f"Succeeded: {len(result.succeeded)}, Failed: {len(result.failed)}")
for item in result.failed:
print(f"[ERR] {item.status_code}: {item.error_message}")
Integración de DataFrame
Alimentar DataFrames de Pandas directamente en un lote.
import pandas as pd
batch = client.batch.new()
# Create records from a DataFrame
df = pd.DataFrame([{"name": "Contoso"}, {"name": "Fabrikam"}])
batch.dataframe.create("account", df)
# Update records from a DataFrame
updates = pd.DataFrame([
{"accountid": id1, "telephone1": "555-0100"},
{"accountid": id2, "telephone1": "555-0200"},
])
batch.dataframe.update("account", updates, id_column="accountid")
# Delete records from a Series
batch.dataframe.delete("account", pd.Series([id1, id2]))
result = batch.execute()
Para obtener un ejemplo de lote completo, consulte examples/advanced/batch.py.
Información relacionada
- Personalización de tablas y columnas
- Consultar datos
- Ejemplos de código del SDK para Python
- SDK para Python README