Django 框架 数据库操作

数据库与ORM

1    django默认支持sqlite,mysql, oracle,postgresql数据库。

     <1> sqlite

            django默认使用sqlite的数据库,默认自带sqlite的数据库驱动 , 引擎名称:django.db.backends.sqlite3

     <2> mysql

            引擎名称:django.db.backends.mysql

2    mysql驱动程序

  •    MySQLdb(mysql python)
  •    mysqlclient
  •    MySQL
  •    PyMySQL(纯python的mysql驱动程序)

3     在django的项目中会默认使用sqlite数据库,在settings里有如下设置:

# Database
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

如果我们需要更改数据库,就需要改其配置信息,一般是mysql

DATABASES = {

    'default': {

        'ENGINE': 'django.db.backends.mysql',

        'NAME': 'django_learn',    #你的数据库名称

        'USER': 'root',   #你的数据库用户名

        'PASSWORD': '', #你的数据库密码

        'HOST': '', #你的数据库主机,留空默认为localhost

        'PORT': '3306', #你的数据库端口

    }

}
NAME即数据库的名字,在mysql连接前该数据库必须已经创建,而上面的sqlite数据库下的db.sqlite3则是项目自动创建

USER和PASSWORD分别是数据库的用户名和密码
 

 这样我们的数据库就基本配置完成,我们可以创建一个表来测试一下:

我简单的创建一个数据表:

from django.db import models

# Create your models here.

class Book(models.Model):   #必须继承
    name = models.CharField(max_length=32)
    price = models.FloatField()

然后启动:

python manage.py makemigrations

启动后会报错,报错信息如下:

扫描二维码关注公众号,回复: 1807079 查看本文章
Traceback (most recent call last):
  File "G:\PythonLearning\django_project\venv\lib\site-packages\django\db\backends\mysql\base.py", line 15, in <module>
    import MySQLdb as Database
ModuleNotFoundError: No module named 'MySQLdb'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "manage.py", line 15, in <module>
    execute_from_command_line(sys.argv)
  File "G:\PythonLearning\django_project\venv\lib\site-packages\django\core\management\__init__.py", line 371, in execute_from_command_line
    utility.execute()
  File "G:\PythonLearning\django_project\venv\lib\site-packages\django\core\management\__init__.py", line 347, in execute django.setup() File "G:\PythonLearning\django_project\venv\lib\site-packages\django\__init__.py", line 24, in setup apps.populate(settings.INSTALLED_APPS) File "G:\PythonLearning\django_project\venv\lib\site-packages\django\apps\registry.py", line 112, in populate app_config.import_models() File "G:\PythonLearning\django_project\venv\lib\site-packages\django\apps\config.py", line 198, in import_models self.models_module = import_module(models_module_name) File "G:\PythonLearning\django_project\venv\lib\importlib\__init__.py", line 126, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "<frozen importlib._bootstrap>", line 994, in _gcd_import File "<frozen importlib._bootstrap>", line 971, in _find_and_load File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 665, in _load_unlocked File "<frozen importlib._bootstrap_external>", line 678, in exec_module File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed File "G:\PythonLearning\django_project\venv\lib\site-packages\django\contrib\auth\models.py", line 2, in <module> from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager File "G:\PythonLearning\django_project\venv\lib\site-packages\django\contrib\auth\base_user.py", line 47, in <module> class AbstractBaseUser(models.Model): File "G:\PythonLearning\django_project\venv\lib\site-packages\django\db\models\base.py", line 114, in __new__ new_class.add_to_class('_meta', Options(meta, app_label)) File "G:\PythonLearning\django_project\venv\lib\site-packages\django\db\models\base.py", line 315, in add_to_class value.contribute_to_class(cls, name) File "G:\PythonLearning\django_project\venv\lib\site-packages\django\db\models\options.py", line 205, in contribute_to_class self.db_table = truncate_name(self.db_table, connection.ops.max_name_length()) File "G:\PythonLearning\django_project\venv\lib\site-packages\django\db\__init__.py", line 33, in __getattr__ return getattr(connections[DEFAULT_DB_ALIAS], item) File "G:\PythonLearning\django_project\venv\lib\site-packages\django\db\utils.py", line 202, in __getitem__ backend = load_backend(db['ENGINE']) File "G:\PythonLearning\django_project\venv\lib\site-packages\django\db\utils.py", line 110, in load_backend return import_module('%s.base' % backend_name) File "G:\PythonLearning\django_project\venv\lib\importlib\__init__.py", line 126, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "G:\PythonLearning\django_project\venv\lib\site-packages\django\db\backends\mysql\base.py", line 20, in <module> ) from err django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module. Did you install mysqlclient?
