【五十一】Python全栈之路--django的orm02

本文详述了一个使用Django ORM构建的图书管理系统,包括书籍展示、添加、编辑和删除功能。涵盖了数据库模型设计、URL路由、视图函数、模板渲染以及静态文件的配置。此外,还讲解了Django中的查询API,如filter、get、exclude等,以及多表关系的处理。文章还提供了代码实现和关键操作步骤。
摘要由CSDN通过智能技术生成

1. 书籍展示和书籍添加_编辑_删除

在这里插入图片描述

1.1 代码编写流程

1. 在项目中创建app(这里面的数据库引用的其他app,所以要执行一遍数据库迁移指令)
    python manage.py startapp booksys

2. 创建好的应用要和项目关联起来
    在setting.py中INSTALL_APPS中添加booksys

3. 在url.py中配置url路径
    from booksys import views as book_view
    url(r'^books/',book_view.books)

4. 在booksys下的views中写视图函数
    def books(request):
          return render(request,'books.html')

5. 在template下创建books.html
    
6. 要用到bootstrap,就要涉及到静态文件的引入,在settings.py中进行设置
    STATICFILES_DIRS = [
           os.path.join(BASE_DIR,'statics')
]

7. 在根下创建一个statics文件夹,在文件夹下创建book文件夹,里面存放自定义文件
    如css、js、img,在创建一个plugins文件夹用来放bootstrap、jquery,然后在books.html
    中引用加载静态文件

8. 开始在books.html表中写样式,表格里面的内容要用循环
    <tr>
              <td></td>
    <tr>

9. 展示数据,在views中导入models,从数据库中读取数据,然后通过模板渲染进行返回给用户,
    然后在books.html中写jinjia模板,进行模板渲染

10 展示书籍已完成,然后就是添加书籍,添加url  到对应的view视图,然后写数据库语句,在template
     下创建一个add_book.html

11. 因为书籍展示和书籍添加有的是一样的,所以写一个模板base.html

在这里插入图片描述
在这里插入图片描述

1.2 项目主目录代码django_orm

init.py

import pymysql
pymysql.install_as_MySQLdb()

settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01.apps.App01Config',
    'booksys',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR , 'templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

DATABASES = {
     'default': {
         'ENGINE': 'django.db.backends.mysql',
         'NAME': 'orm01',
         'HOST': '127.0.0.1',
         'PORT': 3306,
         'USER':'root',
         'PASSWORD':'',

     }
}

STATIC_URL = '/static/'

STATICFILES_DIRS = [
    os.path.join(BASE_DIR,"statics")
]

urls.py

from django.conf.urls import url
from django.contrib import admin
from app01 import views
from booksys import views as book_view

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^query/', views.query),
    url(r'^books/',book_view.books),
    url(r'^add_book',book_view.add_book),
    url(r'^edit_book/(\d+)',book_view.edit_book), # 提交修改请求,http://127.0.0.1:8000/edit_book/2
    url(r'^del_book/(\d+)',book_view.del_book)
]

1.3 图书系统应用booksys

apps.py

from django.apps import AppConfig

class BooksysConfig(AppConfig):
    name = 'booksys'

models.py

from django.db import models

# Create your models here.

from django.db import models


# Create your models here.

class Book(models.Model):
	# 如果没有指定主键字段,默认orm会给这个表添加一个名称为id的主键自增字段
	# 如果指定了,以指定的为准,那么orm不在创建那个id字段了
	# nid = models.AutoField(primary_key=True) # int primary_key auto_increment
	title = models.CharField(max_length=32)  # varchar 书籍名称
	# price = models.FloatField()#
	price = models.DecimalField(max_digits=5,decimal_places=2) # 999.99
	pub_date = models.DateField() # data 出版日期
	publish = models.CharField(max_length=32) # 出版社名称

	# xx = models.CharField(max_length=18,null=True,blank=True) # null=True,blank=True允许该字段数据为空
	xx = models.CharField(max_length=18,default="xxx")  #null=True,blank=True允许该字段数据为空

view.py

from django.shortcuts import render,HttpResponse,redirect
# 不同的应用创建不同的表
from booksys import models

# Create your views here.
def books(request):

	book_list = models.Book.objects.all()
	return render(request,'books.html',{'book_list':book_list})

