Django中ORM系统多表数据操作

一,多表操作之增删改查

1.在seting.py文件中配置数据库连接信息

2.创建数据库关联关系models.py

from django.db import models
# Create your models here.
class Book(models.Model):
    title = models.CharField( max_length=32)
    pub_date=models.DateField()
    price=models.DecimalField(max_digits=5,decimal_places=2)
  #以book表为基本表创建与出版社表的关联关系关联字段publish_id Django会自动拼接_id publish
=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE,null=True)
  #以book表为基本表创建通过与第三方表book2author与author表的多对多关联关系, authors
=models.ManyToManyField("Author",db_table="book2authors") # 创建关系表 def __str__(self): return self.title class Publish(models.Model): name=models.CharField( max_length=32) city=models.CharField( max_length=32) email=models.CharField(max_length=32) def __str__(self): return self.name class Author(models.Model): name=models.CharField( max_length=32) age=models.IntegerField() #books=models.ManyToManyField("Book")

  #以author表为基本表通过创建ad字段关联AuthorDetail作者详情表的一对一的关联关系 ad=models.OneToOneField("AuthorDetail",null=True,on_delete=models.CASCADE) def __str__(self): return self.name class AuthorDetail(models.Model): birthday=models.DateField() telephone=models.BigIntegerField() addr=models.CharField( max_length=64) # author=models.OneToOneField("Author",on_delete=models.CASCADE) def __str__(self): return str(self.telephone) ''' class book_authors(models.Model): book=models.ForeignKey("Book",on_delete=models.CASCADE) author=models.ForeignKey("Author",on_delete=models.CASCADE) ''' class Emp(models.Model): name=models.CharField(max_length=32) age=models.IntegerField() salary=models.DecimalField(max_digits=8,decimal_places=2) dep=models.CharField(max_length=32) province=models.CharField(max_length=32) class Article(models.Model): title=models.CharField(max_length=32) comment_num=models.IntegerField() poll_num=models.IntegerField() def __str__(self):return self.title

3 在启动函数时,在项目文件setiing.py文件中配置相应的库

4 在url分发器中配置网页与视图函数的映射关系

5 在视图函数views.py中封装对数据库操作的功能,

from django.shortcuts import render,HttpResponse,redirect

# Create your views here.
from app01 import models

def add(request):

    ################################## 绑定一对多关系 ##############################
    # 方式1:
    #book=models.Book.objects.create(title="linux",price=122,pub_date="2012-12-12",publish_id=1)

    # 方式2:
    # pub_obj=models.Publish.objects.filter(name="橘子出版社").first()
    # book=models.Book.objects.create(title="php",price=122,pub_date="2012-12-12",publish=pub_obj)
    # print(book.title)
    # print(book.publish_id)
    # print(book.publish) # book书籍出版社对象
    # 查询go出版社的邮箱
    # models.Publish.objects.filter(id= book.publish_id).first().email
    # book.publish.email

    ########################## 绑定多对多的关系;无非是在关系表创建记录 ##########

    # linux这本书绑定两个作者:alex,egon
    # linux=models.Book.objects.filter(title="linux").first()
    # alex=models.Author.objects.filter(name="alex").first()
    # egon=models.Author.objects.filter(name="egon").first()
    # print(linux.price)
    # print(linux.publish)
    #linux.authors.add(alex,egon)
    #linux.authors.add(1)
    #linux.authors.add(*[1,2])
    #linux.authors.remove(alex,egon)
    #linux.authors.clear()
    #linux.authors.set([1,])

    '''
    #KEY:关联属性:authors
    class Book(models.Model):
            title = models.CharField( max_length=32)
            pub_date=models.DateField()
            price=models.DecimalField(max_digits=5,decimal_places=2)
            publish=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE,null=True)
            authors=models.ManyToManyField("Author",db_table="book2authors") # 创建关系表
            def __str__(self):
                return self.title
    '''

    ###############
    # 正向操作按字段,反向操作按表名小写

    linux = models.Book.objects.filter(title="linux").first()
    go = models.Book.objects.filter(title="go").first()
    alex = models.Author.objects.filter(name="alex").first()
    # 给alex作者绑定两本书籍: linux,go
    alex.book_set.add(linux,go)

    return HttpResponse("添加成功!")