这是因为django默认你导入的驱动是MySQLdb,可是MySQLdb对于py3有很大问题,所以我们需要的驱动是PyMySQL
所以,我们只需要找到项目名文件下的__init__,在里面写入:

#在该文件写入如下代码
import pymysql
pymysql.install_as_MySQLdb()

 这样问题就解决了。

 

但表并未成功创建,还需运行:

python manage.py migrate

这样就完全成功,可以在数据库上查看我们创建的表了。

ORM表模型

表(模型)的创建:

实例:我们来假定下面这些概念,字段和关系

作者模型:一个作者有姓名。

学生模型:每个学生对应一张身份证,每张身份证对应一位学生,学生和身份证模型之间是一对一的关系(one-to-one)

班级模型:一个班级有多个学生,但一个学生不能在多个班上,学生和班级是一对多关联关系(one-to-many),也被称作外键。

班级老师模型:一个老师可以教多个班级,一个班级可以由多个老师教,老师和班级模型就是多对多的关联关系(many-to-many)

 表关系一对一:  

#实质就是在主外键(author_id就是foreign key)的关系基础上,
# 给外键加了一个UNIQUE=True的属性,基本上很少用到一对一,就一张表表示就可以了

单表操作:
创建表:
class Student(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    gender = models.BooleanField()

若表已经被创建,想要增加新的字段,直接在我们创建的类里面加,例:

class student(models.Model):
    name = models.CharField(max_length=30)
    age = models.IntegerField()
    gender = models.BooleanField()
    sign_date = models.CharField(max_length=10)  #新加字段

然后运行:

python manage.py makemigrations

这时会出现选择框,让我们填一下,我们之前上传数据后,该列的默认值:

(venv) G:\PythonLearning\orm_learn>python manage.py makemigrations
You are trying to add a non-nullable field 'sign_date' to student without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
 2) Quit, and let me add a default in models.py
Select an option: 1      #这里选择一,然后填写对应的数值

增加数据(也叫添加表记录):

def one_increate(request):
    #添加表数据一  推荐使用
    student.objects.create(name="wallace",age=12,gender=True)
    student.objects.create(**{
        "name":"夏露",
        "age":13,
        "gender":False
    })
    #添加表数据二
    stu1 = student(name="小米",age=14,gender=False)
    stu1.save()
stu2
= student() stu2.name="小张" stu2.age=13 stu2.gender=True stu2.save() return HttpResponse("创建成功")

 删除表记录

student.objects.filter(name="wallace").delete()

修改表记录

    #方法一
    student.objects.filter(id=6).update(age=20)    #找到直接修改对应字段

    #方法二
    stu1 = student.objects.filter(id=4)[0]   #找到后全部修改一遍,再保存不推荐用
    stu1.age=50
    stu1.save()

查询表记录

关于查询的API

#  <1>filter(**kwargs):      它包含了与所给筛选条件相匹配的对象,结果是一个QuerySet对象,里面的元素是表对象,也叫表记录

#  <2>all():                 查询所有结果,结果是Query对象,里面的元素是表对象,也叫表记录

#  <3>get(**kwargs):         返回与所给筛选条件相匹配的对象,返回结果有且只有一个就是表对象,也叫表记录,如果符合筛选条件的对象超过一个或者没有都会抛出错误。
#  <4>exclude(**kwargs):     它包含了与所给筛选条件不匹配的对象,与filter相反,结果是一个QuerySet对象,里面元素是表对象也叫表记录
 

