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.字段类型

类型举例
AutoFieldmodels.AutoField(primary_key=True)
BooleanFieldmodels.BooleanField(default=True)
CharFieldmodels.CharField(max_length=512, verbose_name="评论内容")
TextFieldmodels.TextField()
DecimalFieldmodels.DecimalField(max_digits=5,decimal_places=2)
FloatFieldmodels.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_deletemodels.CASCADE(表示级联),models.SET_NULL(表示非级联)

3.Meta选项

db_table

db_table="my_book"

constraints

 constraints=[
 #让id和title这个组合变得唯一    
 models.UniqueConstraint(fields=['id','title'],name='unique_user'),
 #增加对书籍出版日期的约束,必须小于当前时间
 models.CheckConstraint(check=models.Q(pub_date__gte=datatime.now()),name="time_gte_now")
        ]

unique_together

#让id和title这个组合变得唯一
#Django2.2之前
unique_together=('id','title')

abstract

 abstract = True  # 说明是抽象模型类, 用于继承使用,数据库迁移时不会创建BaseModel的表

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.基本查询

方法调用
allBook.objects.all()
getBook.objects.get(id=1)
countBook.objects.count()

2.过滤查询

语法

Book.objects.filter(属性名称____过滤符=值)

名称举例
exactid__exact=1
containstitle__contains=“python”
startswithtitle__startswith=“p”
endswithtitle__startswith=“典”
isnulltitle__isnull=“True”
inid__in=[1,2,3]
gt,gte,lt,lteid_gt=1
year,month,day,week_day,hour,minute,secondpub_date__year=1980
rangeprice_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 }}">
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值