In the Google Ads API, updates are done using a field mask. The field mask lists all
the fields you intend to change with the update, and any specified fields that
are not in the field mask are ignored, even if sent to the server.

## Field mask helper

The recommended way to generate field masks is using the `field_mask` helper
function included in the `google.api_core` package. It accepts two protobuf
objects and returns a field mask object with a `paths` list that contains all of
the fields that are different between the two objects.

If `None` is passed as the first parameter, then the field mask list contains
all of the fields on the second protobuf object that are not set to their
default value.

Once constructed, the field mask object should be copied onto the operation
object that will be sent to the server.

### Update from a new local object

In the following example, you create an empty
[`CampaignOperation`](https://developers.google.com/google-ads/api/reference/rpc/v26/CampaignOperation) object and retrieve an
empty [`Campaign`](https://developers.google.com/google-ads/api/reference/rpc/v26/Campaign) object from its `update` field. You
then modify that campaign object and create a new field mask by comparing it to
`None`, which generates a field mask containing the modified
`network_settings.target_search_network` field:

    from google.ads.googleads.client import GoogleAdsClient
    from google.api_core import protobuf_helpers

    # Retrieve a GoogleAdsClient instance.
    client = GoogleAdsClient.load_from_storage()

    # Create a new campaign operation.
    campaign_operation = client.get_type("CampaignOperation")

    # Retrieve a new campaign object from its update field and set its resource
    # name.
    campaign = campaign_operation.update
    campaign.resource_name = client.get_service("CampaignService").campaign_path(
        customer_id, campaign_id
    )

    # Mutate the campaign (use direct attribute assignment in proto-plus).
    campaign.network_settings.target_search_network = False

    # Create a field mask using the updated campaign.
    # The field_mask helper is compatible with raw protobuf message instances,
    # which you can access using the ._pb attribute.
    field_mask = protobuf_helpers.field_mask(None, campaign._pb)

    # Copy the field_mask onto the operation's update_mask field.
    client.copy_from(campaign_operation.update_mask, field_mask)

### Update an existing resource

The following example updates an existing campaign retrieved from the API,
assuming a valid `resource_name` and `customer_id`. With this strategy,
`updated_campaign` shares all the fields retrieved on `initial_campaign`
(including its `resource_name`), and the generated field mask tells the API that
only the `network_settings.target_search_network` field changed:

    from google.ads.googleads.client import GoogleAdsClient
    from google.api_core import protobuf_helpers

    # Retrieve a GoogleAdsClient instance.
    client = GoogleAdsClient.load_from_storage()

    # Retrieve an instance of the GoogleAdsService.
    googleads_service = client.get_service("GoogleAdsService")

    # Search query to retrieve the campaign. Quote string literals in GAQL.
    query = f"""
        SELECT
          campaign.network_settings.target_search_network,
          campaign.resource_name
        FROM campaign
        WHERE campaign.resource_name = '{resource_name}'"""

    # Submit a query to retrieve a campaign instance.
    response = googleads_service.search_stream(
        customer_id=customer_id, query=query
    )

    # Iterate over results to retrieve the campaign.
    initial_campaign = None
    for batch in response:
        for row in batch.results:
            initial_campaign = row.campaign
            break

    if not initial_campaign:
        raise ValueError(f"Campaign '{resource_name}' not found.")

    # Create a new campaign operation.
    campaign_operation = client.get_type("CampaignOperation")

    # Set the copied campaign object to a variable for easy reference.
    updated_campaign = campaign_operation.update

    # Copy the retrieved campaign into the new campaign.
    # client.copy_from works with both native protobuf messages and messages
    # wrapped by the proto-plus library.
    client.copy_from(updated_campaign, initial_campaign)

    # Mutate the new campaign.
    updated_campaign.network_settings.target_search_network = False

    # Create a field mask by comparing initial and updated protobuf objects.
    field_mask = protobuf_helpers.field_mask(
        initial_campaign._pb, updated_campaign._pb
    )

    # Copy the field mask onto the operation's update_mask field.
    # Note that the client's copy_from method works with both native messages
    # and messages wrapped by proto-plus, including google.protobuf.field_mask_pb2.
    client.copy_from(campaign_operation.update_mask, field_mask)

### Clear fields or set empty messages

When comparing against `None`, the `field_mask` helper ignores fields set to
empty or default values. To explicitly clear a field or set an empty message
field, append the field path directly to `campaign_operation.update_mask.paths`.
For more details, see
[Set empty message objects as fields](https://developers.google.com/google-ads/api/docs/client-libs/python/empty-message-fields).