例:

#关于查找的API
def one_filter(request):
    #单用filter得到是一个QuerySet的对象,类似列表,可迭代,可切片
    stu_obj = student.objects.filter(id=4)
    print(stu_obj)
    #将里面的数据迭代,结构是一个表记录对象,可以通过点的方式取值
    for i in stu_obj:
        print(i)       #表对象,就是一个表的记录
        print(i.name)  #取值
    return HttpResponse("查询结束")

def one_get(request):
    #直接得到一个表对象,也就是表记录  如果得到多个会报错
    stu_obj=student.objects.get(id=4)
    print(stu_obj)
    #取值
    print(stu_obj.name)
    return HttpResponse("查询结束")

def one_all(request):
    #查询结果是一个QuerySet,类似列表,里面是所有的表对象也叫表记录
    stu_obj_list=student.objects.all()
    print(stu_obj_list)
    #迭代出每一个表记录,通过属性对其取值
    for i in stu_obj_list:
        print(i)

    print(i.name)
    return HttpResponse("查询结束")

def one_exclude(request):
  #查询结果是QuerySet对象,里面的元素是除了给定条件的所有表对象,也叫表记录
stu_obj = student.objects.exclude(name="wallace")
  #和上面的效果一样
stu_obj1 = student.objects.all().exclude(name="wallace")
print(stu_obj)
for i in stu_obj:
print(i.name)
print(stu_obj1)
return HttpResponse("exclude success")

对查询结构处理的方法:

 values:返回得到的是一个Queryset对象,但里面的元素是一个个字典。单表情况下配合all或直接引用。多表以后介绍

def one_value(request):
    #values得到的是一个特殊的QuerySet对象,类似列表,但里面的元素是一个一个的字典
    stu_obj = student.objects.values("name")print(stu_obj)
    #得到的是一个特殊的QuerySet对象,类似列表,里面的元素是一个一个字典
    stu_obj2 = student.objects.filter(id=3).values("name")
    print(stu_obj2)
    
#all取得了全部的表记录,类似于一张表,所以可以去的对应的值 stu_obj3 = student.objects.all().values("name") print(stu_obj3) return HttpResponse("value success")  
def one_value_list(request):
    #和value类似,返回的是QuerySet对象,不过里面元素是列表的形式
    stu_obj = student.objects.values_list()
    print(stu_obj)

正向排序order_by_反向排序reverse

#  <6>order_by(*field):      对查询结果排序,默认是正向排序,*field为按照那个字段排序

#  <7>reverse():              在排序的基础上加上这个语句,进行反向排序,单独使用无意义

def one_order(request):
    #排序
    stu_obj = student.objects.all().order_by("age")
    stu_obj1 = student.objects.order_by("age")
    stu_obj3 = student.objects.filter(age__gt=20).order_by("age")
    print(stu_obj3)
    for i in stu_obj3:
        print(i.age)

    return HttpResponse("order success")

def one_reverse(request):
    stu_obj = student.objects.all().order_by("age").reverse()
    stu_obj1 = student.objects.filter(age__gte=20).order_by("age").reverse()

    print(stu_obj)
    for i in stu_obj:
        print(i.age)

    return HttpResponse("rever success")

distinct:从返回结果中剔除重复记录

def one_distinct(request):
    #取重,这里的去重指的是全部字段都重复时进行去重,除了id字段
    stu_obj = student.objects.all().distinct().values("age","name")
    stu_obj1 = student.objects.distinct().values("age","name")
    print(stu_obj)
    print(stu_obj1)

    return HttpResponse("distinct success")

count:返回数据库中匹配查询(QuerySet)的对象数量

def one_count(request):
    #统计得到表对象的数量
    stu_obj = student.objects.all().count()
    print(stu_obj)
    stu_obj1 = student.objects.filter(age__gte=30).count()
    print(stu_obj1)

    stu_obj2 = student.objects.count()
    print(stu_obj2)

    return HttpResponse("success")