def add_book(request):
	if request.method == 'GET':
		return render(request,'add_book.html')
	else:
		# request.POST是一个querydict类型,提供一个dict方法,把querydict转换成普通类型字典类型数据
		data = request.POST.dict()
		print(data)


		# print(request.POST)
		# title = request.POST.get('title')
		# price = request.POST.get('price')
		# pub_date = request.POST.get('pub_date')
		# publish = request.POST.get('publish')
		# print(title,title,pub_date,publish)

		# 关键字传参可以通过**打散的形式来传入
		ret = models.Book.objects.create(
			**data
			# title = title,
			# price = price,
			# pub_date = pub_date,
			# publish = publish,
		)
		return redirect('/books/')
		# return HttpResponse('ok')

def edit_book(request,book_id):
	if request.method == 'GET':
		old_obj = models.Book.objects.get(id=book_id)
		return  render(request,'edit_book.html',{'old_obj':old_obj})

	else:
		date = request.POST.dict()
		models.Book.objects.filter(id=book_id).update(
			**date
		)
		return redirect('/books/')

def del_book(request,book_id):
	models.Book.objects.get(id=book_id).delete()
	return redirect('/books/')

1.4 静态文件static

book目录下放的是css、img、js各种样式
plugins是引用的bootstrap文件

1.5 前端渲染模板template

add_book.html

{% extends 'base.html' %}

{% block content_title %}
    <h1>添加书籍</h1>
{% endblock %}

