Django-orm数据库相关

django-orm

数据库设定

Django默认使用的为sqlite,所以在使用mysql或其他数据库的时候需要对其进行相关设定

1.settings.py

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME':'dbname',
        'USER': 'root',
        'PASSWORD': 'xxx',
        'HOST': '',
        'PORT': '',
    }
}

2. project项目下的_init_.py

由于Django默认使用MySQLdb,python3中无此模块,使用pymysql的话需要再次添加:
    import pymysql
    pymysql.install_as_MySQLdb()

3. 注册

在settings中INSTALLED_APPS注册我们的app

4.app的models.py中创建表

from django.db import models
# Create your models here.
class UserInfo(models.Model):
    # django会默认帮你创建一个自增id字段作为主键
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=64)
    email = models.EmailField()

5. makemigrations

python manage.py makemigrations
创建更改的文件

6.migrate

python manage.py migrate
将生成的py文件应用到数据库

7. 生成的表:

+----------------------------+
| Tables_in_cmdb             |
+----------------------------+
| app_cmdb_userinfo          |
| auth_group                 |
| auth_group_permissions     |
| auth_permission            |
| auth_user                  |
| auth_user_groups           |
| auth_user_user_permissions |
| django_admin_log           |
| django_content_type        |
| django_migrations          |
| django_session             |
+----------------------------+ 

mysql> desc app_cmdb_userinfo;
+----------+--------------+------+-----+---------+----------------+
| Field    | Type         | Null | Key | Default | Extra          |
+----------+--------------+------+-----+---------+----------------+
| id       | int(11)      | NO   | PRI | NULL    | auto_increment |
| username | varchar(32)  | NO   |     | NULL    |                |
| password | varchar(64)  | NO   |     | NULL    |                |
| email    | varchar(254) | NO   |     | NULL    |                |
+----------+--------------+------+-----+---------+----------------+

Django ORM操作相关

1.添加数据

from app_cmdb import models
# 有几个字段,传几个参数就行了
models.UserInfo.objects.create(username="leon", password="123123", email='4641231@qq.com')

# 方法2
stu1 = user(username="leon", password="123123", email='4641231@qq.com')
stu1.save() # flush到数据库中

2.数据修改

# 单个数据的多个字段同时跟新
models.UserInfo.objects.get(username="leon", password="123123", email='4641231@qq.com').update(username="Leon",password="qweasdC")

# 跟新某个字段
user_obj = models.UserInfo.objects.get(username="leon", password="123123")
user_obj.username="Jack"
user_obj.save()

# 多条数据同时跟新
models.UserInfo.objects.all().update(username='Zhang') 

3.数据删除

# 删除表中所有数据
models.UserInfo.objects.all().delete()
# 筛选单个删除
models.UserInfo.objects.get(username="leon").delete()
# 过滤多个删除
models.UserInfo.objects.filter(username="leon").delete()

4.数据查询

所有查询、过滤、排序、取值方法可以结合自己的使用场景来使用,以达到最佳的效果,下面是一些基础的查询操作,在文末会有更加详细的介绍

# 查询所有记录
models.UserInfo.objects.all()


# 带字段名的所有记录,就是将所有记录以key-value的形式保存在字典中
models.UserInfo.objects.all().values()
>>><QuerySet [{'id': 1, 'username': 'leon', 'password': '123123', 'email': '4641231@qq.com'}, {'id': 2, 'username': 'leon', 'password': '1123123', 'email': '4641231@qq.com'}]>

# 查询单条记录,使用get查询单条数据,如果没有查到,会直接报错,结合try来使用
models.UserInfo.objects.get(name='Aaron')

# 查询多条中的第一条记录,多个过滤条件,需要在filter中用逗号分隔开
models.UserInfo.objects.filter(username='leon', password="123123").first()

# 模糊过滤,字段只要包含就可以
models.UserInfo.objects.filter(username__contains='leo').first()

# 模糊-不区分大小写
models.UserInfo.objects.filter(username__icontains='leo').first()


# 将字段内容排序后显示
models.UserInfo.objects.order_by('username')


# 查询记录的个数
models.UserInfo.objects.filter().conut()

