如何从具有值数据的选择字段的允许值列表中删除项目?


16

我创建了一个具有列表/选择选项字段的内容类型,并根据需要输入了键|值对,以使选择列表起作用。

数据已输入,已经确定某些术语不再适用,应删除它们。

但是,当尝试删除所说的术语时,出现以下错误:

Allowed values list: some values are being removed while currently in use.

显然,在项目的整个生命周期中,价值都会发生变化。一旦节点与列出的术语相关联,删除项目的实际方法是什么?

这是我能找到的最接近的东西:

https://drupal.org/node/1653012

它引用了一个d6插件和一些我不想不必求助的补丁技巧。如果确实必须最终使用补丁程序删除该字段上的验证检查,那么在与它们关联的节点上将这些项目变成孤立项目是否有任何危害?

更新,我再次遇到了一个政府客户,在拥有Drupal网站的过去7年中,有一个政府客户选择了50个州和地区。现在,政策已更改,不再需要包括这些领土。能够从选择列表中删除项目很重要,因此,我提供了一笔赏金。

我正在寻找一种安全的解决方案,以便能够从选择列表中删除项目。我不知道该解决方案是否应该更新任何节点,因为我不确定字段值相对于节点总内容的存储方式。

我对在MySQL中运行纯SQL解决方案感到满意;或者,我正在寻找一个模块。


3
显然,在项目的整个生命周期中,价值都会发生变化。我会怀疑-静态选择列表的值应在项目开始时定义。如果需要灵活,则应使用术语引用而不是静态列表。静态清单用于诸如性别(男性/女性)之类的事物,除非我们对事物进行认真的调整,否则它不可能很快改变。如果这样做,它将被添加到而不是删除。每当我犯了“错误”时,我总是发现最好的退回方法是对数据运行手动查询
Clive

1
您要使此列表动态吗?动态创建和删除。
妈妈D 2014年

1
是的,我当时认为这是可以接受的-汽车制造商永远是我要建立的任何站点的节点类型或词汇。由于制造商是汽车的一种类别(或某人修理的汽车的类别),因此对我而言,分类法而非内容类型是最有意义的。但是我知道这无济于事...我会谨慎地将孤立的数据留在数据库中,很难说出在不确切了解站点上安装了什么以及如何配置的情况下会产生什么效果
Clive

1
views_bulk_operations有什么问题?
donquixote

1
嘿,这些答案都还没有投票:/
tenken 2014年

Answers:


7

我最近使用以下方法做了类似的事情。

  1. 添加新的允许值。
  2. 添加设置以配置“活动”值。
  3. 从表单上的显示中过滤掉“无效”值。

例如:

/**
 * Admin settings form
 */
function MODULE_admin_settings(){

  $form = array();

  // Select active preferences for display
  $field = field_info_field('field_preferences');
  $preferences = list_allowed_values($field);
  $form['field_preferences_active'] = array(
    '#type' => 'checkboxes',
    '#title' => t('Active preferences'),
    '#options' => $preferences,
    '#description' => t('Select the preferences available for user selection.'),
    '#default_value' => variable_get('field_preferences_active', array()),
  );

  return system_settings_form($form);

}

/**
 * Implements hook_field_attach_form
 */
function MODULE_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) {

  // Filter out inactive preferences
  if(isset($form['field_preferences'])){
    $preferences = variable_get('field_preferences_active', array());
    foreach($preferences as $key => $preference){
      // If this preference isn't checked, but is set in the field values, unset it.
      if(empty($preference) && isset($form['field_preferences'][LANGUAGE_NONE]['#options'][$key])){
        unset($form['field_preferences'][LANGUAGE_NONE]['#options'][$key]);
      }
    }
  }

}

这样,将保留旧数据以供参考,验证表单并完整保留数据完整性。


1
该选项本质上是非描述性的(即,隐藏内容而不是删除),并且可能是最佳起点,直到您可以确定如何处理具有过时选项的任何实体的最佳方法为止。
mpdonadio

3

据我所知,所有字段数据都存储在2个表中:field_data_field_FIELDNAME和field_revision_field_FIELDNAME。我在这里找到了我的想法的确认:https : //stackoverflow.com/a/7773117/1300562

因此,要删除不必要的字段值,您需要从上述表格中删除这些值,然后从允许值列表中删除它们。

步骤1。

$values_to_remove = array('value1', 'value2'); // an array of unnecessary values
$fieldname = 'FIELDNAME'; // name of your field. For example,
                          // 'territory' for field with machine name 'field_territory'
$entity_type = 'node'; // it's 'node' in your case, but it can be 'taxonomy_term' or something else

db_delete('field_data_field_' . $fieldname)
  ->condition('entity_type', $entity_type)
  ->condition('field_' . $fieldname . '_value', $values_to_remove)
  ->execute();

