database - Django 自定义字段的属性进行数据库查询

标签 database django custom-fields

我在我的一个 Django 项目中遇到了一个非常奇怪的问题。在我的项目中,我有一个自定义字段类来处理外键、一对一和许多 2 许多模型字段。该类类似于以下内容。

from django import forms


class CustomRelatedField(forms.Field):
     def __init__(self, model, limit=None, multiple=False, create_objects=True, *args, *kwargs):
         self.model = model
         self.limit = limit
         self.multiple = multiple
         self.create_objects = create_objects

         super(CustomRelatedField, self).__init__(*args, **kwargs)

    def clean(self, value):
        """ Calls self.get_objects to get the actual model object instance(s)
            from the given unicode value.
        """
        # Do some value processing here
        return self.get_objects(value)

    def get_objects(self, values):
        """ Returns the model object instances for the given unicode values.
        """

        results = []
        for value in values:
            try:
                obj = self.model.object.get_or_create(name=value)[0]
                results.append(obj)
            except Exception, err:
                # Log the error here.

        return results

    def prepare_value(self, value):
        """ Returns the value to be sent to the UI. The value
            passed to this method is generally the object id or
            a list of object id's (in case it is a many to many object).
            So we need to make a database query to get the object and
            then return the name attribute.
        """

       if self.multiple:
           result  = [obj.name for obj in self.model.filter(pk__in=value)]
       else:
           result = self.model.object.get(pk=value)

       return result

最近我在玩 django-toolbar ,我发现其中一个包含上述字段的表单的页面荒谬地一次又一次地对相同的对象进行多次查询。

enter image description here

在调试时,我发现 prepare_value 方法被反复调用。经过更多调试后,我意识到罪魁祸首是模板。我有一个用于表单的通用模板,它看起来类似于以下内容:

{% for field in form %}
   {% if field.is_hidden %}
      <!-- Do something here -->
   {% endif %}

   {% if field.field.required %}
      <!-- Do something here -->
   {% endif %}

   <label>{{ field.label }}</label>
   <div class="form-field">{{ field }}</div>

   {% if field.field.widget.attrs.help_text %}
      <!-- Do something here -->
   {% elif field.errors %}
      <!-- Do something here -->
   {% endif %}
{% endfor %}

在上面的代码中,每个if 语句调用字段类,该字段类调用prepare_value 方法,然后进行数据库查询。下面列出的每一个都在进行数据库查询,我完全不知道为什么会这样,也不知道任何解决方案。任何帮助,建议将不胜感激。谢谢。

  • field.is_hidden
  • field.field.required
  • 字段标签
  • field.label_tag
  • 领域
  • field.field.widget.attrs.help_text
  • 字段错误

另外,为什么只有我的自定义字段类会发生这种情况,应用程序中的其他字段(FKs、O2Os、M2M's)和应用程序管理员只需进行一次查询,即使它们使用的是类似的模板。

最佳答案

问题出在执行显式查询的 prepare_value() 方法上。 .get() 不会被缓存,并且在 .filter() 查询集上迭代时总是命中数据库将对其进行评估。 这可能会导致您多次查询。

这在默认字段中是看不到的,因为它们不在 prepare_value() 中进行任何查询。

要解决这个问题,您可以尝试缓存valueresult。如果 value 没有改变,返回缓存的结果。像这样的东西:

class CustomRelatedField(forms.Field):
    def __init__(self, model, limit=None, multiple=False, create_objects=True, *args, *kwargs):
       self.cached_result = None
       self.cached_value = None
    ...
    def prepare_value(self, value):
       #check we have cached result
       if value == self.cached_value:
           return self.cached_result

       if self.multiple:
           result  = [obj.name for obj in self.model.filter(pk__in=value)]
       else:
           result = self.model.object.get(pk=value)

       #cache the result and value
       self.cached_result = result
       self.cached_value = value    
       return result

虽然不确定这个解决方案有多好/多坏!

关于database - Django 自定义字段的属性进行数据库查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20279674/

相关文章:

mysql - 如何在mysql运行时插入数据

php - 使 Woocommerce (3.8.0) 管理电子邮件包含结账页面中的我的自定义字段数据

mysql - SQL 中的 Group By 和having 出现问题

php - 在 Laravel 中咨询多对多关系

django - 如何判断 Django 查询集中哪些字段已被延迟/仅被延迟

python - 有没有办法让 Django-registration-redux 与 `@login_required` 一起工作?

django - 将表达式与 CHECK 约束中的常量进行比较

php - 如何使用之前输入的值填充自定义结帐字段,例如默认的 WooCommerce 结帐字段?

mysql - 获取受帖子类别限制的自定义字段值列表

database - 记录两次插入数据库