Django_Model详解

Models

model是对于信息的一种模型封装与定义。它包含了你要存储的必要字段和操作数据的方法。一句话概括就是,每个模型映射了一张数据表。
基本概念:

  • 每个model都是继承于django.db.models.Model 的Python类。

  • model的每一个属性对应数据表中的一个字段。

  • 通过所有的这些,Django提供了一个自动化生成访问数据库的API。

简单实例

这个例子定义了Person ,并给它赋予了first_namelast_name:

from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

其中first_namelast_name 是model的字段。如你所见,每一个字段被定义为class类的一个属性,而每个属性对应着数据库的一列。

上面的创建Person ,model模型的过程用SQL语句翻译过来如下:

CREATE TABLE myapp_person(
    "id" serial NOT NULL PRIMARY KEY,
    "first_name" varchar(30) NOT NULL,
    "last_name" varchar(30) NOT NULL
);

下面是一些需要注意的问题:

  • 数据表的名字,myapp_person,自动继承一些model的metadata设定,但是同时支持自定义。

  • id字段是自动添加的,但是它同样可以自定义。

  • CREATE TABLE这个SQL语句在这个例子中由PostgreSQL来实现,

使用models

一旦你定义好了你的模型,你需要告诉Django你将要使用这些models。这就需要秀修改工程目录下的settings.py文件。假设你的model定义在了app名为myapp的models.py 文件中,为了使得Django识别出你要使用这个model,你就需要在settings.py中设定如下:

INSTALLED_APPS = [
    #...
    'myapp',
    #...
]

当你添加新的APP到INSTALLED_APPS中时。需要运行命令python manage.py migrate使设置生效。可供选择的是为了使用git等代码管理软件,你可以先运行python manage.py makemigrations

字段

model最重要的部分而且也是model所需的基础部分是它定义的数据库字段的集合。字段由类的属性来定义。需要注意一点,不要使用和models API冲突的名字来命名字段例如clean,save或者delete

例子:

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.DataField()
    num_stars = models.IntegerField()

字段类型

你模型中的每一个字段应该是一个Field类的实例。Django使用字段类来决定一些事:

  • 列的类型,就是告诉数据库要存储的数据类型是什么。

  • 默认的HTML插件 ,用以渲染表单字段(例如<input type="text">,<select>)

  • 基本的验证需求,在Django的admin中和自动生成的表单中使用。

Django自带了很多内建的字段类型。若Django没有你想要的类型,你可以自己实现


字段选项

每一个字段使用一个确定的字段声明参数集合。例如,CharField(还有它的子类)需要一个max_length参数来声明数据库用于存储字段VARVHAR的个数。

同样的,还有其他的一些选项可用来设置字段,它们都是可选的。下面介绍几个比较常用的设置选项:

null:
若为True,Django会把空数据使用NULL存储在数据库中。默认是False。
blank:
若为True,该字段允许为空。默认是False。
注意它和null的不同。null是纯粹和数据库相关的,而’blank’则是和验证相关的。若一个字段的blank=True,表单的验证将会允许实例带一个空值。反之则不行。
choices:
一个可迭代的元祖,用来作为字段内容的选择。若这个给定,默认的表单插件将会变成一个单选框而不是简单的文本字段,并且单选框中的选项数目由给定的choices来限定。
一个标准的choices列表和下面的形式类似:

YEAR_IN_SCHOOL_CHOICES = (
    ('FR','Freshman'),
    ('SO','Sophmore'),
    ('JR','Junior'),
    ('SR','Senior'),
    ('GR','Graduate'),
)

每个元组中的第一个元素是要存储在数据库中的内容。第二个元素用于在显示的控件上展示。

给定一个model的实例,用于显示的choices的值可以通过使用get_FOO_display()方法来获取,例如:

from django.db import models

