Recently i discovered that there is not-documented django.db.models.fields.Field.name
option:
@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): ...
There is mention of it in doc-way:
# 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)
Description above is related with #683 ([patch] Saving with custom db_column fails) ticket.
So if we look through whole django.db.models.fields.Field
class, this seems as name
option is setting attribute name, which make real name of variable invalid:
Suppose we have our model:
# 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')
What django-admin shell
tells us:
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'
Question is kinda broad, but i am also curious.
Is this name
option is a thing that only helped to develop django
, or ordinary developers can also make use of it? And if we can, what for?
Django uses field class types to determine a few things: The column type, which tells the database what kind of data to store (e.g. INTEGER, VARCHAR, TEXT). The default HTML widget to use when rendering a form field (e.g. <input type=”text”>, <select>).
How to use required in Django Form field? required is often used to make the field optional that is the user would no longer be required to enter the data into that field and it will still be accepted.
The related_name attribute specifies the name of the reverse relation from the User model back to your model. If you don't specify a related_name, Django automatically creates one using the name of your model with the suffix _set.
str function in a django model returns a string that is exactly rendered as the display name of instances for that model. # Create your models here. This will display the objects as something always in the admin interface.
I've found name
useful if I want a model's field to have a getter and setter and hide the naming convention introduced by the getter/setter from the Django ORM and the database.
A fairly common pattern in Python is to have the getter and setter be named after the public name of the field, and have the field that holds the value of the field start with an underscore which by convention indicates that it is private. So for instance you'd have a setter and getter named foo
and the "private" field for it named _foo
:
class Something(object):
_foo = "some default value"
@property
def foo(self):
return self._foo
@foo.setter
def foo(self, val):
self._foo = val
The code above is barebones. Presumably, in a real-world scenario you'd have additional code in your getter or setter to do some additional work. (Otherwise, there's no reason for the getter and setter.) Assuming an instance of the class above named instance
, you access instance.foo
and you do not touch instance._foo
because the _foo
field is not part of the public API.
If you want to take the pattern above and implement it on a Django model you could just do this:
class MyModel(models.Model):
_foo = models.TextField()
@property
def foo(self):
return self._foo
@foo.setter
def foo(self, val):
self._foo = val
However, the net result is that your field is known to the Django ORM as _foo
and it is stored in a column named _foo
in the database. Some people will be okay with this, but in my projects I prefer that the existence of the getter/setter in Python not affect the name of the field elsewhere. In order to have the same name in the Django ORM and for the column name, you can do:
_foo = models.TextField(name="foo")
Doing this will set the name of the field as seen in the Django ORM, so this works:
MyModels.objects.get(foo=...)
Otherwise, you'd have to use the underscore and do MyModels.objects.get(_foo=...)
. And it also sets the name of the database column so in raw SQL you'd access the column as foo
. If you happen to want a different column name, you have to use the db_column
argument to set the name: models.TextField(name="foo", db_column="something_else")
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With