最近我发现有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'
问题有点广泛,但我也很好奇。
此name
选项是否仅有助于开发django
,还是普通开发人员也可以使用它?如果可以的话,那是为了什么?
答案 0 :(得分:6)
我发现name
很有用,如果我希望模型的字段具有getter和setter并隐藏Django ORM和数据库中的getter / setter引入的命名约定 。
Python中一个非常常见的模式是让getter和setter以该字段的公共名称命名,并让包含该字段值的字段以下划线开头,by convention表示该字段是私人的。因此,例如,您将有一个名为foo
的setter和getter以及一个名为_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
,因为{{1} }字段不属于公共API。
如果您想采用上述模式并在Django模型上实现,您可以 做到这一点:
_foo
但是,最终结果是Django ORM将您的字段称为class MyModel(models.Model):
_foo = models.TextField()
@property
def foo(self):
return self._foo
@foo.setter
def foo(self, val):
self._foo = val
,并将其存储在数据库中名为_foo
的列中。有人会对此表示满意,但是在我的项目中,我更喜欢Python中的getter / setter方法不会影响其他字段的名称。为了在Django ORM中具有相同的名称,并为列名称提供相同的名称,您可以执行以下操作:
_foo
这样做将设置字段名称,如Django ORM所示,因此可以正常工作:
_foo = models.TextField(name="foo")
否则,您必须使用下划线并执行MyModels.objects.get(foo=...)
。而且它还会设置数据库列的名称,因此在原始SQL中,您将以MyModels.objects.get(_foo=...)
的形式访问该列。如果碰巧想要一个不同的列名,则必须使用foo
参数来设置名称:db_column
答案 1 :(得分:0)
如果您想使用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