db_delete('field_revision_field_' . $fieldname)
  ->condition('entity_type', $entity_type)
  ->condition('field_' . $fieldname . '_value', $values_to_remove)
  ->execute();

步骤2.
在字段设置页面上删除不必要的键对对,然后提交表单以保存更改。
此后应自动清除缓存,但是如果您仍然可以在节点页面上看到已删除的字段值,请手动清除缓存。

PS最近,我遇到了类似的问题,现在我更喜欢使用“术语引用”或(甚至更好)“实体引用”类型的字段来代替文本值列表。使用参考字段时,您可以为每个字段创建单独的词汇表,并且可以随时创建/编辑/删除术语。


如果该字段重复,则这些查询将不会调整剩余数据的增量。
mpdonadio

1

首先检查是否在字段中指定了任何允许的值?如果这样做,则其他选项将不会被验证。因此,请尝试首先从“字段设置”选项卡中删除值。

另外,您有2个选项:


1。

删除您在允许值列表中放入的所有由用户帐户使用的值。例如,您可以运行SQL查询来查找以下内容:

SELECT * FROM field_data_field_MYFIELDNAME WHERE entity_type = 'user' and value = 'MY VALUE'

或创建一个用户视图,向您显示哪些用户帐户具有要从允许值列表中删除的值。


2。

如果您不想从字段中删除值,可以通过hack来实现。

警告,这不是建议的生产解决方案,您应该知道自己在做什么!

  1. 查找和编辑模块/field/field.module
  2. 找到field_has_data()函数,然后return TRUE;在函数的第一行中添加。

    function field_has_data($field) {
      return FALSE; // HACK !!!
      $query = new EntityFieldQuery();
  3. 用所需的值重新保存该字段。
  4. 完成后请立即删除该hack。

0

我认为您实际上可以通过使用“ 视图批量操作”模块来完成此操作

  1. 在您要替换的字段上添加新选项。例如:na | NA
  2. 创建一个包含该字段的“查看列表”节点
  3. 在该视图上添加“批量操作:内容”字段
  4. 选中“修改实体值”和“显示可用令牌”(在显示值上选择全部)
  5. 添加要在“过滤条件”上更改的字段,然后“公开”该过滤条件
  6. 在该视图上设置url路径
  7. 转到该视图页面并进行更改
  8. 现在,使用暴露和操作功能更改字段选项
  9. 完成

0

我认为这是最好的HL答案的改进:

总结起来,您需要为具有为选择字段分配的“旧”值的内容分配新值。

除了Views Bulk Operations,您还需要安装并启用Administration Views模块。使用此模块,您已经具有启用了批量操作的开箱即用视图(启用后只需查看admin / content)。然后:

1)转到admin / structure / views,然后编辑“ Administration:Node”视图

2)使用顶部的“添加->页面”按钮为视图添加新页面显示

3)分配新显示的路径:示例admin / content / custom

4)为选择字段添加新的过滤器:选择运算符“是其中之一”,然后选择要删除的所有选项

5)保存视图

6)转到admin / content / custom现在,您将看到需要批量编辑的所有内容(更改选择字段的值)

7)通过单击表格左侧的第一个复选框来选择所有行(如果有多个页面,还选择一个按钮,显示“选择此视图中的所有X行”)

8)选择操作“更改值”,然后按“执行”

9)对于您的选择字段,选择一个新值以覆盖您要删除的值

10)选中该选择字段的复选框

11)单击下一步,完成


0

听起来您的Drupal问题是基于更深层的数据问题:当前正在使用折旧列表值的实体会发生什么?这个问题是Drupal发送给您的错误消息的根源。

让我们仔细看看您的州/领地示例。多年来,您的客户一直在使用一种以相同方式处理州和领地的系统,并且已经建立了包含州和领地的庞大节点组。然后有一天,决定区域需要以不同方式处理以及用于分配区域的下拉列表中不应再包含区域的决定权。大。只需创建一个使用标准过滤器的视图即可呈现所有区域节点的列表,然后使用“视图批量操作”将其所有区域值更改为...什么...可能称为第51个状态的其他状态?领土的命运是一个非常严重的问题。您的解决方案必须包括一种用于保留或重定位地区状态的方法。您可能需要创建一个名为“ Territory”的新列表字段

您需要将“规则”与“ 查看批量操作结合使用才能执行这些更改。如果您对规则了解不多,请花一些时间来了解它们的工作原理。规则使您能够根据触发器,条件和操作来操纵信息。学习了规则之后,您可能会发现所寻找的答案会直观地呈现出来。基本上,您将需要创建一个由批量操作触发的规则,该规则将以所有区域为目标,并将其从信息主体中移除,重新分配,重命名或以其他方式分离。该规则必须能够以某种方式存储区域状态,同时将状态下拉菜单设置为“其他”或“不适用”状态。这可能就是所需要的。除此以外...