def query(request):
    '''
    一 基于对象的跨表查询( 子查询:以上一次的查询结果作为下一次的查询条件)
       (1)一对多
                         正向查询:按字段 book.publish
         Book对象    ---------------------------------- >  Publish 对象
                      <---------------------------------
                        反向查询:按表名小写_set.all()


        (2)多对多
                       正向查询:按字段 book.authors.all()
         Book对象    ---------------------------------- >  Author 对象
                      <---------------------------------
                        反向查询:按表名小写_set.all()


        (2)一对一
                        正向查询:按字段 book.ad
         Author 对象   ---------------------------------- >  AuthorDetail 对象
                      <---------------------------------
                        反向查询:按表名小写

    二 基于双下划綫的跨表查询:

       KEY:通知ORM引擎如何跨表: 正向查询按字段,反向查询按表名小写

    :param request:
    :return:
    '''
    重点1############一基于对象的跨表查询#######################
    #(1)一对多

    # 1 查询linux这本书籍的出版社的地址
    # book=models.Book.objects.filter(title="linux").first()
    # print(book.publish.city)
    # 2 查询苹果出版社出版的所有书籍
    # publish=models.Publish.objects.filter(name="苹果出版社").first()
    # queryset=publish.book_set.all()
    # print(queryset) # <QuerySet [<Book: linux>, <Book: python>]>


    # (2)多对多

    # 1 查询linux书籍的所有作者
    # linux=models.Book.objects.filter(title="linux").first()
    # queryset=linux.authors.all() # <QuerySet [<Author: alex>]>
    # print(queryset)
    # 2 查询alex作者出版过得所有书籍
    # alex=models.Author.objects.filter(name="alex").first()
    # queryset=alex.book_set.all()
    # print(queryset) # <QuerySet [<Book: linux>, <Book: go>]>

   # (3)一对一
    # 1  查询alex的手机号
    # alex = models.Author.objects.filter(name="alex").first()
    # print(alex.ad.telephone)

    # 2 查询手机号为911的作者的名字
    # ad=models.AuthorDetail.objects.filter(telephone=911).first()
    # print(ad.author.name)
    重点2###基于双下划线的跨表查询(join查询)#################################
    # 1 查询linux这本书籍的出版社的地址
    '''
    SELECT app01_publish.city from app01_book INNER JOIN app01_publish 
                                  ON app01_book.publish_id = app01_publish.id 
                                  WHERE app01_book.title ="linux"
    
    '''
    # 方式1
    # queryset=models .Book.objects.filter(title="linux").values("price","publish__city")
    # print(queryset)
    # # 方式2
    # queryset=models.Publish.objects.filter(book__title="linux").values("city")
    # print(queryset)

    # 2 查询linux书籍的所有作者
    #queryset=models.Book.objects.filter(title="linux").values("authors__name")
    #queryset=models.Book.objects.filter(title__startswith="l").values("authors__name") # ********
    #print(queryset) # <QuerySet [{'authors__name': 'alex'}, {'authors__name': 'alex'}, {'authors__name': 'egon'}]>

    # queryset=models.Author.objects.filter(book__title="linux").values("name")

    # 3  查询alex的手机号

    # queryset=models.Author.objects.filter(name="alex").values("ad__telephone")
    # queryset=models.AuthorDetail.objects.filter(author__name="alex").values("telephone")
    # print(queryset) # <QuerySet [{'telephone': 110}]>

    # 重点3  连续跨表
    # 4 查询人民出版社出版过的所有书籍的名字以及作者的姓名
    # queryset=models.Book.objects.filter(publish__name="人民出版社").values("title","authors__name")
    # models.Author.objects.filter(book__publish__name="人民出版社").values("book__title","name")
    # 5 手机号以151开头的作者出版过的所有书籍名称以及出版社名称
    queryset=models.Book.objects.filter(authors__ad__telephone__contains="1").values("title","publish__name")
    print(queryset)
    return HttpResponse("查询成功!")
    重点4:###################### 分组查询 #####################################

    # 单表分组查询

    #queryset=models.Emp.objects.all() # select * from emp
    # queryset=models.Emp.objects.values("name") # select name from emp;
    # print(queryset)

    '''
    单表分组查询:
    #查询每一个部门名称以及对应的员工数
    
    sql:
        select dep,Count(*) from emp group by dep;        
        select dep,AVG(salary) from emp group by dep;
        
    orm:
        queryset=models.Emp.objects.values("dep").annotate(c=Count("*"))
    '''
    from django.db.models import Avg,Count,Max,Min

    # 查询每一个部门的人数
   #  queryset=models.Emp.objects.values("dep").annotate(c=Count("*"))
   #  print(queryset)  # <QuerySet [{'dep': '销售部', 'c': 1}, {'dep': '人事部', 'c': 2}]>
   #
   # # 查询每一个省份的平均薪水
   #  queryset=models.Emp.objects.values("province").annotate(avg_salary=Avg("salary"))
   #  print(queryset) # <QuerySet [{'province': '山东', 'avg_salary': 4500.0}, {'province': '河北', 'avg_salary': 5000.0}]>

    ############### 多表分组查询
    # 1 查询每一个出版社的名字和出版过的书籍的平均价格
    '''
       
        -- sql语句:
        SELECT app01_publish.name,AVG(app01_book.price) from app01_book LEFT JOIN app01_publish on 
                                 app01_book.publish_id = app01_publish.id
                                 group by app01_publish.id,app01_publish.name
    '''

    # queryset=models.Publish.objects.values("id","name").annotate(avg_price=Avg("book__price"))
    # queryset=models.Publish.objects.values("id","name","email","city").annotate(avg_price=Avg("book__price"))
   #打印结果
