django -- ORM实现出版社增删改查

前戏

我们来完成一个图书管理系统的增删改查

表结构设计

1. 出版社
  id   name
2. 作者
  id  name
3. 书
  id  title  出版社_id
4. 作者_书_关系表
  id  书_id  作者_id

创建表

现在有个需求,当我们访问http://127.0.0.1:8080/press_list/这个网址时,django给我们返回所有的出版社名称,我们可以在models里创建一个press的类来生成数据表

class Press(models.Model):
    id = models.AutoField(primary_key=True)  # id主键
    name = models.CharField(max_length=32)  # 出版社名称

然后再Terminal里执行下面的两句代码:

python manage.py makemigrations
python manage.py migrate

然后我们去往数据库里手动插入几条数据,添加好了之后我们该干什么了呢?想一想我上篇文章写的和上上篇文章写的,我们在浏览器访问上面的url是不是django先去url.py里去找这个路径,那我们就去url.py里添加一个

url(r'^press_list/', views.press_list),

添加好了,这个函数是不是还没有,那在去views里添加一个press_list的函数,记得导入这个类

def press_list(request):
    ret = Press.objects.all()  # 查询所有的出版社
    print(ret)
    return HttpResponse('ok')

结果

<QuerySet [<Press: Press object>, <Press: Press object>, <Press: Press object>]>

打印出来的是一个对象,大家在学面向对象的时候记不记得有个魔术方法__str__,通常用法是把对象的值打印出来,我们在去Press类里添加下面的代码

# __str__ 如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。

class Foo(object):

    def __str__(self):
        return 'zouzou'

    def eat(self):
        print('we are eating...')

obj = Foo()
print(obj)

结果:zouzou
不会__str__方法的看这里
class Press(models.Model):
    id = models.AutoField(primary_key=True)  # id主键
    name = models.CharField(max_length=32)  # 出版社名称

    def __str__(self):
        return self.name  

注意:

添加完__str__方法后不需要执行那两行命令,因为__str__方法对数据库没有影响

然后我们重新访问一下刚才的网站,看一下ret的值

<QuerySet [<Press: 清华出版社>, <Press: 北大出版社>, <Press: 复旦出版社>]>

这样就打印出了我们的出版社名称,结合上篇的ret[0].name就可以取到第一个值

print(ret[0].name)
print(ret[1].name)
print(ret[2].name)

这样我们就取到了三个出版社的名称,现在出版社的名称取到了,我们要给返回一个press_list的页面,而不是一个ok,在来改一下press_list的函数

def press_list(request):
    ret = Press.objects.all()  # 查询所有的出版社

    return render(request,'press_list.html',{'ret':ret})

之前学了查询某个字段的值:

User.objects.filter(email=ema,pwd=password)

如果要查询所有的值用all

User.objects.all()

上面的{'ret':ret})在上篇里说过,是django的模版语言,上次是传了一个固定的值,这次我们是传了一个对象,里面暂时有三个值

创建html文件

函数有了,是不是差个press_list.html的文件,在去templates下新增一个press_list.html的文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <table border="1">
        <thead>
            <th>id</th>
            <th>名称</th>
        </thead>
        <tbody>
            {% for i in ret %}
                <tr>
                    <td>{{ i.id}}</td>
                    <td>{{ i.name }}</td>
                </tr>
            {% endfor %}
        </tbody>

    </table>

</body>
</html>
press_list.html

代码解释:

{% for i in ret %}
      <tr>
         <td>{{ i.id}}</td>
         <td>{{ i.name }}</td>
     </tr>
{% endfor %}

这是django的模版语言里for循环的用法,之前我们是返回了一个值,用{{变量名}},现在我们是要取到所有的出版社,所以要用for循环,和python里的for循环一样,以{% for i in ret %}开始,以{% endfor %}结束,中间还是用{{变量名}}的方法取值

现在我们都已经配置好了,在去访问一下网址看看效果

我们在数据库里在加一条数据,也能展示在页面上,这样我们就完成了我们需要的功能

用ORM往数据库里新增数据

上面我们的数据都是我们手动在数据库里添加的,那怎么使用ORM往数据库里添加数据呢?使用

User.objects.create(name=value)

就可以往数据库里插入数据了,和上面的分析一样,先去url.py加上路由

url(r'^add_press/', views.add_press),

在去views里添加add_press函数

# 添加出版社的处理函数
def add_press(request):
    if request.method == 'POST':  # 表示用户要发数据
        name = request.POST.get('name')  # 获取用户填的出版社数据
        Press.objects.create(name=name)  # 将数据添加到数据库中
        return redirect('/press_list/')  # 跳转到出版社列表页面
    
    return render(request,'add_press.html')  # 表示获取页面

在去创建一个新增数据的html文件叫add_press.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/add_press/" method="post">
        <input type="text" name="name">
        <input type="submit">
    </form>

</body>
</html>

接下来我们访问http://127.0.0.1:8080/add_press/就可以实现在页面上往数据库里添加数据的功能了

用ORM从数据库里删除数据

我们已经完成了一个很low的往数据库里新增数据的功能,现在来完成一个删除的功能

分析:

删除数据我们根据什么来删,前面设计表的时候因为id是主键,所以我们可以根据id去删除数据,那么问题就来了,我们是不是要有一个删除的按钮。我们删除了数据之后,id是不是就不是按照顺序往上增加了,是不是要在前面加一个序号,删除之后序号也跟着改变呢。然后我们查询到数据,使用ORM里的方法删除数据

表名.objects.filter('列名').delete()