# 筛选之大于小于,多个用逗号分开
models.UserInfo.objects.filter(id__gt=1)  # 大于1
models.UserInfo.objects.filter(id__gte=1)  # 大于等于1
models.UserInfo.objects.filter(id__lt=1)  # 小于1
models.UserInfo.objects.filter(id__lte=1)  # 小于等于1
models.UserInfo.objects.filter(id_gt=1,id__lte=10) # 大于1小于等于10


# in,not in
models.UserInfo.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据
models.UserInfo.objects.exclude(id__in=[11, 22, 33])  # not in


# 排序值逆序
models.UserInfo.objects.order_by('-username')

# 限制数据条数,因为返回的是一个QuerySet类型的列表,我们可以使用列表的分片来获取想要的数据内容,依然按照`顾首不顾尾`的原则
models.UserInfo.objects.filter(username="leon")[0]  # 第一条数据
models.UserInfo.objects.filter(username="leon")[0:3]  # 去前三条数据


5.数据字段类型

  • 几种主要的类型之-数字类型
1. AutoField int类型(1 to 2147483647)的自增id列,须加参数 primary_key=True
2. BigAutoField bigint类型(1 to 9223372036854775807),同上
3. BigIntegerField
4. IntegerField
5. FloatField 
6. SmallIntegerField
7. PositiveIntegerField
8. PositiveSmallIntegerField

  • 字符串类型
1. CharField
2. EmailField (admin)
3. GenericIPAddressField (admin)
4. URLField (admin)
5. UUIDField

  • 时间类型
1. DateField (Python:datetime.date)
2. DateTimeField (Python: datetime.datetime )
3. DecimalField (python : Decimal)
4. DurationField (python :  timedelta)
5. TimeField  (python : datetime.time)

  • 二进制类型
1. BinaryField
  • 布尔类型
1. BooleanField
  • 文件类型
1. FileField

6.参数

  • 基本
- null 是否可以为空
- default 默认值
- primary_key 主键
- db_column 舍子数据库中的列名
- db_index  建立普通索引
- unique 唯一索引
- unique_for_data 只对时间做索引
- unique_for_month 只对月份做索引
- unique_for_year 只对年份做索引
- auto_now  添加还是修改对象,时间为你添加或者修改的时间,需要使用obj.save()来跟新,而update不能跟新
- auto_now_add 创建时自动创建时间,跟新不动

  • admin:

- choices 两个作用
	user_type_choices = (  # 将这些字段放进内存,而避免数据库连表操作
        (1,'root'),
        (2,'root1'),
        (3,'root1')
    ) 而且在django-admin中可以通过select直接选择
    user_type_id = models.IntegerField(choices=user_type_choices,default=1)
- blank admin中是否可以为空
- verbose_name="用户名"  前端显示的别名
- editable 是否可以被编辑
- error_messages 输入错误提示消息自定义   error_messages={'required':u'邮箱不能为空'}????
- help_text help_text="user_name"  输入框下的用户提示信息
- validators  Django的form自定义验证机制设置

7.外键的连表操作

表结构

class Host(models.Model):
    nid = models.AutoField(primary_key=True)
    hostname = models.CharField(max_length=32, db_index=True)
    ip = models.GenericIPAddressField(db_index=True, protocol='ipv4')
    port = models.IntegerField()
    b = models.ForeignKey(to='Business', to_field='id')


    def __str__(self):
        # 定制输出对象的时候,自动输出name字段
        return self.name


class Business(models.Model):
    caption = models.CharField(max_length=32)
    code = models.CharField(max_length=32)

测试数据

1.单表相关

  • 查询
# QuerySet内部为对象,模板获取的时候用"."来获取
v1 = models.Business.objects.all() 

# QuerySet内部为key、value的字典,因为是字典,在模板中获取的时候用"."来获取,
v2 = models.Business.objects.all().values('id', 'caption')  #只获取特定字段