重新分配完成后,更改原始列表字段并删除地区名称应该是一个简单的操作。但是,如果系统仍然不允许您更改列表,则可能需要创建一个新的列表字段,然后使用“查看批量操作和规则”来查看所有当前状态值,并将它们重新分配给新列表。规则可以与Views Bulk Operations一起使用,以所有相关节点为目标,并根据字段值对它们进行操作。使用“规则”时,基于一组节点的现有列表字段的值设置新列表字段的值很容易。

还要记住,如果Drupal在操作上给您带来麻烦,请在考虑困难的替代方案之前始终刷新缓存。


0

我假设您的客户希望遗留内容保持其原始值,这意味着更改选择列表将有效地破坏以前的任何数据。如果这不是一个问题,那么其他任何答案都可能会起作用。如果是这样,您必须在不丢失数据历史记录的情况下真正更改选择列表。我可能会走一条简单得多的路线,以便保留历史数据,同时使该站点更具前瞻性-我建议使用字段权限:

*使用分类法而不是静态数据为该选择列表设置新字段

*将现有选择列表的字段权限设置为VIEW,但除admin以外的任何人都不能编辑

这样,旧字段应保持可见和可搜索(添加一个新标题,将其仅反映为旧标题),但不可编辑。当然,这很大程度上取决于可能需要调整的自定义搜索,视图等。

我建议这样做(听起来可能很混乱),因为删除该数据,删除历史记录,从长远来看可能最终会造成毁灭性的后果。您甚至可以使用css在编辑节点中隐藏旧字段,并使用钩子将其隐藏以显示新内容(未设置值)。这样,它将仅针对该旧内容显示。

当然,您可以使用自定义的一次性模块将数据从旧的选择列表复制到新的分类法,从而更进一步。


0

一个简单的草稿脚本即可解救!我们会更新字段数据和字段修订表,并在手动更改字段设置之前用新值替换旧值。

如果我们在当前字段设置中有类似这样的内容:

&date=today|today
&date=last2days|last2days

并希望将其替换为以下内容:

date=today|today
date=last2days|last2days

我们首先运行drush脚本,然后在管理界面中更改字段设置。

注意:该代码用于机器名称为的字段field_foo_bar

    $field_name = 'foo_bar';

    print "for {$field_name}...\n";

    replace_field("&date=today", "date=today", $field_name);

    replace_field("&date=last2days", "date=last2days", $field_name);

    function replace_field($old_value, $new_value, $field_name, $entity_type='node') {
      print "Replacing {$old_value} with {$new_value}...\n";
      $data_count = replace_options_data_field($field_name, $entity_type, $old_value, $new_value);
      $revision_count = replace_options_revision_field($field_name, $entity_type, $old_value, $new_value);
      print $data_count + $revision_count . " entries replaced.\n";
    }

    function replace_options_data_field($field_name, $entity_type, $old_value, $new_value) {
      $num_updated = db_update('field_data_field_' . $field_name)
        ->fields(array(
                   'field_' . $field_name . '_value' => $new_value,
                 ))
        ->condition('entity_type', $entity_type)
        ->condition('field_' . $field_name . '_value', $old_value)
        ->execute();
      return $num_updated;
    }

function replace_options_revision_field($field_name, $entity_type, $old_value, $new_value) {
  $num_updated = db_update('field_revision_field_' . $field_name)
    ->fields(array(
               'field_' . $field_name . '_value' => $new_value,
             ))
    ->condition('entity_type', $entity_type)
    ->condition('field_' . $field_name . '_value', $old_value)
    ->execute();
  return $num_updated;
}

0

我使用kenorb的第二个建议,它可以更新Drupal 7.52,Profile2 7.x-1.3字段中的值列表。因此,如果您收到了drupal警告:“允许的值列表:当前正在使用中,某些值正在被删除。”以下内容使我可以从(profile2)字段中删除值,而无需在数据库中删除或替换它们。

在Drupal核心的根目录中,有一个名为modules的文件夹,要编辑的文件位于:modules / field / field.module。这是一个核心文件,完成值更新后,您必须绝对还原所做的更改。我使站点脱机,暂时将以下代码块替换为(双根)/modules/field/field.module

function field_has_data($field) {
  $query = new EntityFieldQuery();
  $query = $query->fieldCondition($field)
    ->range(0, 1)
    ->count()
    // Neutralize the 'entity_field_access' query tag added by
    // field_sql_storage_field_storage_query(). The result cannot depend on the
    // access grants of the current user.
    ->addTag('DANGEROUS_ACCESS_CHECK_OPT_OUT');

  return (bool) $query
    ->execute() || (bool) $query
    ->age(FIELD_LOAD_REVISION)
    ->execute();
}

准确地

function field_has_data($field) { 
    return FALSE; // hack 
    $query = new EntityFieldQuery();
}

Drupal不再抱怨了,我得以更改列表。(在我的情况下,这是已经离开大学但仍与学生记录相关的价值观列表中的教职员工,例如其顾问,导师等)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.