# [{"id":1,"name":"苹果出版社","eamil":"123","city":"beijing",'avg_price': 119.0},
  {"id":1,"name":"橘子出版社","eamil":"123","city":"beijing",'avg_price': 155.333333.0}]
# queryset=models.Publish.objects.all().annotate(avg_price=Avg("book__price")) # print(queryset) #<QuerySet [<Publish: 苹果出版社>, <Publish: 橘子出版社>]> # for obj in queryset: # print(obj.name,obj.avg_price) # 2 查询每一个作者的名字以及出版书籍的个数 queryset=models.Author.objects.annotate(c=Count("book")).values("name","c") print(queryset) # <QuerySet [{'name': 'alex', 'c': 2}, {'name': 'egon', 'c': 2}]> # 3 查询每一个书籍的名称以及作者的个数 queryset=models.Book.objects.annotate(c=Count("authors")).values("title","c") print(queryset) # 4 查询作者个数大于1 的每一本书籍的名称和作者个数 queryset=models.Book.objects.annotate(c=Count("authors")).filter(c__gt=1).values("title","c") print(queryset) # <QuerySet [{'title': 'python', 'c': 2}, {'title': 'go', 'c': 2}]> # 5 查询书籍名称包含"h"的书籍名称和作者个数 queryset=models.Book.objects.filter(title__contains="h").annotate(c=Count("authors")).values("title","c") 重点5############# F查询与Q查询 # F查询 from django.db.models import F,Q,Avg # 1 查询评论数大于100的文章 # queryset=models.Article.objects.filter(comment_num__gt=100) # print(queryset) # 2 查询评论数大于点赞数的文章 # queryset=models.Article.objects.filter(comment_num__gt=F("poll_num")) # print(queryset) # <QuerySet [<Article: 那一夜>]> # 3 查询点赞数大于两倍评论数 # queryset=models.Article.objects.filter(poll_num__gt=F("comment_num")*2) # print(queryset) # <QuerySet [<Article: 那一天>]> # 4 将所有的书籍的价格提高100元 # models.Book.objects.all().update(price=F("price")+100) # Q查询 # 5 查询价格大于300或者名称以p开头的书籍 # Q : & | ~ # queryset=models.Book.objects.filter(Q(title__startswith="p")&Q(price__gt=300)) # print(queryset) # <QuerySet [<Book: python>, <Book: php>, <Book: pJS>]> # # 5 查询价格大于300或者不是2019年一月份的书籍 # lq=Q(price__gt=300)|~Q(Q(pub_date__year=2019)&Q(pub_date__month=1)) queryset = models.Book.objects.filter(q) # print(queryset)

6 刷新网页来测试数据库相关功能

实例1ORM 多表关联图书管理系统

第一步 创建项目,先创建模型对数据库进行操作
    并配置数据库信息
1 创建表
from django.db import models

# Create your models here.
class Book(models.Model):
    title = models.CharField( max_length=32)
    pub_date=models.DateField()
    price=models.DecimalField(max_digits=5,decimal_places=2)
    #以Book表为基本表创建与Publish表的外键关联关系关联字段publish_id Django自动拼接_id,on_delete=models.CASCADE:级联删除
    publish=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE,null=True)
    #以Book表为基本表创建第三方表book2authors与Author表建立多对多的关联关系
    authors=models.ManyToManyField("Author",db_table="book2authors") # 创建关系表
    def __str__(self):
        return self.title

class Publish(models.Model):
    name=models.CharField( max_length=32)
    city=models.CharField( max_length=32)
    email=models.CharField(max_length=32)
    def __str__(self):
        return self.name