# QuerySet内部为元组,因为是元组,在模板中获取的时候使用0,1,2的index来获取
v3 = models.Business.objects.all().values_list('id', 'caption')
class Host(models.Model):
    class Meta:
        # django创建表的时候未指定此字段,则默认为app名称_类名小写
        db_table = "host"    # 数据库中生成的表名称 

        # 多字段联合索引,注意mysql联合索引的最左前缀原则!!!
        index_together = [
            ("hostname", "ip"),
        ]

        # 多字段联合唯一索引
        unique_together = (("hostname", "ip"),)

        # admin中一种易于理解展示形式,默认展示为类名,设定此字段后显示为该字段加's'
        verbose_name='主机'

        # 同上,但是不会加上's'
        verbose_name_plural='主机'

......待补充~

verbose_name结果

verbose_name_plural结果


2. 一对多ForeignKey

1) 数据查询

  • 正向数据查询
# QuerySet内部为对象
v1 = models.Host.objects.filter(nid__gt=0)

# QuerySet内部为key、value的字典,因为是字典
v2 = models.Host.objects.all().values('nid', 'hostname', 'b_id', 'b__caption', 'b__code')

# QuerySet内部为元组,因为是元组
v2 = models.Host.objects.all().values_list('nid', 'hostname', 'b_id', 'b__caption', 'b__code')

# 通过host字段查business
v = models.Host.objects.filter(id=1).all()
v[0].b.caption 或 v[0].b.code
  • 数据反向查询,从Business查询Host
# QuerySet对象
v = models.Business.objects.filter(id=1).all()
# 这样就可以获取所有绑定business.id=1的所有Host的对象
v[0].host_set.all()
# 获取对应的值  
v[0].b.caption 或 v[0].b.code

# QuerySet字典
models.Business.objects.all().values('caption','host__hostname')

# QuerySet元组
models.Business.objects.all().values_list('caption','host__hostname')

2) 可用的字段以及参数

  • to要进行关联的表名

  • to_field要关联的表中的字段名称

  • db_constraint=True 是否在数据库中创建外键约束。例如,默认django在创建host数据的时候对他的b_id字段没有约束性,只是在创建sql语句的时候对sql语句进行了约束。当你设定该字段为False的时候,django支持你的b_id不创建与business表的约束条件,你可以随意设定该值

  • on_delete:外键指向的对象删除时,本对象应该采取的措施,默认级联删除CASCADE。假如删除business表中的一条数据,在新版本的django中也会把与其关联的host表中的数据也删除,但是在mysql中使用delete语句是会引发异常的。on_delete定制当删除关联表中的数据时,定制当前表与其关联的行的行为官方文档:

- models.CASCADE,删除外键对象(Business)数据,与之关联的所有数据也完全删除(默认行为)

- models.DO_NOTHING,删除外键对象(Business)数据,不删除被关联(Host)的数据,引发db层错误IntegrityError

- models.PROTECT,删除外键对象(Business)数据,不删除被关联(Host)的数据,引发django层错误ProtectedError

- models.SET_NULL,删除外键对象(Business)数据,与之关联的(Host)对应字段值设置为null,且前提外键字段需要设置为可为空

- models.SET_DEFAULT,删除外键对象(Business)数据,与之关联的(Host)对应字段值设置为默认值,前提外键字段需要设置默认值

- models.SET,删除外键对象(Business)数据,
    a. 与之关联的(Host)对应字段值设置为指定值,设置:models.SET(值)
    b. 与之关联的(Host)对应字段值设置为可执行对象的返回值,设置:models.SET(可执行对象)

on_delete中的models.SET举例:

# 我们可以在func函数中自定制返回结果,这样开发起来就会有更多选择,可以对数据判断等等~
def func1():
   return 10

class MyModel(models.Model):
    user =models.ForeignKey(to="User",to_field="id"on_delete=models.SET(func1),)
  • related_name='connFK' 上面反向操作时,使用的是表名,用于代替表名_set成为obj.connFK.all(),例如:
v = models.Business.objects.filter(id=1).all()  
v[0].connFK.all() 
  • related_query_name='host_table' 反向操作时,原来使用的是表名,此字段只是用来替换表名,例如:
models.Business.objects.all().values_list('caption','host__hostname')
# 变为
models.Business.objects.all().values_list('caption','host_table__hostname')
  • limit_choices_to=None 显示关联数据时,提供的筛选条件:
limit_choices_to={'id__gt': 1}
limit_choices_to=lambda : {'id__gt': 1}
  • swappable??

2. 一对一:OneToOneField

Stack Overflow热帖,这个问答讲解的其实特别的好,分享一下~

表结构,一个汽车只可以对应一个引擎,一个引擎也只能对应一个汽车

class Engine(models.Model):
    name = models.CharField(max_length=25)

    def __unicode__(self):
        return self.name

class Car(models.Model):
    name = models.CharField(max_length=25)
    engine = models.OneToOneField(Engine)

    def __unicode__(self):
        return self.name

其实OneToOneField其实可以理解为 ForeignKey加上 unique=True的另一种展现形式,但是外键不加unique=True的约束的时候,反向查询返回的是一个QuerSet列表,而OneToOneField反向查询只返回一个QuerSet对象,因为他是一对一的

class Engine2(models.Model):
    name = models.CharField(max_length=25)

    def __unicode__(self):
        return self.name

class Car2(models.Model):
    name = models.CharField(max_length=25)
    engine = models.ForeignKey(Engine2, unique=True)

    def __unicode__(self):
        return self.name

3. 多对多:ManyToManyField

官方文档

表结构,一个作者可以出版很多本书,一本书有很多个作者

class Author(models.Model):
    name = models.CharField(max_length=64)
    age = models.IntegerField()
    
    def __unicode__(self):
        return self.name

class Book(models.Model):
    book_name = models.CharField(max_length=128)
    pub_date = models.DateField()
    book_to_author = models.ManyToManyField('Author')

    def __unicode__(self):
        return self.book_name

这样就会生成三张表,一个作者表,一个书表,还有一个Django自动生成的第三张表,存放作者与书之间的关系表:

在Django中,多对多关系中的第三张表,我们可以让Django自动创建,也可以选择自己创建第三张表,当自己创建的时候,又有两种情况:

  • ManyToManyField 字段, 当存在这个字段的时候,Django支持我们对数据的查询、清除操作可以使用这个字段,但是其他操作是不可以使用这个字段的:

  • 没有ManyToManyField 字段,当没有这个字段的时候,第三张表中就是全部是ForiegnKey,而我们对数据的操作就只能通过这个第三张表来操作:

有ManyToManyField字段

无ManyToManyField字段

1)数据查询

# 通过book_to_author字段来正向查询
v = models.Book.objects.filter(id=1).first()
print(v.book_to_author.all())
>>>> <QuerySet [<Author: Author object>, <Author: Author object>]>
# 反向查询
v1 = models.Author.objects.filter(id=1).first().book_set.all()
v2 = models.Author.objects.filter(id=1).values('name','book__book_name')
v3 = models.Author.objects.filter(id=1).values_list('name','book__book_name')

2)其他操作

v = models.Book.objects.filter(id=1).first()
v.book_to_author.remove   # 可以删除某一条对应关系
v.book_to_author.add      # 添加一条关系
v.book_to_author.set      # 直接设定,会覆盖原值
v.book_to_author.clear    # 清除v对象的所有与之联系

3)参数以及字段

  • to 同ForeignKey中解释,指定需要关联的表名

  • db_table 设定表名,不再使用Django默认创建的表名

  • related_name 同ForeignKey中解释

  • related_query_name 同ForeignKey中解释

  • limit_choices_to 同ForeignKey中解释

  • db_constraint 同ForeignKey中解释

  • through 当第三张表是自己创建的的时候,此字段用于指定第三张关系表。如果不指定,且还有ManyToManyField字段的时候,Django会在数据库中多创建第四张表(自己创建和自动创建都会存在)。使用该字段来定制关系表,就不会创建你自己的那张表

  • through_fieldsDjango默认创建第三张关系表的时候,这个关系表只有三个字段,当第三张表是自己创建的时候,不能规定你的第三张表中的有多少列数据,但是可以通过该字段传入一个多字段的列表来指定那些字段做多对多关系

  • swappable

  • symmetrical

orm数据操作补充

posted @ 2020-03-19 13:02  我的胡子有点扎  阅读(111)  评论(0编辑  收藏  举报