{% block content %}
    {#  如果action中没有写路径,就往获取当前页面下进行提交  #}
    <form action="" method="post">
        {# 写csrf_token可以通过后台的认证  #}
{#        {% csrf_token %}#}
        <div class="form-group">
            <label for="title">价格</label>
            <input type="text" class="form-control" id="title" placeholder="书籍名称" name="title">
        </div>
        <div class="form-group">
            <label for="price">价格</label>
            <input type="number" class="form-control" id="price" placeholder="价格" name="price">
        </div>
        <div class="form-group">
            <label for="pub_date">出版日期</label>
            <input type="date" class="form-control" id="pub_date" placeholder="出版日期" name="pub_date">
        </div>
        <div class="form-group">
            <label for="publish">出版社</label>
            <input type="text" class="form-control" id="publish" placeholder="出版社" name="publish">
        </div>
        {# button默认type属性就是submit,可以触发form表单。如果只想要给普通的按钮,那么type属性就写成button,不能提交form表单数据#}
        {#<button type="button" class="btn btn-default">Submit</button>#}
        <button type="submit" class="btn btn-success">Submit</button>
    </form>
{% endblock %}

base.html

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="{% static 'plugins/bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
    <meta name="viewport" content="width=device-width,initial-scale=1">
</head>
<body>

<div class="container">
    {% block content_title %}
        <h1 > 模板书籍 </h1>
    {% endblock %}

    <div class="row">
        <div class="col-md-8 col-md-offset-2">

                {% block content %}
                    模板内容
                {% endblock %}
        </div>
    </div>
</div>

</body>
<script src="{% static 'plugins/jquery.js' %}"></script>
<script src="{% static 'plugins/bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
</html>

books.html

{% extends 'base.html' %}

{% block content_title %}
    <h1>查看书籍</h1>
{% endblock %}

{% block content %}
    <a href="/add_book" class="btn btn-primary">添加书籍</a>
    <table class="table table-striped table-hover">
        <thead>
        <tr>
            <th>编号</th>
            <th>书籍名称</th>
            <th>价格</th>
            <th>出版日期</th>
            <th>出版社</th>
            <th>操作</th>

        </tr>
        </thead>
        <tbody>
        {% for book in book_list %}
            <tr>
                <td>{{ forloop.counter }}</td>
                <td>{{ book.title }}</td>
                <td>{{ book.price }}</td>
                <td>{{ book.pub_date | date:'Y-m-d' }}</td>
                <td>{{ book.publish }}</td>
                <td>
                    <a href="/edit_book/{{ book.id }}" class="btn btn-warning">编辑</a>
                    <a href="/del_book/{{ book.id }}" class="btn btn-danger">删除</a>
                </td>
            </tr>
        {% endfor %}
        </tbody>

    </table>
{% endblock %}

edit_book.html

{% extends 'base.html' %}

{% block content_title %}
    <h1>编辑书籍</h1>
{% endblock %}

{% block content %}
    {#  如果action中没有写路径,就往获取当前页面下进行提交  #}
    <form action="" method="post">
        {# 写csrf_token可以通过后台的认证  #}
{#        {% csrf_token %}#}
        <div class="form-group">
            <label for="title">价格</label>
            <input type="text" value="{{ old_obj.title }}" class="form-control" id="title" placeholder="书籍名称" name="title">
        </div>
        <div class="form-group">
            <label for="price">价格</label>
            <input type="number" value="{{ old_obj.price }}" class="form-control" id="price" placeholder="价格" name="price">
        </div>
        <div class="form-group">
            <label for="pub_date">出版日期</label>
            <input type="date" value="{{ old_obj.pub_date | date:"Y-m-d" }}" class="form-control" id="pub_date" placeholder="出版日期" name="pub_date">
        </div>
        <div class="form-group">
            <label for="publish">出版社</label>
            <input type="text" value="{{ old_obj.publish }}" class="form-control" id="publish" placeholder="出版社" name="publish">
        </div>
        {# button默认type属性就是submit,可以触发form表单。如果只想要给普通的按钮,那么type属性就写成button,不能提交form表单数据#}
        {#<button type="button" class="btn btn-default">Submit</button>#}
        <button type="submit" class="btn btn-success">Submit</button>
    </form>
{% endblock %}

2. 13个查询api接口

还记得表类.objects像是一个管理器,提供了增删改查的方法,Book.objects.all()获取所有的书籍,查询这里大家就掌握谁调用的下面的方法

<1> all():                  查询所有结果,结果是queryset类型
  
<2> filter(**kwargs):       它包含了与所给筛选条件相匹配的对象,结果也是queryset类型 Book.objects.filter(title='linux',price=100) #里面的多个条件用逗号分开,并且这几个条件必须都成立,是and的关系,or关系的我们后面再学,直接在这里写是搞不定or的
  
<3> get(**kwargs):          返回与所给筛选条件相匹配的对象,不是queryset类型,是行记录对象,返回结果有且只有一个,
                            如果符合筛选条件的对象超过一个或者没有都会抛出错误。捕获异常try。  Book.objects.get(id=1)
  
<4> exclude(**kwargs):      排除的意思,它包含了与所给筛选条件不匹配的对象,没有不等于的操作昂,用这个exclude,返回值是queryset类型 Book.objects.exclude(id=6),返回id不等于6的所有的对象,或者在queryset基础上调用,Book.objects.all().exclude(id=6)
                 
<5> order_by(*field):       queryset类型的数据来调用,对查询结果排序,默认是按照id来升序排列的,返回值还是queryset类型
                  models.Book.objects.all().order_by('price','id') #直接写price,默认是按照price升序排列,按照字段降序排列,就写个负号就行了order_by('-price'),order_by('price','id')是多条件排序,按照price进行升序,price相同的数据,按照id进行升序
        
<6> reverse():              queryset类型的数据来调用,对查询结果反向排序,返回值还是queryset类型
  
<7> count():                queryset类型的数据来调用,返回数据库中匹配查询(QuerySet)的对象数量。
  
<8> first():                queryset类型的数据来调用,返回第一条记录 Book.objects.all()[0] = Book.objects.all().first(),得到的都是model对象,不是queryset
  
<9> last():                queryset类型的数据来调用,返回最后一条记录
  
<10> exists():              queryset类型的数据来调用,如果QuerySet包含数据,就返回True,否则返回False
                   空的queryset类型数据也有布尔值TrueFalse,但是一般不用它来判断数据库里面是不是有数据,如果有大量的数据,你用它来判断,那么就需要查询出所有的数据,效率太差了,用count或者exits
                 例:all_books = models.Book.objects.all().exists() #翻译成的sql是SELECT (1) AS `a` FROM `app01_book` LIMIT 1,就是通过limit 1,取一条来看看是不是有数据

<11> values(*field):        用的比较多,queryset类型的数据来调用,返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列
                            model的实例化对象,而是一个可迭代的字典序列,只要是返回的queryset类型,就可以继续链式调用queryset类型的其他的查找方法,其他方法也是一样的。
<12> values_list(*field):   它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
 
<13> distinct():            values和values_list得到的queryset类型的数据来调用,从返回结果中剔除重复纪录

举例子:

# 127.0.0.1:8000/query
from django.shortcuts import render,HttpResponse
from app01 import models
import datetime
# Create your views here.
def query(request):
	# exclude排除
	# 返回结果为queryset类型数据,通过objects控制器可以调用,queryset类型数据也能调用
	# obj_list = models.Book.objects.exclude(id=2)
	# obj_list = obj_list.filter(title='少年1')
	# obj_list = obj_list.all()
	# obj_list = models.Book.objects.exclude(id=2).filter(title__contains='少年').exclude(id=5)

	# order_by 排序
	# 返回结果为queryset类型数据,queryset类型数据可以调用这个方法
	# obj_list = models.Book.objects.all().order_by('-id')   #-id加个-号表示按照该字段降序排列, desc  asc
	# '''select * from app01_book order by id desc;'''
	# obj_list = models.Book.objects.all().order_by('price', '-id') #按照价格升序排列,价格相同的按照id降序排列

	# reverse()
	# 翻转必须在排序数据的基础上
	# 返回结果为queryset类型数据,queryset类型数据可以调用这个方法
	# obj_list = models.Book.objects.all().order_by('-id').reverse()

	# count
	# queryset类型数据可以调用这个方法,返回值为数字
	# obj_list = models.Book.objects.all().count()

	# first\last
	# queryset类型数据可以调用这个方法,返回值为模型类对象
	# obj_list = models.Book.objects.all().first()
	# obj_list = models.Book.objects.all()[0]
	# obj_list = models.Book.objects.all().last()

	# exists
	# 判断查询结果是有数据
	# queryset类型数据可以调用这个方法
	# obj_list = models.Book.objects.all().exists()  #判断是否有数据的效率高,只找一条记录 limit 1


	# values
	# 可以获取指定字段数据
	# objects可以调用, queryset也能调用,返回结果还是queryset,内容为一个个字典数据
	# obj_list = models.Book.objects.values('title', 'price')
	# obj_list = models.Book.objects.filter(id=5).values('title', 'price')

	# values_list
	# 可以获取指定字段数据,返回结果还是queryset,内容为一个个元组数据
	# obj_list = models.Book.objects.values_list('title', 'price')
	# obj_list = models.Book.objects.filter(id=5).values_list('title', 'price')

	# distinct 去重
	# 一般配合values和values_list来使用
	# distinct 去重的是整条记录,整条记录重复才是重复,要指定去重的字段才有意义
	obj_list = models.Book.objects.values('price').distinct()

	print(obj_list)
	return HttpResponse('ok')

小提示: 有queryset方法大全,可以进行查看

3. 表关系设计

from django.db import models

# Create your models here.


# 作者表
class Author(models.Model):
	name = models.CharField( max_length=32)
	age = models.IntegerField()

	# django2.x版本必须手动指定on_delete=models.CASCADE级联模式
	# au = models.OneToOneField(to="AuthorDetail", to_field="id", on_delete=models.CASCADE)
	# au = models.OneToOneField("AuthorDetail")
	# au = models.IntegerField()
	au = models.OneToOneField("AuthorDetail", db_constraint=False)
	# db_constraint=False取消foreign key的强制约束效果,还可以继续使用orm的提供的属性或者方法来操作关系记录
	# foreign key + unique

# 属性是OneToOneField或者ForeignKey,那么生成的对应字段是  属性名称_id

#作者详细信息表
class AuthorDetail(models.Model):
	birthday=models.DateField()
	telephone=models.BigIntegerField()
	addr=models.CharField(max_length=64)

# 出版社表
class Publish(models.Model):
	name=models.CharField( max_length=32)
	city=models.CharField( max_length=32)


#书籍表
class Book(models.Model):

	title = models.CharField( max_length=32)
	publishDate=models.DateField()
	price=models.DecimalField(max_digits=5,decimal_places=2)

	# publishs=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE)
	publishs=models.ForeignKey("Publish")
	authors = models.ManyToManyField('Author')


# class authortobook(models.Model):
# 	book_id = models.ForeignKey('Book')
# 	author_id = models.ForeignKey('Author')

4. 级联解释

举例子来说明表设计(下面的表操作都是按照下面的例子来看):
作者和作者详细信息是一对一关系(在哪个表写关联关系都可以,这里写到了作者里面)
解释:如果写在作者表这块,如果删除作者详情里的表记录并且关联了作者表,则都会删除。如果删除作者表,则不会删除作者信息表。
          通俗理解,作者表抱着作者详情表的大腿,详情表的记录没了,关联作者表的内容也没了。作者表记录没了,不会影响作者详细表内容。
          提示:OneToOneField生成的字段是属性名称_id

书籍表和出版社表是多对一关系(在多的那张表写关联关系,这里写到了书籍表中)
提示:ForeignKey属性生成的字段是属性名称_id,删除书不影响出版社,因为书籍表中有外键

书籍表和作者表是多对多关系(在哪个表写关联关系在都可以,这里写到了书籍表中)
解释:authors = models.ManyToManyField('Author')不会在当前表(Book)创建author字段,而是会自动创建一张新表app01_book_authors(名字组成应用名称+模型类小写+关联关系属性), 删除作者表和书籍表中的内容只会对第三表产生影响,因为自动生成的表中的foreignkey都指向book、author表,book和author不会相互影响。
          app01_book_authors中有id、book_id、author_id, 而且authors这个字段还可以操控自动生成的第三张表

foreignKey强制约束效果很麻烦,比较恶劣

没有强制约束的效果的方法(删除不会影响对方,但是还要有关联的关系字段):
1. au = models.integerField()
    这种不能使用orm提供的级联方法
 
2. au = models.OneToOneField("AuthorDetail",db_constraint=False)  
    db_constraint=False这个属性的作用:取消foreignkey的强制约束效果,和AuthorDetail建立的级联关系,可以继续使用orm给
    我们提供的关联表查询或操作的各种方法,没有强制约束效果
    使用级联方法:author.obj.au.birthday 拿到当前表的对象,然后.au级联关系,然后就可以拿到关联表的属性了。

5. 多表关系记录的添加

增加

from django.shortcuts import render,HttpResponse
from app01 import models
def query(request):
	# 增
	# 一对一关系的添加
	# 先创建作者详细信息表记录
	# ret = models.AuthorDetail.objects.create(
	# 	birthday='2000-12-12',
	# 	telephone='122',
	# 	addr='惠州',
	# )
	#
	#
	# models.Author.objects.create(
	# 	name='元涛',
	# 	age=18,
	## 第一种写法
	# 	# au_id=ret.id,  #如果用的是属性名称_id,那么值为关联记录的id值
	## 第二种写法
	# 	au=ret,  #如果写属性名称来添加关系数据,那么值为关联记录的模型类对象
	# )


	# 一对多(publish表记录是提前加好了)
	# pub_obj = models.Publish.objects.get(id=1)

	# models.Book.objects.create(
	# 	title='白洁2',
	# 	price=10,
	# 	publishDate='1980-07-07',
	## 第一种写法
	# 	# publishs=pub_obj, #如果写属性名称来添加关系数据,那么值为关联记录的模型类对象
	##  第二种写法
	# 	publishs_id=2, #如果用的是属性名称_id,那么值为关联记录的id值
	#
	# )

	# 多对多

	# book_obj = models.Book.objects.get(title='白夜行')
	# author1 = models.Author.objects.get(id=1)
	# author2 = models.Author.objects.get(id=2)

	## 第一种写法
	# book_obj.authors.add(author1,author2)
	
	## 第二种写法
	# book_obj.authors.add(1, 2)
	# book_obj.authors.add(*[1,2])
    return HttpRequest('ok')

6. 小提示和小练习

小提示:

1. pycharm默认只能给你创建一个应用,后面的只能用指令操作
2. 在Tools点击Run manage.py Task,这样就可以简单的输入命令了
startapp booksys
3. 应用和项目关联起来,在settings中添加一个应用
4. 自己的应用创建自己的表
5. 如果action什么都没有写,post请求就是忘当前路径上发
6. updata方法只能queryset类型数据调用
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值