class Author(models.Model):
    name=models.CharField( max_length=32)
    age=models.IntegerField()
    #books=models.ManyToManyField("Book")
    #以作者表Author为基本表创建与作者详情表AuthorDetail的一对一的关联关系
    ad=models.OneToOneField("AuthorDetail",null=True,on_delete=models.CASCADE) 
    def __str__(self):
        return self.name
class AuthorDetail(models.Model):
    birthday=models.DateField()
    telephone=models.BigIntegerField()
    addr=models.CharField( max_length=64)
    # author=models.OneToOneField("Author",on_delete=models.CASCADE)
    def __str__(self):
        return str(self.telephone)
models.py

   2 配置数据库信息

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME':'duo', # 要连接的数据库,连接前需要创建好
        'USER':'root', # 连接数据库的用户名
        'PASSWORD':'123', # 连接数据库的密码
        'HOST':'127.0.0.1', # 连接主机,默认本级
        'PORT':3306  #  端口 默认3306
    },
}
seting.py
3 启动项目:通过模型在目标数据库中创建相应的表,
#注意:在建表之前必须先创建好seting.py文件中mysql配置的库
在建表之前要在url.py路由分发的同级目录下的启动文件__init__.py中导入
import pymysql
pymysql.install_as_MySQLdb()

然后在项目路径文件下执行以下命令在mysql中创建表
python manage.py makemigrations
python manage.py migrate
引入pymysql
第二步 创建URL与该URL调用的视图函数之间的映射表
from django.contrib import admin
from django.urls import path,re_path
from duo_books import views


