代码之家  ›  专栏  ›  技术社区  ›  vishes_shell hendrixski

django.db.models.fields.field.name参数的用途

  •  5
  • vishes_shell hendrixski  · 技术社区  · 6 年前

    最近我发现 not-documented django.db.models.fields.Field.name 选项:

    @total_ordering
    class Field(RegisterLookupMixin):  #   here we have it
        ...                                   ↓↓↓↓↓↓↓↓↓
        def __init__(self, verbose_name=None, name=None, primary_key=False,
                     max_length=None, unique=False, blank=False, null=False,
                     db_index=False, rel=None, default=NOT_PROVIDED, editable=True,
                     serialize=True, unique_for_date=None, unique_for_month=None,
                     unique_for_year=None, choices=None, help_text='', db_column=None,
                     db_tablespace=None, auto_created=False, validators=(),
                     error_messages=None):
            ...
    

    mention 文件方式:

    # A guide to Field parameters:
    #
    #   * name:      The name of the field specified in the model.
    #   * attname:   The attribute to use on the model object. This is the same as
    #                "name", except in the case of ForeignKeys, where "_id" is
    #                appended.
    #   * db_column: The db_column specified in the model (or None).
    #   * column:    The database column for this field. This is the same as
    #                "attname", except if db_column is specified.
    #
    # Code that introspects values, or does other dynamic things, should use
    # attname. For example, this gets the primary key value of object "obj":
    #
    #     getattr(obj, opts.pk.attname)
    

    以上描述与 #683 ([patch] Saving with custom db_column fails) 票。

    所以如果我们从整体上看 django.db.models.fields.Field 班级,这似乎 name 选项正在设置属性名,这使变量的实名无效:

    假设我们有我们的模型:

    # models.py
    from django.db import models
    
    
    class SomeModel(models.Model):
        first = models.CharField(max_length=50, verbose_name='first', name='second')
        third = models.CharField(max_length=50, verbose_name='third')
    

    什么 django-admin shell 告诉我们:

    In[2]: from app.models import SomeModel
    In[3]: SomeModel.objects.create(first='first', third='third')
    Traceback (most recent call last):
      File "/Users/ailove/Home/personal/untitled/venv/lib/python3.6/site-packages/IPython/core/interactiveshell.py", line 2963, in run_code
        exec(code_obj, self.user_global_ns, self.user_ns)
      File "<ipython-input-3-08e446dfd6e3>", line 1, in <module>
        SomeModel.objects.create(first='first', third='third')
      File "/Users/ailove/Home/personal/untitled/venv/lib/python3.6/site-packages/django/db/models/manager.py", line 82, in manager_method
        return getattr(self.get_queryset(), name)(*args, **kwargs)
      File "/Users/ailove/Home/personal/untitled/venv/lib/python3.6/site-packages/django/db/models/query.py", line 415, in create
        obj = self.model(**kwargs)
      File "/Users/ailove/Home/personal/untitled/venv/lib/python3.6/site-packages/django/db/models/base.py", line 495, in __init__
        raise TypeError("'%s' is an invalid keyword argument for this function" % kwarg)
    TypeError: 'first' is an invalid keyword argument for this function
    In[4]: obj = SomeModel.objects.create(second='second', third='third')
    In[5] obj.third
    Out[5]: 'third'
    In[6]: obj.second
    Out[6]: 'second'
    In[7]: obj.first
    Traceback (most recent call last):
      File "/Users/ailove/Home/personal/untitled/venv/lib/python3.6/site-packages/IPython/core/interactiveshell.py", line 2963, in run_code
        exec(code_obj, self.user_global_ns, self.user_ns)
      File "<ipython-input-7-f0deaec10795>", line 1, in <module>
        obj.first
    AttributeError: 'SomeModel' object has no attribute 'first'
    

    问题有点宽泛,但我也很好奇。

    这是 名称 选择权只是一种有助于发展的东西。 django 或者普通的开发者也可以利用它?如果可以,为什么?

    2 回复  |  直到 6 年前
        1
  •  6
  •   Louis    6 年前

    我找到了 name 如果我想要一个模型的字段有一个getter和setter, 隐藏getter/setter从django orm和数据库中引入的命名约定 .

    在Python中,一个相当常见的模式是让getter和setter以字段的公共名称命名,并让保存字段值的字段以下划线开头,该下划线 by convention 表示它是私有的。例如,你会有一个名为setter和getter的 foo 它的“private”字段命名为 _foo :

    class Something(object):
        _foo = "some default value"
    
        @property
        def foo(self):
            return self._foo
    
        @foo.setter
        def foo(self, val):
            self._foo = val
    

    上面的代码是赤裸裸的。可能,在现实场景中,getter或setter中会有额外的代码来做一些额外的工作。(否则,没有理由使用getter和setter。)假设上述类的一个实例 instance ,您访问 instance.foo 而且你不碰 instance._foo 因为 福禄 字段不是公共API的一部分。

    如果您想采用上面的模式并在Django模型上实现它,您可以 能够 只要这样做:

    class MyModel(models.Model):
        _foo = models.TextField()
    
        @property
        def foo(self):
            return self._foo
    
        @foo.setter
        def foo(self, val):
            self._foo = val
    

    但是,最终结果是,Django ORM知道您的字段为 福禄 它存储在一个名为 福禄 在数据库中。有些人会同意这一点,但在我的项目中,我更喜欢Python中getter/setter的存在不会影响其他字段的名称。为了在django orm中具有相同的名称和列名称,可以执行以下操作:

    _foo = models.TextField(name="foo")
    

    这样做将设置字段的名称,如Django ORM中所示,这样可以:

    MyModels.objects.get(foo=...)
    

    否则,您必须使用下划线 MyModels.objects.get(_foo=...) . 它还设置了数据库列的名称,因此在原始SQL中,您可以将该列作为 . 如果您碰巧需要不同的列名,则必须使用 db_column 用于设置名称的参数: models.TextField(name="foo", db_column="something_else")

        2
  •  0
  •   vishes_shell hendrixski    6 年前

    另一个示例在您希望从 keyword.kwlist ,例如

    class Emails(models.Model):
        from_ = models.CharField(name='from', ...)  # workaround to have `.from` field
        to = models.CharField(...)
        content = models.TextField(...)
    

    因为最初它会 禁止将名称为的字段设置为 from 例外: SyntaxError: invalid syntax