先去修改press_list.html的代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<a href="/add_press/">添加出版社</a>
    <table border="1">
        <thead>
            <th>序号</th>
            <th>id</th>
            <th>名称</th>
            <th>操作</th>
        </thead>
        <tbody>
            {% for i in ret %}
                <tr>
                    <td >{{ forloop.counter }}</td>  <!--循环,从1开始,每次加1-->
                    <td>{{ i.id}}</td>
                    <td>{{ i.name }}</td>
                    <td><a href="/delete_press/?id={{ i.id}}">删除</a></td>

                </tr>
            {% endfor %}
        </tbody>

    </table>

</body>
</html>

代码解释:

<td >{{ forloop.counter }}</td>  for循环,从1开始,如果想从0开始,则<td >{{ forloop.counter0 }}</td>
<td><a href="/delete_press/?id={{ i.id}}">删除</a></td> 我们可以通过url访问,当点击删除的时候,浏览器会往服务器发送一个url地址:http://127.0.0.1:8080/delete_press/?id=XX的网址。

然后我们去添加路由
url(r'^delete_press/', views.delete_press),  # 删除出版社

在去添加对应的函数

# 删除出版社
def delete_press(request):
    delete_id = request.GET.get('id')
    Press.objects.filter(id=delete_id).delete()
    return redirect('/press_list/')

这样当我们点击删除时,会删除掉对应的数据,并且重新访问press_list网页

Press.objects.filter(id=delete_id).delete()先查询数据,然后删除

用ORM从数据库里更改数据

先添加一个路由

url(r'^edit_press/', views.edit_press),  # 编辑出版社

这里有两种方法可以实现编辑

第一种方法

先去添加一个函数

#编辑出版社
def edit_press(request):
    if request.method=='POST':
        #取出用户点击编辑之后的数据
        edit_id = request.POST.get('id')
        new_name = request.POST.get('name')
        #去数据库修改对应的数据,先查询,在修改,在保存到数据库
        edit_press_obj = Press.objects.get(id=edit_id)
        edit_press_obj.name = new_name
        edit_press_obj.save()
        #让用户再次访问列表页面
        return redirect('/press_list/')

    #获取要编辑的出版社
    edit_id = request.GET.get('id')
    #获取该出版社的信息
    # ret = Press.objects.filter(id=edit_id)
    ret = Press.objects.get(id=edit_id)
    return render(request,'edit_press.html',{'press_obj':ret})

代码解释:

Press.objects.get(id=edit_id) 和filter都是查询数据的,不同的是get有且只能找到一个对象,否则会报错
他们两个返回的值都是一个对象,filter取值是
ret[0].name

就能取出name的值,而get取值是

ret.name

在去添加一个edit_press.html的文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/edit_press/" method="post">
        <input type="text" name="id" value="{{ press_obj.id }}" style="display: none">
        <input type="text" name="name" value="{{ press_obj.name }}">
        <input type="submit" value="提交">
    </form>

</body>
</html>
edit_press.html

我们给服务器传了个id的值,把它设置了隐藏,这样服务器就能拿到我们的id值,才能去根据id唯一的修改数据

第二种方法

第二种方法和第一种差不多,我们在html文件里把id放到action里提交到服务器

修改edit_press.html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/edit_press/?id={{ press_obj.id }}" method="post">
        <input type="text" name="name" value="{{ press_obj.name }}">
        <input type="submit" value="提交">
    </form>

</body>
</html>
edit_press.html

不同的是我们把id的值放在了action里传给了服务器,然后服务器就可以通过GET方法得到id值

修改edit_press函数

#编辑出版社
def edit_press(request):
    # 获取要编辑的出版社id,因为是在url里,所以用GET
    edit_id = request.GET.get('id')

    if request.method=='POST':
        #取出用户点击编辑之后的数据
        new_name = request.POST.get('name')
        #去数据库修改对应的数据,先查询,在修改,在保存到数据库
        edit_press_obj = Press.objects.get(id=edit_id)
        edit_press_obj.name = new_name
        edit_press_obj.save()
        #让用户再次访问列表页面
        return redirect('/press_list/')

    #获取该出版社的信息
    ret = Press.objects.filter(id=edit_id)[0]
    # ret = Press.objects.get(id=edit_id)
    return render(request,'edit_press.html',{'press_obj':ret})

我们通过Press.objects.filter(id=edit_id)[0]获取到了值,如果使用的是Press.objects.get()就不需要再加[0],只有filter需要加[0]

这样我们也实现了编辑的功能

总结:

ORM的语句

  查:  

    1. 类名.objects.all()       --> 返回一个列表
    2. 类名.objects.filter()    --> 返回一个列表,取值要用[0],如果是循环,就不需要加[0]
    3. 类名.objects.get()      --> 返回一个对象,必须只能有一个,否则会报错

  增:

    类名.objects.create(name='')       --> 创建一个对象,返回的就是刚创建的对象 

  删:

    类名.objects.filter(id=).delete()  --> 删除

  改:

    obj = 类名.objects.get(id='')

    obj.name = '新值' --> 修改对象的属性(修改数据行某个字段的值)

    obj.save() --> 把修改同步到数据库

模版语言

for循环
{% for i in ret %}
  {{ i.属性 }}
  {{ forloop.counter }}     --> for循环从1开始计数
  {{ forloop.counter0 }}   --> for循环从0开始计数
{% endfor %} 

posted @ 2019-07-06 00:07  邹邹很busy。  阅读(340)  评论(0编辑  收藏  举报