urlpatterns = [
    path('admin/', admin.site.urls),
    path('add/', views.add),
    path('query/', views.query),
    path('books/', views.books),
    path('books/add/', views.addbook),
    re_path('books/delete/(\d+)/', views.delbook),
    re_path('books/edit/(\d+)/', views.editbook),
urls.py
第三步 创建视图函数中对数据的操作进行封装
def books(request):
    queryset = models.Book.objects.all()

    return render(request, "books.html", {"queryset": queryset})


def delbook(request, id):
    models.Book.objects.filter(pk=id).delete()

    return redirect("/books/")


def addbook(request):
    if request.method == "POST":

        data = request.POST.dict()
        data.pop("csrfmiddlewaretoken")
        data.pop("author_list")
        book = models.Book.objects.create(**data)  # 保证提交键值对的键必须和数据库表字段一致
        #  为书籍绑定作者关系
        author_list = request.POST.getlist("author_list")
        print(author_list)  # ['1', '2']
        book.authors.add(*author_list)

        return redirect("/books/")
    else:

        publish_list = models.Publish.objects.all()
        author_list = models.Author.objects.all()
        return render(request, 'addbook.html', locals())
def editbook(request,edit_book_id):
    edit_book = models.Book.objects.filter(pk=edit_book_id).first()
    if request.method=="POST":
        # 方式1:
        # title=request.POST.get("title")
        # price=request.POST.get("price")
        # pub_date=request.POST.get("pub_date")
        # publish_id=request.POST.get("publish_id")
        # author_list=request.POST.getlist("author_list")
        # models.Book.objects.filter(pk=edit_book_id).update(title=title,price=price,pub_date=pub_date,publish_id=publish_id)  # update只有queryset才能调用
        # edit_book.authors.set(author_list)

        #  方式2:

        data=request.POST.dict()
        data.pop("csrfmiddlewaretoken")
        author_list=data.pop("author_list")
        models.Book.objects.filter(pk=edit_book_id).update(**data)  #  保证提交键值对的键必须和数据库表字段一致
        #  为书籍绑定作者关系
        author_list=request.POST.getlist("author_list")
        edit_book.authors.set(author_list)

        return redirect("/books/")
    else:

        publish_list=models.Publish.objects.all()
        author_list=models.Author.objects.all()
        return render(request,'editbook.html',locals())
views.py
第四步 创建静态文件夹static放置Jquery,css,bootstrap样式文件
修改Django配置,完成对静态文件的配置
STATIC_URL = '/static/'
STATICFILES_DIRS=[
    os.path.join(BASE_DIR,"static") #  静态文件的物理路径
]
seting.py


第五步 在模板文件夹template下建立相应的前端页面

添加功能页面
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
   <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
</head>
<body>
<h3>添加书籍</h3>
<div class="row">
    <div class="col-md-4 col-md-offset-3">
        <form action="/books/add/" method="post">
            {% csrf_token %}
            <div class="form-group">
                <label for="title">书籍名称</label>
                <input class="form-control" type="text" id="title" placeholder="名称" name="title">
            </div>
            <div class="form-group">
                <label for="price"> 价格</label>
                <input class="form-control" type="text" id="price" placeholder="价格" name="price">
            </div>
             <div class="form-group">
                <label for="pub_date">出版日期</label>
                <input class="form-control" type="date" id="pub_date" placeholder="出版日期" name="pub_date">
            </div>
            <div class="form-group">
                <label for="publish_id">出版社</label>
                <select class="form-control" name="publish_id" id="">
                    {% for publish in publish_list %}
                        <option value="{{ publish.pk }}">{{ publish.name }}</option>
                    {% endfor %}

                </select>
            </div>
              <div class="form-group">
                <label for="author">作者</label>
                <select class="form-control" name="author_list" id="author" multiple>
                    {% for author in author_list %}
                        <option value="{{ author.pk }}">{{ author.name }}</option>
                    {% endfor %}

                </select>
            </div>
           
            <input type="submit"value="submit" class="btn btn-default pull-right">
        </form>
    </div>
</div>

</body>
</html>
addbook.html
 查看功能页面(含删除功能)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="/static/jquery-3.1.js"></script>
    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
<link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
</head>
<body>

<h3>书籍列表</h3>

<div class="row">
    <div class="col-md-8 col-md-offset-2">
        <a href="/books/add/" class="btn btn-primary"> 添加书籍</a>
        <table class="table table-striped table-hover">
            <thead>
            <tr>
                <th>ID</th>
                <th>书籍名称</th>
                <th>价格</th>
                <th>出版社</th>
                <th>出版日期</th>
                <th>作者</th>
                <th>操作</th>
            </tr>
            </thead>
            <tbody>
                {% for book in queryset %}
                <tr>
                     <td>{{ forloop.counter }}</td>
                     <td>{{ book.title }}</td>
                     <td>{{ book.price }}</td>
                     <td>{{ book.publish }}</td>
                     <td>{{ book.pub_date|date:"Y/m/d" }}</td>
                     <td>
                         {% for author in book.authors.all %}
                         <span>{{ author.name }}</span>
                         {% endfor %}

                     </td>
                     <td>
                         <a href="/books/delete/{{ book.pk }}">删除</a>
                         <a href="/books/edit/{{ book.pk }}">编辑</a>
                     </td>
                </tr>
                {% endfor %}

            </tbody>
        </table>
    </div>
</div>


<script>
     $("h3").click(function () {
         $(this).css("color","red")
     })
</script>

</body>
</html>
books.html

   编辑功能的页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
   <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<h3>编辑书籍</h3>
<div class="row">
    <div class="col-md-4 col-md-offset-3">
        <form action="" method="post">
            {% csrf_token %}
            <div class="form-group">
                <label for="title">书籍名称</label>
                <input class="form-control" type="text" id="title" placeholder="名称" name="title" value="{{ edit_book.title }}">
            </div>
            <div class="form-group">
                <label for="price"> 价格</label>
                <input class="form-control" type="text" id="price" placeholder="价格" name="price" value="{{ edit_book.price }}">
            </div>
             <div class="form-group">
                <label for="pub_date">出版日期</label>
                <input class="form-control" type="date" id="pub_date" placeholder="出版日期" name="pub_date" value="{{ edit_book.pub_date|date:'Y-m-d' }}">
            </div>
            <div class="form-group">
                <label for="publish_id">出版社</label>
                <select class="form-control" name="publish_id" id="">
                    {% for publish in publish_list %}
                        {% if publish == edit_book.publish %}
                        <option selected value="{{ publish.pk }}">{{ publish.name }}</option>
                        {% else %}
                        <option value="{{ publish.pk }}">{{ publish.name }}</option>
                        {% endif %}
                    {% endfor %}

                </select>
            </div>
              <div class="form-group">
                <label for="author">作者</label>
                <select class="form-control" name="author_list" id="author" multiple>
                    {% for author in author_list %}
                        {% if author in edit_book.authors.all %}
                          <option selected value="{{ author.pk }}">{{ author.name }}</option>
                        {% else %}
                          <option value="{{ author.pk }}">{{ author.name }}</option>
                        {% endif %}

                    {% endfor %}

                </select>
            </div>
           
            <input type="submit"value="submit" class="btn btn-default pull-right">
        </form>
    </div>
</div>

</body>
</html>
editbook.html

 

posted @ 2019-01-04 15:49  传盛  阅读(532)  评论(0编辑  收藏  举报