first和last:返回得到QuerySet对象中的第一或最后一个表对象

def one_first_last(request):
    #fiest返回找到的第一个表对象
    stu_obj = student.objects.first()
    stu_obj1 = student.objects.filter(age=13).first()
    print(stu_obj,stu_obj1)
    #last返回的是最后一个表对象
    stu_obj2 = student.objects.last()
    print(stu_obj2)
    return HttpResponse('success')

单表的双下划线操作

        __gt     大于
        __lt     小于
        __gte     大于等于
        __lte    小于等于
        __in       在几个值中
        __range  在一定范围内            

#双下滑线机制,单表
def one__select(request):
    #大于13
    stu_obj = student.objects.filter(age__gt=13).values("age")
    #大于等于13
    stu_obj1 = student.objects.filter(age__gte=13).values("age")
    print(stu_obj)
    print(stu_obj1)
    #小于
    stu_obj2 = student.objects.filter(age__lt=13).values("age")
    #小于等于
    stu_obj3 = student.objects.filter(age__lte=13).values("age")
    print(stu_obj2)
    print(stu_obj3)
    #等于13
    stu_obj4 = student.objects.filter(age__exact=13).values("age")
    print(stu_obj4)
    #在多个值里面
    stu_obj5 = student.objects.filter(age__in=[12,13,14]).values("age")
    print(stu_obj5)
    #在一个范围里面
    stu_obj6 = student.objects.filter(age__range=[12,14]).values("age")
    print(stu_obj6)
    return HttpResponse("success")

注意:Publisher.objects.all()或者.filter()等都只是返回了一个QuerySet(查询结果集对象),它并不会马上执行sql,而是当调用QuerySet的时候才执行。如在遍历或条件

判断的时候,查询数据库的操作才会执行。

查找表字段,也叫对象查找:

def one_obj(request):
    stu_obj_list = student.objects.all()
    #从Queryset集合中得到表对象,通过对象获取里面的字段
    for stu_obj in stu_obj_list:
        print(stu_obj.name)
        print(stu_obj.age)
        print(stu_obj.gender)

    return HttpResponse("success")

一对多的表操作:

在创建多表关系时,先讨论一下,FroeignKey的创建时需注意的地方:

我现在用的是django2.0.2版本,当使用models.ForeignKey设置外键,但是不添加on_delete时,总是会报错:

TypeError: __init__() missing 1 required positional argument: 'on_delete'

而django自从1.9版本之后,on_delete这个参数就必须设置了

看看官网怎么说的吧:

ForeignKey.on_delete
    当一个ForeignKey 引用的对象被删除时,Django 默认模拟SQL 的ON DELETE CASCADE 的约束行为,并且删除包含该ForeignKey的对象。这种行为可以通过设置on_delete 参数来改变。例如,如果你有一个可以为空的ForeignKey,在其引用的对象被删除的时你想把这个ForeignKey 设置为空:

user = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL)

on_delete 在django.db.models中可以找到的值有:
CASCADE
级联删除;默认值。
PROTECT
抛出ProtectedError 以阻止被引用对象的删除,它是django.db.IntegrityError 的一个子类。
SET_NULL¶
把ForeignKey 设置为null; null 参数为True 时才可以这样做。
SET_DEFAULT¶
ForeignKey 值设置成它的默认值;此时必须设置ForeignKey 的default 参数。
SET()¶
设置ForeignKey 为传递给SET() 的值,如果传递的是一个可调用对象,则为调用后的结果。在大部分情形下,传递一个可调用对象用于避免models.py 在导入时执行查询:
from django.conf import settings
from django.contrib.auth import get_user_model
from django.db import models
def get_sentinel_user():
    return get_user_model().objects.get_or_create(username='deleted')[0]
class MyModel(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL,
                             on_delete=models.SET(get_sentinel_user))
