5.Model层
1.ORM 简介
- ORM是MVC 框架中包括一个重要的部分,
- 它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大的减轻了开发人员的工作量,不需要面对因数据库变更而导致的无效劳动
- ORM 是 “对象 - 关系 - 映射” 的简称。

2.创建数据模型
1.创建名为 book 的 app,在 book下的 models.py 中创建模型:
from django.db import models
# Create your models here.
class Book(models.Model):
     #创建的主键列属性为id,可以使用pk代替,pk全拼为primary key
     id=models.AutoField(primary_key=True)
     title=models.CharField(max_length=32)
     state=models.BooleanField()
     pub_date=models.DateField()
     price=models.DecimalField(max_digits=8,decimal_places=2)
     publish=models.CharField(max_length=32)
    
    class Meta:
        #自定义表名,Django默认以 小写app应用名_小写模型类 名为数据库表名。
        db_table="my_book"
        #让id和title这个组合变得唯一
        #Django2.2之前
        unique_together=('id','title')
        #Django2.2之后
        constraints=[
 models.UniqueConstraint(fields=['id','title'],name='unique_user'),
 #增加对书籍出版日期的约束,必须小于当前时间
 models.CheckConstraint(check=models.Q(pub_date__gte=datatime.now()),name="time_gte_now")
        ]
注意:
1.字段名不允许使用连续的下划线,因为字段名称和比较运算符间使用两个下划线
1.字段类型
| 类型 | 举例 | 
|---|---|
| AutoField | models.AutoField(primary_key=True) | 
| BooleanField | models.BooleanField(default=True) | 
| CharField | models.CharField(max_length=512, verbose_name="评论内容") | 
| TextField | models.TextField() | 
| DecimalField | models.DecimalField(max_digits=5,decimal_places=2) | 
| FloatField | models.FloatField() | 
| DateField | 在 Python 中用一个 datetime.date实例表示 | 
| TimeField | 在 Python 中用 datetime.time实例表示 | 
| DateTimeField | 在 Python 中用一个 datetime.datetime实例表示 | 
注意
1.
FloatField内部使用 Python 的float类型,而DecimalField则使用 Python 的Decimal类型2.DateField,TimeField, DateTimeField拥有相同的参数auto_now,auto_now_add
2.字段选项
| 选项 | 说明 | 
|---|---|
| null | 默认值是False,数据库中存储不允许输入空值 | 
| blank | 默认值是False,表单验证不允许输入空值 | 
| db_column | 字这个字段要使用的数据库列名.如果没有给出列名,Django 将使用字段名 | 
| db_index | 默认值是False, 不会在表中为此字段创建索引 | 
| default | 字段的默认值 | 
| primary_key | 若为True,则该字段会成为模型的主键字段,默认值是False | 
| unique | 如果为True, 这个字段在表中必须有唯一值,默认值是False | 
| choices | 由二元组组成的一个可迭代对象(例如,列表或元组),用来给字段提供选择项. 如果设置了choices ,默认的表单将是一个选择框而不是标准的文本框,而且这个选择框的选项就是choices 中的选项。 | 
| verbose_name | 给字段起别名,默认Django会将字段的属性名自动创建,并将下划线转换成空格 | 
| on_delete | models.CASCADE(表示级联),models.SET_NULL(表示非级联) | 
3.配置数据库
1.若想将模型转为 mysql 数据库中的表,需要在 settings.py中配置:
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME':'orm',           # 要连接的数据库,连接前需要创建好
        'USER':'root',        # 连接数据库的用户名
        'PASSWORD':'',        # 连接数据库的密码
        'HOST':'127.0.0.1',       # 连接主机,默认本级
        'PORT':3306            #  端口 默认3306
    }
}
2.确保配置文件中的 INSTALLED_APPS 中写入我们创建的 app 名称
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    "book"
]
3.最后通过两条数据库迁移命令即可在指定的数据库中创建表 :
# 数据库的迁移
python manage.py makemigrations
python manage.py migrate
# 迁移的回退
python manage.py migrate app的名称 aap中migrations中相应的迁移文件名
# 注意:之后别忘了手动删除 migrations 目录中的 0004 号迁移文件,从而完成回退动作
4.如果想打印 orm 转换过程中的 sql,需要在 settings 中进行如下配置:
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
}  
问题1
启动项目报错:no module named MySQLdb 或者 Error loading MySQLdb module
import pymsql
pymsql.install_as_MySQLdb()
问题2
django.core.exceptions.ImproperlyConfigured: mysqlclient 1.4.0 or newer is required; you have 0.10.0
import pymsql
pymysql.version_info=(1,4,13,"final",0)
pymsql.install_as_MySQLdb()
原因分析:
MySQLclient目前只支持到 python3.4,因此如果使用的更高版本的 python,需要修改如下:通过查找路径
\site-packages\Django-2.0-py3.6.egg\django\db\backends\mysql 这个路径里的文件把注释掉就OK了
if version < (1, 3, 3):
     raise ImproperlyConfigured("mysqlclient 1.3.3 or newer is required; you have %s" % Database.__version__)