class Person(models.Model):
    SHIRT_SIZE = (
    ('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()
 'L'

default:
这个选项用于设置该字段的默认值。可以是一个值或者可以是一个可以调用的对象。若是可调用的对象,它会在每次新对象创建的时候调用。
help_text:
额外的帮助文本用于显示在widget上。它对文档的生成很有用。
primary_key:
若为True,该字段会作为这个model的主键。如果你没有为其他字段声明primary_key=True,Django会自动地添加一个IntegerField字段作为主键。所以如果没有特殊需求,这个选项可以不做设置。
主键的字段是只读的。如果你改变了现有对象的主键的值然后保存了这个对象,一个新的对象就会和旧的对象并行创建。啥意思呢?如下面的例子所示:

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)
<QuerySet ['Apple','Pear']>

unique:
若为True,该字段必须是整张表中独一无二的

自动主键字段

默认情况下,Django给每个模型以下字段:

id = models.AutoField(primary_key=True)

这是一个自动添加的自增主键。
如果你想声明一个典型的主键,只需要在对应的字段选项中设置primary_key=True。若Django看到你显式声明了自定义的主键,那么Django就不会为你创建一个自增的id字段。
每个模型需要明确一个字段作为主键。


verbose字段

除了ForeignKeyManyToManyFieldOneToOneField,每个字段都有一个可选的设置参数:详细。若这个选项未给定,Django会使用属性名来定义,用下划线分隔。
下面的例子中,verbose的名称是”person’s first name”

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

下面的例子中,verbose的值为”first name”:

first_name = models.CHarField(max_length=30)

ForeignKeyManyToManyFieldOneToOneField需要第一个参数为model类对象,所以如果要使用verbose_name,需要显式地声明:

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

一个惯例就是verbose_name的第一个字母一般不写成大写的形式。Django将会自动地将需要首字母大写的地方大写。


数据库关系

Django提供了用来描述三种数据库关系的方法,分别是:many-to-onemany-to-manyone-to-one

Many-to-one

使用django.db.models.ForeignKey来定义Many-to-one这种关系。这个类的使用和其他字段的定义一样,也是作为一个属性存在。
ForeignKey需要一个位置指示参数:当前model相关联的class类名。
例如,Car 和Manufacturer(制造商)。每个Manufacturer都会制造很多Car,但是每辆Car只属于一家Manufacturer,这样的关系就称为多对一关系。基于此例子,代码可以编写如下:

from django.db import models

class Manufacture(models.Model):
    # ...
    pass
class Car(models.Model):
    manufacturer = models.ForeignKey(Manufacturer,on_delete=models.CASCADE)
    # ...

关于ForeignKey更加详尽的定义链接如下

Many-to-many

举个例子,每个Pizza对象都有多个Topping对象,而多个Topping对象则可以在多个Pizza饼上。代码如下:

from django.db import models

class Topping(models.Model):
    # ...
    pass
class Pizza(models.Model):
    # ...
    toppings = models.ManyToManyField(Topping)

————(复杂的多对多情况遇到的时候再补充)—————–

One-to-one

例如,如果你构建了一个名为places的数据库,你应该在数据库中构建相对标准的东西例如地址,电话号码等。然后,如果你想在places的基础上创建一个restaurants 的数据表,这时你就可以直接使用places 所定义好的部分,使用的方式就是一种one-to-one的模式。

跨APP的model调用

如果当前app下models.py 文件中的代码想要调用另外一个app中models.py中的model,这也是可以的。做法就是在当前文件中以导入类的方式导入你想要使用的外部的model,然后直接使用即可:

from django.db import models
from geography.models import ZipCode

class Restaurant(models.Model):
    # ...
    zip_code = models.ForeignKey(
    ZipCode,
    on_delete=models.SET_NULL,
    blank=True,
    null=True,
)

字段的名称限定

Django对于字段的限制有两个:
- 字段的名称不能为Python的关键字,这个比较好理解,举例如下:

class Example(models.Model):
    class = models.IntegerField() # 'pass' 是Python的保留字符
  • 字段的名称不能包含超过两个下划线,因为这会与Django查找语法起冲突。
class Example(models.Model):
    foo__bar = models.IntegerField() # 'foo__bar' 有两个下划线

SQL的一些保留字如`join,whereselect则是可以在model的字段名称中使用的,因为Django在每次SQL查询中避免了可能发生的冲突。


自定义字段类型

如果现有的字段无法满足你的需求,你也可以自定义字段。具体的细节参考此链接

Meta选项

通过使用内部类Meta来设置model的元数据,例子如下:

from django.db import models

class Ox(models.Model):
    horn_length = models.IntegerField()

    class Meta:
        ordering = ["horn_length"]
        verbose_name_plural = "oxen"

Model的元数据是“任何非字段的数据”,例如ordering的选项,数据表名字(db_table),或者人类可读的单复数名称(verbose_name和verbose_name_plural)。这些都不是Model所必需的,是可选项。
更多关于Meta的选项点击此链接

Model属性

objects:
model最重要的属性是Manager。它是提供给Django的数据库查询操作的接口,用于从数据库中获取model实例。若非特别声明Manager,它默认的名字为objects。Manager只能通过model类进行访问,不能通过model实例进行访问。


Model方法

为model的对象操作定义一般的“row-level”功能。而Manager方法是对于整张表操作的方法。model的方法应该作用于某一特定的model实例上。
对于使得业务逻辑的统一来说这是一项很有价值的技术。
例如,下面的model有一些常用方法:

from django.db import models
class Person(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    birth_date = models.DateField()
    def baby_boomer_status(self):
        "returns the person's baby-boomer status."
        import datetime
        if self.birth_date < datetime.date(1945,8,1):
            return "Pre-boomer"
        elif self.birth_date < datetime.date(1965,1,1):
            return "baby boomer"
        else:
            return "Post-boomer"
    @property
    def full_name(self):
        "Returns the person's full name."
        return "%s %s %(self.first_name,self.last_name)

本例中的最后一个方法是一个property
model实例有很多方法的接口,你可以通过重写这些方法来实现自己想要的功能:
__str__():
Python的”魔力函数“,该函数返回一个表示当前对象的字符串。适用于Python或者Django用于将实例显示为纯字符串的形式,这样的情形往往会出现在交互的命令行窗口或者在admin页面中。
get_absolute_url():
该函数告诉Django如何计算一个对象的url。Django
在admin接口中使用该函数,在需要的时候返回对象的url。

覆写预定义的模型方法

还有一些其他方法封装了一些你可能会使用到的数据库操作。尤其是save()delete()方法比较常用。
你可以自由覆写这些方法来获得自己想要的数据库操作。
一个典型的使用情景是如果你想要在保存对象到数据库的时候做一些事情,就可以覆写实现。以save()函数为例:

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()
    def save(self, *args, **kwargs):
        do_something()
        super().save(*args, **kwargs) # Call the 'real' save() method.
        do_something_else()

同样你可以阻止保存行为:

from django.db import models
class Blog(models.Model):
    name = models.ChariField(max_length=100)
    tagline = models.TextField()
    def save(self, *args, **kwargs):
        if self.name == 'Yoko Ono's blog':
            return # Yoko shall never have her own blog!
        else:
            super().save(*args, **kwargs) # Call the 'real' save() method.

不要忘记在覆写的时候调用父类的方法super().save(*args,**kwargs),这样可以确保对象可以存储到数据库中。如果你忘记了调用父类的方法,那么所有的操作都不会数据库中生效。

在shell中对数据库进行操作

Django提供了一个命令行工具,可以将当前项目下的环境,迁移到当前工作环境下。

在建立了model之后,可以在shell中对model进行操作,执行以下语句,进入shell:
python manage.py shell
执行后,进入python命令行模式,此时就可以在这里对你建立的model进行操作了。
假设我们建立了两个model,定义如下:

class Grades(models.Model):
    gname = models.CharField(max_length=20)
    gdate = models.DateTimeField()
    ggirlnum = models.IntegerField()
    gboynum = models.IntegerField()
    isDelete = models.BooleanField()
    def __str__(self):
        return "%s-%d-%d"%(self.gname,self.ggirlnum,self.gboynum)

class Student(models.Model):
    sname = models.CharField(max_length=20)
    sgender = models.BooleanField()
    sage = models.IntegerField()
    scontend = models.CharField(max_length=20)
    isDelete = models.BooleanField()
    sgrade = models.ForeignKey('Grades', on_delete=models.CASCADE)

数据的插入

from myapp.models import *
from django.utils import timezone
from datetime import *
grade1 = Grades() #新建一个数据表实例
grade1.gname = 'table1'
grade1.gboynum = 10
grade1.ggirlnum = 3
grade1.gdate = datetime(year=2018,month=7,day=17)
grade1.isDelete  = False
grade1.save()#保存数据表

以上代码执行后,会在mysql数据库的myapp_grades数据表中插入一条数据。

数据的修改

from myapp.models import *
grade2 = Grades.objects.get(pk=2)
grade2.gboynum = 60
grade2.save()

数据的删除

from myapp.models import *
grade2 = Grades.objects.get(pk=2)
grade2.delete()

关联对象

from myapp.models import *

grade1 = Grades.objects.get(pk=1)

stu = Student()
stu.sname = "abc"
stu.sage = 20
stu.sgender = False
stu.scontend = "hello abc"
stu.grade = grade1
stu.save()

关联对象下,对于获取关联对象的机集合,有两个主要任务:

获得一条Grades数据所对应的所有学生Student
获得Student所对应的班级Grade

获取grade1下所对应的所有学生
grade1.students_set.all()

运行上面的语句i,可以得到grade1所对应的所有学生的集合。格式可以总结为:

对象名.关联的类名(小写)_set.all()

也可以使用grade1直接创建grade1下的Student对象,代码如下:

grade1.students_set.creat(sname="add",sage=22,sgender=False,scontent="asdfasf")

运行SQL语句

model方法或者module-level方法的另外一个特性是写传统的SQL语句


Model继承

Django中Model的继承方式几乎和Python中类的继承方式几乎一样。所有的model都继承于实例django.db.models.Model
你需要做的决定仅仅是你的父类model的角色:是作为一个抽象类,给子类提供一个通用部分的描述?还是直接作为实例,拥有自己的数据表?以下是三种最常用的类继承模式:

  • 通常情况下,我们只想使用父类来保存一些你不想在每个子类中都敲一遍的通用信息。该类不会真正对数据库操作,也就是所谓的抽象基类。
  • 如果你继承了一个现存的模型(可能来自于另外一个app实例)并且想要每个model都有自己的数据表,Multi-table inheritance就是这样做的。
  • 最后,如果你只是想要修改Python语言级别的model行为而不修改models的字段,你可以使用[Proxy models](https://docs.djangoproject.com/en/2.0/topics/db/models/#proxy-models)

抽象基类

抽象基类在你想要在你的模型中加入一些信息的时候很有用。在元数据中将基类的参数abstract=True,这样,该model就不会被用来创建任何数据表。当它被其他model作为基类时,它的字段将会作为继承它基类的字段。子类中的字段名不能和基类中的字段名一样,否则会报错。下面是一个例子:

from django.db import models
class CommonInfo(models.Model):
    name = models.CharField(max_length=100)
    age = models.PositiveIntegerField()
    class Meta:
        abstract = True
class Student(CommonInfo):
    home_group = models.CharField(max_length=5)

Student模型有三个字段,分别是name,agehome_group
CommonInfo模型不能被用作是一个正常的Django模型,因为他是一个抽象基类,它不会生成数据库表或者有manager,不能被直接实例化或者保存。


Meta继承

当一个抽象基类被创建的时候,Django会声明一些Meta 内部类,若子类没有声明它自己的Meta类,它就会继承父Meta。如果子类想要拓展父Meta类,需要先继承,再拓展:

from django.db import models
class CommonInfo(models.Model):
    # ...
    class Meta:
        abstract = True
        ordering = ['name']
class Student(CommonInfo):
    # ...
    class Meta(CommonInfo.Meta):
        db_table = 'student_info'

Django对于抽象基类Meta类做了调整:在使用Meta属性的时候,会设置abstract=False 。这意味着抽象基类的子类不会自动变成抽象类,除非你自己手动将其设置为True,让其成为抽象类。

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Django_celery_beat是一个django应用程序,它允许您使用celery定期运行周期性任务。这些周期性任务可以是一次性的或循环的,你可以设置它们在指定的时间间隔内自动运行,也可以设置它们在特定的时间运行。 要使用django_celery_beat,请按照以下步骤操作: 1. 安装django_celery_beat: ``` pip install django_celery_beat ``` 2. 在settings.py中添加以下代码: ``` INSTALLED_APPS = [ # ... 'django_celery_beat', ] CELERY_BEAT_SCHEDULER = 'django_celery_beat.schedulers:DatabaseScheduler' ``` 3. 在项目的urls.py文件中添加以下代码: ``` from django.urls import path from django_celery_beat.views import ( PeriodicTaskListView, PeriodicTaskCreateView, PeriodicTaskUpdateView, PeriodicTaskDeleteView, PeriodicTaskDetailView, ) urlpatterns = [ # ... path('celery/periodic-tasks/', PeriodicTaskListView.as_view(), name='periodic_task_list'), path('celery/periodic-task/add/', PeriodicTaskCreateView.as_view(), name='periodic_task_create'), path('celery/periodic-task/<int:pk>/', PeriodicTaskDetailView.as_view(), name='periodic_task_detail'), path('celery/periodic-task/<int:pk>/update/', PeriodicTaskUpdateView.as_view(), name='periodic_task_update'), path('celery/periodic-task/<int:pk>/delete/', PeriodicTaskDeleteView.as_view(), name='periodic_task_delete'), ] ``` 4. 在celery.py文件中添加以下代码: ``` from celery import Celery from django.conf import settings app = Celery('my_project') app.config_from_object('django.conf:settings', namespace='CELERY') app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) ``` 5. 在tasks.py文件中创建您的任务,例如: ``` from celery import shared_task @shared_task def my_task(): # Do something here ``` 6. 创建周期性任务,您可以使用Django admin或创建它们的视图。 现在,您已经可以在django中使用celery定期运行周期性任务了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值