DO_NOTHING¶
Take no action. 如果你的数据库后端强制引用完整性,它将引发一个IntegrityError ,除非你手动添加一个ON DELETE 约束给数据库自动(可能要用到初始化的SQL)。
View Code

创建一对多关系表Fromkey:

class Teacher(models.Model):
    name = models.CharField(max_length=30)
    galary = models.IntegerField()
    book = models.ForeignKey("Book",null=True,on_delete=models.SET_NULL) #外键关联我们要关联的表
class Book(models.Model): name = models.CharField(max_length=30) price = models.FloatField()

增加表数据:

def one_more_create(request):
    #添加方式一(推荐)  通过下划线的方式获取书籍id
    teach_obj = Teacher.objects.create(
        name="天蚕土豆",
        galary=3000,
        book_id=1
    )
    teach_obj2 = Teacher.objects.create(
        name="老男孩",
        galary=4000,
        book_id=2
    )
    #添加方式二,先获取书籍对象,再将对象赋值给book
    book_obj = Book.objects.filter(id=3).first()
    teach_obj3 = Teacher.objects.create(
        name="wallace",
        galary=1000000,
        book=book_obj
    )
    return HttpResponse("SUCCESS")

删除和修改和单表操作一致,这里就不再赘述了。

一对多查询表记录:

方法一:从一个表中得到关联表的对象,然后从对象中取值,分为正向查询和反向查询

def one_more_filter(request):
    #正向查询,由多的一方查询一个的一方,通过老师查询出版的书籍名字
    #查询方式一
    # teach_obj = Teacher.objects.get(name="wallace")
    # book_obj = teach_obj.book
    # print(book_obj.name)
    #查询过程:得到表对象,找到对应的外键字段,这个外键字段就是一个表记录对象
    #通过这个表记录对象去查找对应表对象的字段

    # 反向查询:一个的一方查多个的一方,比如查询出版某本书籍的老师
    book_obj1 = Book.objects.filter(name="傲视九重天").first()
    teach_name = book_obj1.teacher_set.all().values("name")
    #通过关联的表的类名加上_set得到对应表的对象  classname_set
    #类似于在父表也创建了一个隐藏的字段
    print(teach_name)
    return HttpResponse("查询成功")

方式二:通过(filter,values)的双下滑线机制,理论是将两个表内联结在一起:

def one_more_filter1(request):
    #一对多表查询(filter,values)的双下划线的使用
    #这种双下划线就像吧两个表内联结在一起,同过下划线获取关联表的字段
    #正向   classname__filed
    book_name = Teacher.objects.filter(name="wallace").values("book__name")
    print(book_name)
    teach_name = Teacher.objects.filter(book__name="极品家丁").values("name")
    print(teach_name)
    #反向
    book_name1 = Book.objects.filter(teacher__name="wallace").values("name")
    teach_name1 = Book.objects.filter(name="大主宰").values("teacher__name")
    print(book_name1)
    print(teach_name1)
    #更多筛选条件   classname__filed__逻辑条件
    teach_name2=Book.objects.filter(name="大主宰",teacher__galary__gt=5000).values("teacher__name")
    print(teach_name2)

    return HttpResponse("success")

多对多表关系:

创建多对多表关系:

class Author(models.Model):
    name = models.CharField(max_length=100)
    age = models.IntegerField()


class Book(models.Model):
    title = models.CharField(max_length=100)
    price = models.IntegerField()
    author = models.ManyToManyField("Author")  #通过该字段就可以创建一个Book和Author的多对多表字段

#这种方式的创建会自动帮我们生成一张关系表,不需要我们自己手动创建

还有另一种创建方式就是我们自己手动的创建第三张关系表,表中只有两表的主键id,因为这种用的不多所以在这里就不赘述了。

多对多表添加绑定关系,如果是单纯的添加字段,可以直接进行单表添加:

def more_create(request):
    #其他字段正常添加,这里添加的是两个表之间的关系
    #例如:向给id=3的书,添加作者
    '''
    第一步:获取该书的对象
    第二步: 获取你给书绑定的作者的集合
    第三步: 通过书的表对象获取添加多对多表关系的字段用add方式添加
    '''
    book_obj = Book.objects.get(id=4)
    author_obj = Author.objects.all()
    #author_obj是一个表集合,所以要加*号
    # book_obj.author.add(*author_obj)
    #通过remove方法,可以将我们建立的表关系解除
    # book_obj.author.remove(*author_obj)
    #也可以传人数字,删除的id为时的关联关系,不常用

    #同理反向添加也是一样的
    author_obj1 = Author.objects.get(id=2)
    book_obj1 = Book.objects.all()
    author_obj1.book_set.add(*book_obj1)
    return HttpResponse("success")

多对多表查询:

def more_to_more(request):
    #找书名id为1的作者的名字
    book_obj = Book.objects.filter(id=1).values("author__name")
    print(book_obj)

    book_obj2 = Book.objects.filter(id=1).first()
    print(book_obj2.author)

    book_obj3 = Book.objects.get(id=3)
    # 这里得到的是一个author的Qureyset的对象
    print(book_obj3.author)
    # 所以需要对他进行去取值
    print(book_obj3.author.all())

    # 而反向查找的时候用set的方式查询
    author_obj = Author.objects.get(id=3)
    print(author_obj.book_set.all())
    return HttpResponse("success")

聚合查询和分组查询:

#聚合查询
def aggre_query(request):
    #这里是选择对应的作者,查询他所有的出的书的价格
    price_avg = Author.objects.filter(id=1).aggregate(Avg("book__price"))
    print(price_avg)

    price_avg2 = Book.objects.all().aggregate(Avg("price"))
    price_max = Book.objects.all().aggregate(Max("price"))
    price_min = Author.objects.filter(id=1).aggregate(Min("book__price"))
    print(price_avg2,price_max,price_min)
    return HttpResponse("success")

#分组查询
def anno_query(request):
    #对作者进行价格的分组,一般分组时会联合聚合函数
    price_avg = Author.objects.values("name").annotate(Avg("book__price"))
    print(price_avg)

    return HttpResponse("success")

F查询和Q查询:是一种自定义的查询手段,当聚合和组合无法满足我们时,可以使用F和Q查询

def q_query(request):
    #这里得到的是一个Queryset集合
    q1 = Author.objects.filter(Q(name__startswith="")).all()
    #可以用逻辑运算符一起作用
    q2 = Author.objects.filter(Q(name__startswith="") | Q(name__startswith=""))
    print(q1.first().name)
    return HttpResponse("success")

def f_query(request):
    #F查询是当你需要对表中的某个字段进行操作时,例如运算等的时候使用
    book_obj = Book.objects.update(price=F("price")+100)

admin

admin是django强大功能之一,它能共从数据库中读取数据,呈现在页面中,进行管理。默认情况下,它的功能已经非常强大,如果你不需要复杂的功能,它已经够用,但是有时候,一些特殊的功能还需要定制,比如搜索功能,下面这一系列文章就逐步深入介绍如何定制适合自己的admin应用。

如果你觉得英文界面不好用,可以在setting.py 文件中修改以下选项:

LANGUAGE_CODE = 'zh-hans'

第二步:

admin.site.register(Book)  #将你要使用的数据库进行注册,这是默认样式

第三步:如果希望使用更多的样式,可以进行定制

class Myadmin(admin.ModelAdmin):
    list_display = ("title","price")
    search_fields = ("title","price")

admin.site.register(Book,Myadmin)

定制样式的语句字段:

  list_display:     指定要显示的字段
  search_fields:    指定搜索的字段
  list_filter:      指定列表过滤器
  ordering:        指定排序字段

第二种使用样式方法:不推荐

# @admin.register(Book)
class Myadmin(admin.ModelAdmin):
    list_display = ("title","price")
    search_fields = ("title","price")

#一般是单个表进行样式添加

  

猜你喜欢

转载自www.cnblogs.com/wallacewang/p/9241392.html