4.单表增删改查
1.添加表纪录
book_obj=Book.objects.create(title="python葵花宝典",state=True,price=100,publish="苹果出版社",pub_date="2012-12-12")
2.删除表纪录
#使用delete()可以一次性删除多个对象,没有返回任何值
Blog.objects.filter(pk=1).delete()
注意
在 Django 删除对象时,会模仿 SQL约束ON DELETE CASCADE 的行为,换句话说,删除一个对象时也会删除与它相关联的外键对象.如果不想级联删除,可以将ForeignKey设置为:on_delete=models.SET_NULL
3.修改表纪录
#update()可以同时更新多条记录,返回一个整型数值,表示受影响的记录条数
Book.objects.filter(title__startswith="py").update(price=120)
4.查询表纪录
1.基本查询
| 方法 | 调用 | 
|---|---|
| all | Book.objects.all() | 
| get | Book.objects.get(id=1) | 
| count | Book.objects.count() | 
2.过滤查询
语法
Book.objects.filter(属性名称____过滤符=值)
| 名称 | 举例 | 
|---|---|
| exact | id__exact=1 | 
| contains | title__contains=“python” | 
| startswith | title__startswith=“p” | 
| endswith | title__startswith=“典” | 
| isnull | title__isnull=“True” | 
| in | id__in=[1,2,3] | 
| gt,gte,lt,lte | id_gt=1 | 
| year,month,day,week_day,hour,minute,second | pub_date__year=1980 | 
| range | price_range=[100,200] | 
3.extra方法
1.select提供简单数据
SELECT age, (age > 18) as is_adult FROM myapp_person;
Person.objects.all().extra(select={'is_adult': "age > 18"})
2.where提供查询条件
SELECT * FROM myapp_person WHERE first||last ILIKE 'jeffrey%';
Person.objects.all().extra(where=["first||last ILIKE 'jeffrey%'"])
3.table连接其它表
SELECT * FROM myapp_book, myapp_person WHERE last = author_last
Book.objects.all().extra(table=['myapp_person'], where=['last = author_last'])
4.params添参数
# 如果first_name中有SQL特定字符就会出现漏洞
first_name = 'Joe' 
# 错误方法
Person.objects.all().extra(where=["first = '%s'" % first_name])
# 正确方法
Person.objects.all().extra(where=["first = '%s'"], params=[first_name])
5.select高级查询
#相关子查询,而且只能select一个值(a.id),否则报错:当没有用 EXISTS 引入子查询时,在选择列表中只能指定一个表达式
InnerMail.objects.extra(select={'status':'select a.id from letter_imail_status a where a.id=letter_innermail.id'})
def extra(self, select=None, where=None, params=None, tables=None,
              order_by=None, select_params=None):
        """
        Adds extra SQL fragments to the query.
        """
        assert self.query.can_filter(), \
                "Cannot change a query once a slice has been taken"
        clone = self._clone()
        clone.query.add_extra(select, select_params, where, params, tables, order_by)
        return clone
5.其他操作
| 操作名称 | 关键字 | 举例 | 
|---|---|---|
| 切片 | first(): | articles = Article.objects.filter(created__year=2021).first() | 
| last(): | articles = Article.objects.filter(created__year=2021).last() | |
| [:5] | articles = Article.objects.filter(created__year=2021)[:5] | |
| 排序 | order_by(字段名) | |
| reverse(字段名) | ||
| 去重 | distinct() | Article.objects.filter(title__icontains=‘python’).distinct() | 
| exists() | Book.objects.all().exists() | 
5.问题
jinja2模板中怎样使用csrf_token 值
<input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}">
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号