字段类型和参数

阅读: 118057     评论:36

一、字段fields

字段是模型中最重要的内容之一,也是唯一必须创建的部分。字段在Python中表现为一个类属性,体现了数据表中的一个列。请不要使用cleansavedelete等Django内置的模型API名字,防止命名冲突。下面是一个展示,注意字段的写法:

from django.db import models

class Musician(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    instrument = models.CharField(max_length=100)

class Album(models.Model):
    artist = models.ForeignKey(Musician, on_delete=models.CASCADE)
    name = models.CharField(max_length=100)
    release_date = models.DateField()
    num_stars = models.IntegerField()

字段命名约束:

Django不允许下面三种字段名:

  • 与Python关键字冲突。这会导致语法错误。例如:
class Example(models.Model):
    pass = models.IntegerField() # 'pass'是Python保留字! 
  • 字段名中不能有两个以上下划线在一起,因为两个下划线是Django的查询语法。例如:
class Example(models.Model):
    foo__bar = models.IntegerField() # 'foo__bar' 有两个下划线在一起!
  • 字段名不能以下划线结尾,原因同上。

由于你可以自定义表名、列名,上面的规则可能被绕开,但是请养成良好的习惯,一定不要那么起名。

SQL保留字,例如 joinwhereselect 可以被用在模型字段名当中的,因为 Django 在对底层的 SQL 查询当中清洗了所有的数据库表名和字段名,通过使用特定数据库引擎的引用语法。但是仍然不建议这么起名。

二、字段的类型

模型中的每一个字段都应该是某个 Field 类的实例,字段类型具有下面的作用:

  • 决定数据表中对应列的数据类型(例如:INTEGER, VARCHAR, TEXT)
  • HTML中对应的表单标签的类型,例如<input type=“text” />
  • 在admin后台和自动生成的表单中进行数据验证

Django内置了许多字段类型,它们都位于django.db.models中,例如models.CharField,它们的父类都是Field类。这些类型基本满足需求,如果还不够,你也可以自定义字段。

下表列出了所有Django内置的字段类型,但不包括关系字段类型(字段类型名采用驼峰命名法,初学者请一定要注意),加粗显示的是常用字段类型:

类型 说明
AutoField 一个自动增加的整数类型字段。通常你不需要自己编写它,Django会自动帮你添加字段:id = models.AutoField(primary_key=True),这是一个自增字段,从1开始计数。如果你非要自己设置主键,那么请务必将字段设置为primary_key=True。Django在一个模型中只允许有一个自增字段,并且该字段必须为主键!
BigAutoField 64位整数类型自增字段,数字范围更大,从1到9223372036854775807
BigIntegerField 64位整数字段(看清楚,非自增),类似IntegerField ,-9223372036854775808 到9223372036854775807。在Django的模板表单里体现为一个NumberInput标签。
BinaryField 二进制数据类型。较少使用。
BooleanField 布尔值类型,值为true或者false。在HTML表单中体现为CheckboxInput标签。如果设置了参数null=True,则表现为NullBooleanSelect选择框。如果没有提供default参数值,则默认值是None。
CharField 最常用的类型,字符串类型。必须接收一个max_length参数,表示字符串长度不能超过该值。默认的表单标签是text input。
DateField class DateField(auto_now=False, auto_now_add=False, **options) , 日期类型。一个Python中的datetime.date的实例。在HTML中表现为DateInput标签。在admin后台中,Django会帮你自动添加一个JS日历表和一个“Today”快捷方式,以及附加的日期合法性验证。有两个重要参数:(它们和 default 参数三者互斥,不能共存) auto_now:每当对象被保存时将字段设为当前日期,常用于保存最后修改时间。auto_now_add:每当对象被创建时,设为当前日期,常用于保存创建日期(注意,它是不可修改的)。设置上面两个参数就相当于给field添加了editable=Falseblank=True属性。如果想具有修改属性,请用default参数。例子:pub_time = models.DateField(auto_now_add=True),自动添加发布时间。
DateTimeField 日期时间类型。Python的datetime.datetime的实例。与DateField相比就是多了小时、分和秒的显示,其它功能、参数、用法、默认值等等都一样。
DecimalField 固定精度的十进制小数。相当于Python的Decimal实例,必须提供两个指定的参数!参数max_digits:最大的位数,必须大于或等于小数点位数 。decimal_places:小数点位数,精度。 当localize=False时,它在HTML表现为NumberInput标签,否则是textInput类型。例子:储存最大不超过999,带有2位小数位精度的数,定义如下:models.DecimalField(..., max_digits=5, decimal_places=2)
DurationField 持续时间类型。存储一定期间的时间长度。类似Python中的timedelta。在不同的数据库实现中有不同的表示方法。常用于进行时间之间的加减运算。但是小心了,这里有坑,PostgreSQL等数据库之间有兼容性问题!
EmailField 邮箱类型,默认max_length最大长度254位。使用这个字段的好处是,可以使用Django内置的EmailValidator进行邮箱格式合法性验证。
FileField class FileField(upload_to=None, max_length=100, **options)上传文件类型,后面单独介绍。
FilePathField 文件路径类型,后面单独介绍
FloatField 浮点数类型,对应Python的float。参考整数类型字段。
ImageField 图像类型,后面单独介绍。
IntegerField 整数类型,最常用的字段之一。取值范围-2147483648到2147483647。在HTML中表现为NumberInput或者TextInput标签。
GenericIPAddressField class GenericIPAddressField(protocol='both', unpack_ipv4=False, **options),IPV4或者IPV6地址,字符串形式,例如192.0.2.30或者2a02:42fe::4。在HTML中表现为TextInput标签。参数protocol默认值为‘both’,可选‘IPv4’或者‘IPv6’,表示你的IP地址类型。
JSONField JSON类型字段。签名为class JSONField(encoder=None,decoder=None,**options)。其中的encoder和decoder为可选的编码器和解码器,用于自定义编码和解码方式。如果为该字段提供default值,请务必保证该值是个不可变的对象,比如字符串对象。
PositiveBigIntegerField 正的大整数,0到9223372036854775807
PositiveIntegerField 正整数,从0到2147483647
PositiveSmallIntegerField 较小的正整数,从0到32767
SlugField slug是一个新闻行业的术语。一个slug就是一个某种东西的简短标签,包含字母、数字、下划线或者连接线,通常用于URLs中。可以设置max_length参数,默认为50。
SmallAutoField 类似AutoField,但是只允许1到32767。
SmallIntegerField 小整数,包含-32768到32767。
TextField 用于储存大量的文本内容,在HTML中表现为Textarea标签,最常用的字段类型之一!如果你为它设置一个max_length参数,那么在前端页面中会受到输入字符数量限制,然而在模型和数据库层面却不受影响。只有CharField才能同时作用于两者。
TimeField 时间字段,Python中datetime.time的实例。接收同DateField一样的参数,只作用于小时、分和秒。
URLField 用于保存URL地址的字符串类型,默认最大长度200,可指定max_length。
UUIDField 用于保存通用唯一识别码(Universally Unique Identifier)的字段。使用Python的UUID类。这个字段是自增主键的最佳替代品,后面有例子展示。

1.FileField

class FileField(upload_to=None, storage=None, max_length=100, **options)

上传文件字段(不能设置为主键)。

默认情况下,该字段在HTML中表现为一个ClearableFileInput标签。在数据库内,我们实际保存的是一个字符串类型,默认最大长度100,可以通过max_length参数自定义。这个字符串指向真实的文件地址。

真实的文件是以文件的形式保存在操作系统的存储系统内的。

重要参数upload_to用于设置上传地址的目录和文件名。如下例所示:

class MyModel(models.Model):
    # 文件被传至`MEDIA_ROOT/uploads`目录,MEDIA_ROOT由你在settings文件中设置
    upload = models.FileField(upload_to='uploads/')
    # 或者
    # 被传到`MEDIA_ROOT/uploads/2015/01/30`目录,增加了一个时间划分
    upload = models.FileField(upload_to='uploads/%Y/%m/%d/')

Django很人性化地帮我们实现了根据日期生成目录或文件的方式!

upload_to参数也可以接收一个回调函数,该函数返回具体的路径字符串,如下例:

def user_directory_path(instance, filename):
    #文件上传到MEDIA_ROOT/user_<id>/<filename>目录中
    return 'user_{0}/{1}'.format(instance.user.id, filename)

class MyModel(models.Model):
    upload = models.FileField(upload_to=user_directory_path)

例子中,user_directory_path这种回调函数,必须接收两个参数,然后返回一个Unix风格的路径字符串。参数instace代表模型的实例,说白了就是当前数据记录。filename是原本的文件名。

从Django3.0开始,支持使用pathlib.Path 处理路径。

storage参数是一个存储对象,或是一个返回存储对象的可调用对象。它处理文件的存储和检索。

当你访问一个模型对象中的文件字段时,Django会自动给我们返回一个 FieldFile实例作为文件的代理,通过这个代理,我们可以进行对文件进行一些操作,主要如下:

  • FieldFile.name : 获取文件名
  • FieldFile.size: 获取文件大小
  • FieldFile.url :用于访问该文件的url
  • FieldFile.open(mode='rb'): 以类似Python文件操作的方式,打开文件
  • FieldFile.close(): 关闭文件
  • FieldFile.save(name, content, save=True): 保存文件
  • FieldFile.delete(save=True): 删除文件

这些代理的API和Python原生的文件读写API非常类似,其实本质上就是进行了一层封装,让我们可以在Django内直接对模型中文件字段进行读写,而不需要绕弯子。

2. ImageField

class ImageField(upload_to=None, height_field=None, width_field=None, max_length=100, **options)

用于保存图像文件的字段。

该字段继承了FileField,但是额外增加了验证上传的对象是有效的图像的过程。

其用法和特性与FileField基本一样,只是多了height和width两个属性。

默认情况下,该字段在HTML中表现为一个ClearableFileInput标签。

在数据库内,我们实际保存的是一个字符串类型,默认最大长度100,可以通过max_length参数自定义。真实的图片是保存在服务器的文件系统内的。

height_field参数:保存有图片高度信息的模型字段名。 width_field参数:保存有图片宽度信息的模型字段名。

使用Django的ImageField需要提前安装pillow模块,pip install pillow即可。

3. 使用FileField或者ImageField字段的步骤

  1. 在settings文件中,配置MEDIA_ROOT,作为你上传文件在服务器中的基本路径(为了性能考虑,这些文件不会被储存在数据库中)。再配置个MEDIA_URL,作为公用URL,指向上传文件的基本路径。请确保Web服务器的用户账号对该目录具有写的权限。

MEDIA_ROOT = BASE_DIR / 'media/' MEDIA_URL = '/media/'

  1. 添加FileField或者ImageField字段到你的模型中,定义好upload_to参数,文件最终会放在MEDIA_ROOT目录的“upload_to”子目录中。

  2. 所有被保存在数据库中的,只是指向你上传文件路径的字符串而已。可以通过url属性,在Django的模板中方便的访问这些文件。例如,假设你有一个ImageField字段,名叫mug_shot,那么在Django模板的HTML文件中,可以使用{{ object.mug_shot.url }}来获取该文件。其中的object用你具体的对象名称代替。

  3. 可以通过namesize属性,获取文件的名称和大小信息。

  4. 添加URLconf:

``` from django.contrib import admin from django.urls import path, include from django.conf.urls.static import static from django.conf import settings

urlpatterns = [ path('admin/', admin.site.urls), path('polls/', include('polls.urls')), path('uploads/', include('uploads.urls')), ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) ```

安全建议:

无论你如何保存上传的文件,一定要注意他们的内容和格式,避免安全漏洞!务必对所有的上传文件进行安全检查,确保它们不出问题!如果你不加任何检查就盲目的让任何人上传文件到你的服务器文档根目录内,比如上传了一个CGI或者PHP脚本,很可能就会被访问的用户执行,这具有致命的危害。

4. FilePathField

class FilePathField(path='', match=None, recursive=False, allow_files=True, allow_folders=False, max_length=100, **options)

一种用来保存文件路径信息的字段。在数据表内以字符串的形式存在,默认最大长度100,可以通过max_length参数设置。

它包含有下面的一些参数:

path:必须指定的参数。表示一个系统绝对路径。path通常是个字符串,也可以是个可调用对象,比如函数。

match:可选参数,一个正则表达式,用于过滤文件名。只匹配基本文件名,不匹配路径。例如foo.*\.txt$,只匹配文件名foo23.txt,不匹配bar.txtfoo23.png

recursive:可选参数,只能是True或者False。默认为False。决定是否包含子目录,也就是是否递归的意思。

allow_files:可选参数,只能是True或者False。默认为True。决定是否应该将文件名包括在内。它和allow_folders其中,必须有一个为True。

allow_folders: 可选参数,只能是True或者False。默认为False。决定是否应该将目录名包括在内。

比如:

FilePathField(path="/home/images", match="foo.*", recursive=True)

它只匹配/home/images/foo.png,但不匹配/home/images/foo/bar.png,因为默认情况,只匹配文件名,而不管路径是怎么样的。

例子:

import os
from django.conf import settings
from django.db import models

def images_path():
    return os.path.join(settings.LOCAL_FILE_DIR, 'images')

class MyModel(models.Model):
    file = models.FilePathField(path=images_path)

5. UUIDField

数据库无法自己生成uuid,因此需要如下使用default参数:

import uuid     # Python的内置模块
from django.db import models

class MyUUIDModel(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    # 其它字段

注意,不要写成default=uuid.uuid4()

6. GeneratedField

Django 5.0新增。

class GeneratedField(expression, output_field, db_persist=None, **kwargs)

GeneratedField的值是基于模型的其它字段计算出来的。

GeneratedField由数据库本身进行管理和更新,通过GENERATED ALWAYS这个SQL语法。

有两种类型的GeneratedField,一种是物理存在占用存储空间的,一种是虚拟列,不占用存储空间的。

expression参数:一个表达式,用于数据库自动计算并设置字段的值。

output_field参数:一个模型字段的实例,用于定义字段的数据类型

db_persist参数: 用于决定是否数据库的列需要占用存储空间成为真正的列。如果设置为False,那么本数据列是一个虚拟列,不占用实际的物理存储空间。

提示:目前,不同的数据库系统对这个字段的支持不同,内部执行语法和机制也不同,请慎用。这种字段类型的使用,需要你对数据库管理非常精通,对SQL语言的使用非常深入,至少是高级DBA。

所有的模型字段都可以接收一定数量的参数,比如CharField至少需要一个max_length参数。下面的这些参数是所有字段都可以使用的,并且是可选的。

三、字段的参数

null

该值为True时,Django在数据库用NULL保存空值。默认值为False。对于保存字符串类型数据的字段,请尽量避免将此参数设为True,那样会导致两种没有数据的情况,一种是NULL,另一种是空字符串''。Django 的惯例是使用空字符串而不是 NULL

blank

True时,字段可以为空。默认False。和null参数不同的是,null是纯数据库层面的,而blank是验证相关的,它与表单验证是否允许输入框内为空有关,与数据库无关。所以要小心一个null为False,blank为True的字段接收到一个空值可能会出bug或异常。

choices

这个参数用于页面上的选择框标签。

这个参数很重要,Django官方多此对它进行升级改造。

参数的值可以是:

  • 一个元素为二元元组的列表
  • 一个映射mapping
  • 一个枚举类型
  • 一个可调用对象。这个对象不接收任何参数,并且返回前面类型的值。

以二元元组列表为例,二元元组的第一个元素表示存在数据库内真实的值,第二个表示页面上显示的具体的方便理解的短语。在浏览器页面上将显示第二个元素的值。

  • 第一个元素:简短的缩写,储存在数据库中,降低数据大小,节省存储空间
  • 第二个元素:人性化可阅读的字符串文本,显示在浏览器页面上,更可读和直观

例如:

YEAR_IN_SCHOOL_CHOICES = [
    ('FR', 'Freshman'),
    ('SO', 'Sophomore'),
    ('JR', 'Junior'),
    ('SR', 'Senior'),
    ('GR', 'Graduate'),
]

一个mapping的形式:

YEAR_IN_SCHOOL_CHOICES = {
    "FR": "Freshman",
    "SO": "Sophomore",
    "JR": "Junior",
    "SR": "Senior",
    "GR": "Graduate",
}

一个可调用对象的形式:

def get_currencies():
    return {i: i for i in settings.CURRENCIES} 


class Expense(models.Model):
    amount = models.DecimalField(max_digits=10, decimal_places=2)
    currency = models.CharField(max_length=3, choices=get_currencies)

一般来说,最好将选项定义在类里,并取一个直观的名字,如下所示:

from django.db import models

class Student(models.Model):
    FRESHMAN = 'FR'
    SOPHOMORE = 'SO'
    JUNIOR = 'JR'
    SENIOR = 'SR'
    GRADUATE = 'GR'
    YEAR_IN_SCHOOL_CHOICES = [
        (FRESHMAN, 'Freshman'),
        (SOPHOMORE, 'Sophomore'),
        (JUNIOR, 'Junior'),
        (SENIOR, 'Senior'),
        (GRADUATE, 'Graduate'),
    ]
    year_in_school = models.CharField(
        max_length=2,
        choices=YEAR_IN_SCHOOL_CHOICES,
        default=FRESHMAN,
    )

    def is_upperclass(self):
        return self.year_in_school in {self.JUNIOR, self.SENIOR}

注意:每当 choices 的顺序变动时将会创建新的迁移。

如果一个模型中有多个字段需要设置choices,可以将这些二维元组组合起来,显得更加整洁优雅,例如下面的做法:

MEDIA_CHOICES = [
    ('Audio', (
            ('vinyl', 'Vinyl'),
            ('cd', 'CD'),
        )
    ),
    ('Video', (
            ('vhs', 'VHS Tape'),
            ('dvd', 'DVD'),
        )
    ),
    ('unknown', 'Unknown'),
]

对于一个模型实例,要获取一个choices的第二元素的值,也就是人性化的描述字符串,可以使用get_FOO_display()方法,其中的FOO用字段名代替。对于下面的例子:

from django.db import models


class Person(models.Model):
    SHIRT_SIZES = {
        "S": "Small",
        "M": "Medium",
        "L": "Large",
    }
    name = models.CharField(max_length=60)
    shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES)

使用方法:

>>> p = Person(name="Fred Flintstone", shirt_size="L")
>>> p.save()
>>> p.shirt_size
'L'
>>> p.get_shirt_size_display()
'Large'

从Django3.0开始,新增了TextChoices、IntegerChoices和Choices三个类,用来达到类似Python的enum枚举库的作用,下面是一个例子:

from django.utils.translation import gettext_lazy as _

class Student(models.Model):

    class YearInSchool(models.TextChoices):
        FRESHMAN = 'FR', _('Freshman')   
        SOPHOMORE = 'SO', _('Sophomore')
        JUNIOR = 'JR', _('Junior')
        SENIOR = 'SR', _('Senior')
        GRADUATE = 'GR', _('Graduate')

    year_in_school = models.CharField(
        max_length=2,
        choices=YearInSchool.choices,
        default=YearInSchool.FRESHMAN,
    )

    def is_upperclass(self):
        return self.year_in_school in {
            self.YearInSchool.JUNIOR,
            self.YearInSchool.SENIOR,
        }

简要解释一下:

  • 第一句导入是废话,搞国际化翻译的,和本例的内容其实没关系
  • 核心在Student模型中创建了个内部类YearInSchool
  • YearInSchool继承了Django新增的TextChoices类
  • TextChoices中没定义别的,只定义了一些类变量,这些类变量看起来和我们前面使用的二维二元元组本质上是一个套路
  • FRESHMAN = 'FR', _('Freshman') 等同于FRESHMAN = ('FR', _('Freshman'))
  • Student模型中有一个year_in_school 字段,其中定义了choices参数,参数的值是YearInSchool.choices
  • year_in_school 字段还定义了default参数,值是YearInSchool.FRESHMAN
  • 从本质上来说,这和我们开始使用choice的方式是一样的,只不过换成了类的方式,而不是二维元组

吐个槽,这么设计除了增加学习成本有什么好处?有多少Choice选项需要你非得用类的形式管理起来封装起来?二维元组它就不香吗?新手学习就不累吗?

吐槽归吐槽,该介绍的还得介绍,否则是不敬业。

如果你不需要人类可读的帮助文本,那么类似的YearInSchool还可以写成下面的方式,:

>>> class Vehicle(models.TextChoices):
...     CAR = 'C'
...     TRUCK = 'T'
...     JET_SKI = 'J'
...
>>> Vehicle.JET_SKI.label
'Jet Ski'

直接用变量名来作为人类可读的字符串了。

哎,我都写内部类了,还差这点吗?

另外,由于使用整数作为选项的场景太常见了,Django除了提供TextChoices还提供了一个IntegerChoices,例子如下:

class Card(models.Model):

    class Suit(models.IntegerChoices):
        DIAMOND = 1
        SPADE = 2
        HEART = 3
        CLUB = 4

    suit = models.IntegerField(choices=Suit.choices)

实际上,Django为这几个类提供了一些属性,典型的有下面的:

  • .label
  • .choices
  • .values
  • .name

读者可以多尝试,看看每个的意义。

参考用法:

>>> MedalType = models.TextChoices('MedalType', 'GOLD SILVER BRONZE')
>>> MedalType.choices
[('GOLD', 'Gold'), ('SILVER', 'Silver'), ('BRONZE', 'Bronze')]
>>> Place = models.IntegerChoices('Place', 'FIRST SECOND THIRD')
>>> Place.choices
[(1, 'First'), (2, 'Second'), (3, 'Third')]

如果文本或数字类型不满足你的要求,你也可以继承Choice类,自己写。比如下面就创建了一个时间类型选项的choices类:

class MoonLandings(datetime.date, models.Choices):
    APOLLO_11 = 1969, 7, 20, 'Apollo 11 (Eagle)'
    APOLLO_12 = 1969, 11, 19, 'Apollo 12 (Intrepid)'
    APOLLO_14 = 1971, 2, 5, 'Apollo 14 (Antares)'
    APOLLO_15 = 1971, 7, 30, 'Apollo 15 (Falcon)'
    APOLLO_16 = 1972, 4, 21, 'Apollo 16 (Orion)'
    APOLLO_17 = 1972, 12, 11, 'Apollo 17 (Challenger)'

最后,如果想设置空标签,可以参考下面的做法:

class Answer(models.IntegerChoices):
    NO = 0, _('No')
    YES = 1, _('Yes')

    __empty__ = _('(Unknown)')

db_column

该参数用于定义当前字段在数据表内的列名。如果未指定,Django将使用字段名作为列名。

db_comment

Django 4.2新增

字段在数据库中的列的注释文本。这有助于那些不看Django代码,直接看数据库的人,获得一些帮助说明。

pub_date = models.DateTimeField(
    db_comment="Date and time when the article was published",
)

db_default

Django 5.0新增

为字段指定数据库计算出来的默认值。参数值可以是一个字面量,也可以是数据库函数,比如Now():

created = models.DateTimeField(db_default=Now())

表达式还可以更复杂,就像下面这样:

month_due = models.DateField(
    db_default=TruncMonth(
        Now() + timedelta(days=90),
        output_field=models.DateField(),
    )
)

但是,参数值不能引用其它字段或者模型,比如下面这样是错误的:

end = models.IntegerField(db_default=F("start") + 50)

如果在一个字段内同时提供了 db_defaultdefault参数,那么在Python代码中创建实例的时候,default参数优先级更高。但是,当在ORM之外插入数据行,或者在迁移中增加新字段时,db_default仍然会被使用在数据库层面。

db_index

该参数接收布尔值。如果为True,数据库将为该字段创建索引。

db_tablespace

用于字段索引的数据库表空间的名字,前提是当前字段设置了索引。默认值为工程的DEFAULT_INDEX_TABLESPACE设置。如果使用的数据库不支持表空间,该参数会被忽略。

default

字段的默认值,可以是值或者一个可调用对象。如果是可调用对象,那么每次创建新对象时都会调用,否则只调用一次。设置的默认值不能是一个可变对象,比如列表、集合等等。

lambda匿名函数不可用于default的调用对象,因为匿名函数不能被migrations序列化。

注意:在某种原因不明的情况下将default设置为None,可能会引发intergyerror:not null constraint failed,即非空约束失败异常,导致python manage.py migrate失败,此时可将None改为False或其它的值,只要不是None就行。

editable

如果设为False,那么当前字段将不会在admin后台或者其它的ModelForm表单中显示,同时还会被模型验证功能跳过。参数默认值为True。

error_messages

用于自定义错误信息。参数接收字典类型的值。字典的键可以是nullblankinvalidinvalid_choiceuniqueunique_for_date其中的一个。

help_text

额外显示在表单部件上的帮助文本。即便你的字段未用于表单,它对于生成文档也是很有用的。

该帮助文本默认情况下是可以带HTML代码的,具有风险:

help_text="Please use the following format: <em>YYYY-MM-DD</em>."

所以使用时请注意转义为纯文本,防止脚本攻击。

primary_key

如果你没有给模型的任何字段设置这个参数为True,Django将自动创建一个BigAutoField自增字段,名为‘id’,并设置为主键。也就是id = models.BigAutoField(primary_key=True)

如果你为某个字段设置了primary_key=True,则当前字段变为主键,并关闭Django自动生成id主键的功能。

primary_key=True隐含null=Falseunique=True的意思。一个模型中只能有一个主键字段!

另外,主键字段不可修改,如果你给某个对象的主键赋个新值,实际上是创建一个新对象,并不会修改原来的对象。

from django.db import models
class Fruit(models.Model):
    name = models.CharField(max_length=100, primary_key=True)
###############    
>>> fruit = Fruit.objects.create(name='Apple')
>>> fruit.name = 'Pear'
>>> fruit.save()
>>> Fruit.objects.values_list('name', flat=True)
['Apple', 'Pear']

unique

设为True时,在整个数据表内该字段的数据不可重复。

注意:对于ManyToManyField和OneToOneField关系类型,该参数无效。

注意: 当unique=True时,db_index参数无须设置,因为unqiue隐含了索引。

unique_for_date

日期唯一。可能不太好理解。举个栗子,如果你有一个名叫title的字段,并设置了参数unique_for_date="pub_date",那么Django将不允许有两个模型对象具备同样的title和pub_date。有点类似联合约束。

unique_for_month

同上,只是月份唯一。

unique_for_year

同上,只是年份唯一。

verbose_name

为字段设置一个人类可读,更加直观的别名。

对于每一个字段类型,除了ForeignKeyManyToManyFieldOneToOneField这三个特殊的关系类型,其第一可选位置参数都是verbose_name。如果没指定这个参数,Django会利用字段的属性名自动创建它,并将下划线转换为空格。

下面这个例子的verbose name是"person’s first name":

first_name = models.CharField("person's first name", max_length=30)

下面这个例子的verbose name是"first name":

first_name = models.CharField(max_length=30)

对于外键、多对多和一对一字字段,由于第一个参数需要用来指定关联的模型,因此必须用关键字参数verbose_name来明确指定。如下:

poll = models.ForeignKey(
    Poll,
    on_delete=models.CASCADE,
    verbose_name="the related poll",
    )
sites = models.ManyToManyField(Site, verbose_name="list of sites")
    place = models.OneToOneField(
    Place,
    on_delete=models.CASCADE,
    verbose_name="related place",
)

另外,你无须大写verbose_name的首字母,Django自动为你完成这一工作。

validators

运行在该字段上的验证器的列表。


 模型 关系类型字段 

评论总数: 36


点击登录后方可评论

原文: on_delete=models.RESTRICT >>> song_one = Song.objects.create(artist=artist_one, album=album_one) >>> song_two = Song.objects.create(artist=artist_one, album=album_two) 这个关键字的作用应该是没问题的,亲测。博主的例子中song_two也是调用的artist_one



完成



AssertionError: ForeignKey(<function AUTH_USER_MODEL at 0x03314D18>) is invalid. First parameter to ForeignKey must be either a model, a model name, or the string 'self' 做不下去了,请问这个是怎么回事?



ImportError: cannot import name 'production' from 'polls.models' (C:\Users\liang\mysite\polls\models.py) 还是做不下去,怎么办?



留着问题,往后先学习,有些会自然明白。



1、在应用的models中定义好class;2、项目manage.py目录下打开终端执行makemigrations和migrate命令;3、py manage.py shell打开终端,from django.db import models 与 from 应用.models import 类名。 我是这样解决类似问题的,给后面同学提供点思路,如有不对请指正谢谢。



博主,OneToOneField可以理解成继承吗?



感觉是OneToOneField的两个表产生了对应关系更贴切,应该不是继承,给原来User表额外添加了字段,但又不在一个空间里,使用关联查询能查到



为什么这个User没有定义?需要导入什么吗? 作者麻烦解释一下 Traceback (most recent call last): File "<input>", line 1, in <module> NameError: name 'User' is not defined



models.CASCADE 后面用不用加() ??? 在pycharm中自动补全中后面有括号



不能加。IDE自动补全不是万能的



“而不是子评论。为什么呢?因为外键要放在‘多’的一方!” 为什么 父评论 是比较多的一方 ? 能解释一下吗 ?谢谢



一个父评论下可以有多个子评论,而一个子评论只能属于某个特定的父评论,所以这是个外键,一对多的关系。并且子评论是多的一方,父评论是‘一’的一方。根据Django模型的定义原则,外键放在多的一方。



如果你仔细推敲原文,其实博主没写错。只不过初学者会觉得文中有点饶,容易误解而已。



写的没有错,对比一下上边儿的car,在多的一方car中定义外键的返回名是manufacturer,可能描述产生了歧义



子评论是’多‘的一方,博主这边定义的common指的就是’子评论表‘,外键为父评论。外键可以理解为外部表的主键,他一定是唯一的。但是评论的性质又决定了这是个套娃表



老师,related_name小节下面第二行是不是写错了?Django应该是默认以模型的小写+‘_set'作为反向关联名吧?



你说得对。博主没有细说这个。



感觉写了很多平时根本用不到的内容。



博主前面说过,“参考书式的讲解,可能比较晦涩,但绝对是你入门之后,最好的帮手,我们可以时不时,在需要的情况下,回头再翻翻,然后恍然大悟”,这篇教程是像字典那样把知识点罗列起来,很多字可能确实不常用,但是你以后遇到了可以来这里查看是什么意思。你觉得没用,不深究就行了,快速带过。



你们俩说的都有道理。我看第一遍的时候傻乎乎地一个个细节都从头看到尾,有一点不懂我就觉得好痛苦。 现在觉得应该是好读书不求甚解。我也打算挑重点看,不重要的晦涩的东西就一遍过,知道一个大概,留下一个印象就好了。加油,fighting!



django2.0.1+xadmin,在models中,A类有a,b,c三个CharField类型字段,B类中d,外键关联ForeignKey,关联到指定的字段b或c,咋关联啊?d就自动关联到a字段的值了。跪求老师和在座的各位大神们,帮忙解答下,实在没办法了



ForeignKey('User')和ForeignKey(User)有什么区别呢,感觉应该是一样的呀



加引号时User模型可以在引用的模型之后,不加引号的话只能在前边先定义好User



through段落倒数第二句: ‘邀请时间’的字段。 应该是"邀请原因"的字段.~



请问博主,假如我有一个5行*6列的表,其中有的行 每一列都有数据,有的行只有其中3列有数据。那么在adminsite显示的时候,可否让那些没有值的charfield不显示呢?



参考http://www.liujiangblog.com/course/django/158



博主您好,我看了您发给我的链接。其中exclude可以不显示某一特定的列,但是我想实现的是仅显示一列中有值的内容,而不显示没有值的内容。请问用什么方法可以做到呢?



ModelAdmin.empty_value_display



谢谢您的回复。但是我查到的关于empty_value_display的用法只是说这个可以改变empty value的显示形式(比如‘None’或者其他自定义形式)但是没有说可以不显示,请问是需要override这个类吗?



灵活一下...



测试



为什么models.OneToOneField(to=User),若加上参数to_field=User.name则报错?(注:User.name已设为唯一约束)



问题描述不清晰。根据报错信息具体分析吧。



对应mysql外键的on delete, on update 关键字



没有