django 1

 1. Django的命令:

1. 下载安装
pip install django==1.11.16 -i 源

2. 创建项目
django-admin startproject 项目名称

3. 启动项目
cd 项目根目录下
python manage.py runserver # 127.0.0.1:8000
python manage.py runserver 80 # 127.0.0.1:80
python manage.py runserver 0.0.0.0:80 # 0.0.0.0:80 

4. 创建APP
python manage.py startapp app名称

注册
5. 数据库相关
python manage.py makemigrations # 记录model的变更情况
python manage.py migrate # 将变更记录同步到数据库中

Django 的路由系统 

URL配置(URLconf)就像Django所支撑网站的目录。它的本质是URL与要为该URL调用的视图函 数之间的映射表。

我们就是以这种方式告诉Django,遇到哪个URL的时候,要对应执行哪个函数。

基本格式

from django.conf.urls import url
from app1 import views as aap1vw
from app2 import views as aap2vw
urlpatterns
= [ url(正则表达式, app1vw,参数,别名),
   url(正则表达式, app2vw, 参数, 别名), ]

示例:

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^articles/2003/$', views.special_case_2003),
    url(r'^articles/([0-9]{4})/$', views.year_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]

Django 2.0版本中的路由系统是下面的写法(官方文档):

复制代码
from django.urls import path,re_path

urlpatterns = [
    path('articles/2003/', views.special_case_2003),         #与1的区别一个是url 一个是path
    path('articles/<int:year>/', views.year_archive),
    path('articles/<int:year>/<int:month>/', views.month_archive),
    path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),
]
复制代码

正则匹配url

from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^articles/2003/$', views.special_case_2003),
    url(r'^articles/([0-9]{4})/$', views.year_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]

注意事项 

  1. urlpatterns中的元素按照书写顺序从上往下逐一匹配正则表达式,一旦匹配成功则不再继续。 
  2. 若要从URL中捕获一个值,只需要在它周围放置一对圆括号(分组匹配)。
  3. 不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。
  4. 每个正则表达式前面的'r' 是可选的但是建议加上。
# 是否开启URL访问地址后面不为/跳转至带有/的路径的配置项
APPEND_SLASH=True

Django settings.py配置文件中默认没有 APPEND_SLASH 这个参数,但 Django 默认这个参数为 APPEND_SLASH = True。 其作用就是自动在网址结尾加'/'。

其效果就是:

我们定义了urls.py:

from django.conf.urls import url
from app01 import views

urlpatterns = [
    url(r'^blog/$', views.blog),
]

访问 http://www.example.com/blog 时,默认将网址自动转换为 http://www.example/com/blog/ 。

如果在settings.py中设置了 APPEND_SLASH=False,此时我们再请求 http://www.example.com/blog 时就会提示找不到页面。

 分组命名匹配

上面的示例使用简单的正则表达式分组匹配(通过圆括号)来捕获URL中的值并以位置参数形式传递给视图。

在更高级的用法中,可以使用分组命名匹配的正则表达式组来捕获URL中的值并以关键字参数形式传递给视图。

在Python的正则表达式中,分组命名正则表达式组的语法是(?P<name>pattern),其中name是组的名称,pattern是要匹配的模式。

下面是以上URLconf 使用命名组的重写:

复制代码
from django.conf.urls import url

from . import views
#将匹配到括号里的url内容传给views,views必须的写形参接收
urlpatterns = [
    url(r'^articles/2003/$', views.special_case_2003),
    url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),  
    url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive), 
    url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
]
复制代码

这个实现与前面的示例完全相同,只有一个细微的差别:捕获的值作为关键字参数而不是位置参数传递给视图函数。

例如,针对URL /articles/2017/12/相当于按以下方式调用视图函数:

views.month_archive(request, year="2017", month="12")        #viewa必须的带接收的参数

在实际应用中,使用分组命名匹配的方式可以让你的URLconf 更加明晰且不容易产生参数顺序问题的错误,但是有些开发人员则认为分组命名组语法太丑陋、繁琐。

至于究竟应该使用哪一种,你可以根据自己的喜好来决定。

视图函数中指定默认值

# urls.py中
from django.conf.urls import url

from . import views

urlpatterns = [                        #不同的url找同一个视图函数
    url(r'^blog/$', views.page),
    url(r'^blog/page(?P<num>[0-9]+)/$', views.page),  
]

# views.py中,可以为num指定默认值
def page(request, num="1"):
    pass

在上面的例子中,两个URL模式指向相同的view - views.page - 但是第一个模式并没有从URL中捕获任何东西。

如果第一个模式匹配上了,page()函数将使用其默认参数num=“1”,如果第二个模式匹配,page()将使用正则表达式捕获到的num值。

include使urls.py 文件放在自己app目录里

将django项目里的urls.py 文件复制到app1 和app2里

项目里的urls.py文件

from django.conf.urls import url, include  #引用include

urlpatterns = [
    url(r'app1/', include('app1.urls')),      #r''可以为空,也可以匹配1级url,include 找到app1里的urls文件
    url(r'app1/', include('app1.urls')),
    url(r'app2/', include('app2.urls')),
    url(r'app2/', include('app2.urls')),
    url(r'app2/', include('app2.urls')),
    ]

app1里的urls.py文件

from django.conf.urls import url
from app1 import views as aap1vw

urlpatterns = [
    #此时的url前边要加上/app1/ 即127.0.0.1/app1/zzzz/       
    url(r'zzzz/',aap1vw.zzzz),

app2里的urls.py文件

from django.conf.urls import url

from app2 import views as aap2vw

urlpatterns = [
    url(r'xxxx/',aap2vw.xxxx),
    url(r'dddd/',aap2vw.dddd),
    url(r'cccc/',aap2vw.cccc),
]

 使用上述方法会导致 html页面里的和views里写死的url不能使用,解决办法:给url命名和反向解析:

url命名和反向解析

  给url起一个别名   通过反向解析,通过别名动态拿到url地址

在app1里的urls.py文件里给url地址起别名

from django.conf.urls import url
from app1 import views as aap1vw

urlpatterns = [
    url(r'zhanshi/',aap1vw.Zhan_shi,name='zhanshi'),      #增加别名
    url(r'add/', aap1vw.Add,name='add'), 
    url(r'update/', aap1vw.Update,name='update'),
    url(r'del/', aap1vw.Del,name='del'),
]

修改html展示页里的url,使用url别名   模板:  {% url '别名' %}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/css/bootstrap.min.css">
    <link rel="stylesheet" href="/static/css/das.css">
</head>
<body>

<nav class="navbar navbar-inverse navbar-fixed-top">
    <div class="container-fluid">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
                    aria-expanded="false" aria-controls="navbar">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="#">出版社管理</a>
        </div>
        <div id="navbar" class="navbar-collapse collapse">
            <ul class="nav navbar-nav navbar-right">
                <li><a href="#">Dashboard</a></li>
                <li><a href="#">Settings</a></li>
                <li><a href="#">Profile</a></li>
                <li><a href="#">Help</a></li>
            </ul>
            <form class="navbar-form navbar-right">
                <input type="text" class="form-control" placeholder="Search...">
            </form>
        </div>
    </div>
</nav>

<div class="container-fluid">
    <div class="row">
        <div class="col-sm-3 col-md-2 sidebar">
            <ul class="nav nav-sidebar"> 
                <li class="active"><a href="{% url 'zhanshi' %}">出版社列表 <span class="sr-only">(current)</span></a></li>       {#将 之前的/展示/ 改为 {% url 'zhanshi' %}#} 动态或其url别名对应的url路径
            </ul>
        </div>
        <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
            <h2 class="sub-header">出版社信息</h2>
            <div class="table-responsive">
            <a href="{% url 'add' %}" class="btn btn-primary">添加</a>
                <table class="table table-striped table-hover">
                    <thead>
                    <tr>
                        <th>序号<th>
                        <th>ID</th>
                        <th>出版社名称</th>
                        <th>操作</th>
                    </tr>
                    </thead>
                    <tbody>
                    {% for foo in all %}
                        <tr>
                            <td>{{ forloop.counter }}</td>
                            <td>{{ foo.pk }}</td>
                            <td>{{ foo.mane }}</td>
                            <td>
                                <a href="{% url 'del' %}?sh={{ foo.pk }}" class="btn btn-danger btn-sm">删除</a>
                                <a href="{% url 'update' %}?zj={{ foo.pk }}" class="btn btn-primary btn-sm">编辑</a>
                            </td>
                        </tr>
                    {% endfor %}
                    </tbody>
                </table>
            </div>
        </div>
    </div>
</div>

</body>
</html>

修改views.py 里写死的redirect 跳转的url .(需要在引用reverse方法)   模板   reverse('别名')

from django.shortcuts import render,redirect,reverse     #引用reverse方法
from app1 import models

def Zhan_shi(request):
    all_tusu = models.tusu.objects.all()
    return render(request,'zhanshi.html',{'all': all_tusu})
def Add(request):
    if request.method == 'POST':
        newname = request.POST.get('newname')
        models.tusu.objects.create(mane=newname)
        return redirect(reverse('zhanshi'))                     #将之前写的跳转写死的redirect('/zhanshi/') 修改为获取别名的redirect(reverse('zhanshi'))
    return render(request,'add.html')
def Update(request):
    pk = request.GET.get('zj')
    obj = models.tusu.objects.filter(pk=pk).first()
    if request.method == 'POST':
        newname = request.POST.get('newname')
        obj.mane = newname
        obj.save()
        return redirect(reverse('zhanshi'))
    return render(request,'update.html', {'obj' : obj} )
def Del(request):
    pk = request.GET.get('sh')
    obj = models.tusu.objects.filter(pk=pk).first()
    if request.method == 'POST':
        dname = request.POST.get('dname')
        models.tusu.objects.get(mane = dname).delete()
        return redirect(reverse('zhanshi'))
    return render(request,'del.html',{'obj':obj})

命名空间模式

用来解决 不同app中,url名相同路由找错的问题

即使不同的APP使用相同的URL名称,URL的命名空间模式也可以让你唯一反转命名的URL。

设置项目里的urls.py

from django.conf.urls import url, include

urlpatterns = [
    url(r'app1/', include('app1.urls',namespace='app1')),     #namespace 相当于增加一个别名,用来让模板和views来识别出唯一的url路径
    url(r'app2/', include('app2.urls',namespace='app2'))
    ]

 app1中的urls.py

from django.conf.urls import url
from app01 import views
 
app_name = 'app01'
urlpatterns = [
    url(r'^zhanshi', views.yemian1, name='zhanshi'),
    url(r'^add', views.yemian2, name='add'),       
]

 app2中的urls.py

from django.conf.urls import url
from app01 import views
 
app_name = 'app01'
urlpatterns = [
    url(r'^zhanshi', views.yemian1, name='zhanshi'),
    url(r'^add', views.yemian2, name='add'),       
]

此时app1和app2里的别名相同,要想确认唯一页面,就要把namespace对应的值加入到前后端代码里

前端使用方法

{% url 'app1:zhanshi' %}    #在app里的url的别名前加上 views里的url别名

后端使用方法

return redirect(reverse('app1:zhanshi')        #和前端一样也是前面加views里的url别名

MVC框架和MTV框架

详细介绍:http://www.ruanyifeng.com/blog/2007/11/mvc.html

MVC,全名是Model View Controller,是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller),具有耦合性低、重用性高、生命周期成本低等优点。

 

Django框架的设计模式借鉴了MVC框架的思想,也是分成三部分,来降低各个部分之间的耦合性。

Django框架的不同之处在于它拆分的三部分为:Model(模型)、Template(模板)和View(视图),也就是MTV框架。

Django的MTV模式

Model(模型):负责业务对象与数据库的对象(ORM)

Template(模版):负责如何把页面展示给用户

View(视图):负责业务逻辑,并在适当的时候调用Model和Template

 此外,Django还有一个urls分发器,它的作用是将一个个URL的页面请求分发给不同的view处理,view再调用相应的Model和Template

Django框架图示

Django的View(视图)

一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应。

响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片。

无论视图本身包含什么逻辑,都要返回响应。代码写在哪里也无所谓,只要它在你当前项目目录下面。除此之外没有更多的要求了——可以说“没有什么神奇的地方”。为了将代码放在某处,大家约定成俗将视图放置在项目(project)或应用程序(app)目录中的名为views.py的文件中。

CBV和FBV

我们之前写过的都是基于函数的view,就叫FBV。还可以把view写成基于类CBV的。

FBV (之前写的添加出版舍)

def Add(request):               #此处定义的是函数 是FBV  F是function
    if request.method == 'POST':
        newname = request.POST.get('newname')
        models.tusu.objects.create(mane=newname)
        return redirect(reverse('app1:zhanshi'))
    return render(request,'add.html')

CBV(C为类,把FBV改为CBV)

先修改 对应的url

from django.conf.urls import url
from app1 import views as aap1vw

urlpatterns = [
    url(r'zhanshi/',aap1vw.Zhan_shi,name='zhanshi'),
    url(r'add1/', aap1vw.Add,name='add'),                #这是FBV的url
    url(r'add2/', aap1vw.AddC.as_view(),name='add'),     #这是CBV的url 区别在于后边多了.as_view()
    url(r'update/', aap1vw.Update, name='update'),
    url(r'del/', aap1vw.Del,name='del'),

写CBF方法

from django.views import View      #在VBV的基础上增加引用View方法

class AddC(View):                  #定义类名并继承View
    def get(self,request):               #与FBV的区别在于直接把get和post请求处理的逻辑区分开了 逻辑更清晰
        return render(request, 'add.html')
    def post(self,request):
        newname = request.POST.get('newname')
        models.tusu.objects.create(mane=newname)
        return redirect(reverse('app1:zhanshi'))

给视图加装饰器

装饰器计算程序执行时间

import time
def Time(func):
    def inner(*args, **kwargs):
        cc = time.time()
        ret = func(*args,**kwargs)
        print(cc - time.time())
        return ret
    return inner

装饰FBV

FBV本身就是一个函数,所以和给普通的函数加装饰器无差

@Time
def Add(request):
    if request.method == 'POST':
        newname = request.POST.get('newname')
        models.tusu.objects.create(mane=newname)
        return redirect(reverse('app1:zhanshi'))
    return render(request,'add.html')

装饰CBV

类中的方法与独立函数不完全相同,因此不能直接将函数装饰器应用于类中的方法 ,我们需要先将其转换为方法装饰器。

Django中提供了method_decorator装饰器用于将函数装饰器转换为方法装饰器。

第一种 low版直接在函数上加

class AddC(View):
    @Time
    def get(self,request):
        return render(request, 'add.html')
    @Time
    def post(self,request):
        newname = request.POST.get('newname')
        models.tusu.objects.create(mane=newname)
        return redirect(reverse('app1:zhanshi'))

第二种引用method_decorator

from django.utils.decorators import method_decorator      #引用method_decorator方法, 

class AddC(View): 
    @method_decorator(Time)             #在每个函数上加装饰器
    def get(self,request):
        return render(request, 'add.html')
    @method_decorator(Time)
    def post(self,request):
        newname = request.POST.get('newname')
        models.tusu.objects.create(mane=newname)
        return redirect(reverse('app1:zhanshi'))
 

第三种 引用上级的dispatch

from django.utils.decorators import method_decorator
#不管走post还是gat都走dispatch函数,装饰dispatch函数就是装饰了他俩
class AddC(View): 
    @method_decorator(Time)     #装饰当前的dispatch函数
    def dispatch(self, request, *args, **kwargs):     #定义函数dispatch
        ret = super().dispatch(request, *args, **kwargs)  引用上级的dispatch
        return ret            #把上级的调用结果返回给当前的dispatch函数
    def get(self,request):
        return render(request, 'add.html')
    def post(self,request):
        newname = request.POST.get('newname')
        models.tusu.objects.create(mane=newname)
        return redirect(reverse('app1:zhanshi'))

第四种在类上加并指定使用装饰器的函数

from django.utils.decorators import method_decorator
@ method_decorator(Time,name='get')
@ method_decorator(Time,name='post')
class AddC(View):
    def get(self,request):
        return render(request, 'add.html')
    def post(self,request):
        newname = request.POST.get('newname')
        models.tusu.objects.create(mane=newname)
        return redirect(reverse('app1:zhanshi'))

第五种 最终版直接装饰上级的dispatch 一句搞定

from django.utils.decorators import method_decorator
@ method_decorator(Time,name='dispatch')
class AddC(View):
    def get(self,request):
        return render(request, 'add.html')
    def post(self,request):
        newname = request.POST.get('newname')
        models.tusu.objects.create(mane=newname)
        return redirect(reverse('app1:zhanshi'))

拓展 直接在函数上加装饰器和引用method_decorator家装饰器的区别

区别在于在装饰器里接受的args

def Time(func):
    def inner(*args, **kwargs):
        cc = time.time()
        ret = func(*args,**kwargs)
        print(cc - time.time())
        return ret
    return inner

如果直接加 args接受俩参数,第一个是func对象,第二个是request请求对象

如果用method_decorator  args 只接受一个参数就是request对象

from django.utils.decorators import method_decorator
# @ method_decorator(Time,name='dispatch')
class AddC(View):
    @Time                           #get方式直接装饰
    def get(self,request):
        return render(request, 'add.html')
    @method_decorator(Time)         #post方式method_decorator方式
    def post(self,request):       
        newname = request.POST.get('newname')
        models.tusu.objects.create(mane=newname)
        return redirect(reverse('app1:zhanshi'))

结果

(<app1.views.AddC object at 0x00000241089604A8>, <WSGIRequest: GET '/app1/add2/'>)      #get方式 args俩参数
-0.0019369125366210938
[22/Feb/2019 22:44:11] "GET /app1/add2/ HTTP/1.1" 200 2628


(<WSGIRequest: POST '/app1/add2/'>,)                           #post方式 args一个参数
-0.01776266098022461
[22/Feb/2019 22:44:15] "POST /app1/add2/ HTTP/1.1" 302 0

 请求和响应request和response

请求新手必备三件套

HttpResponse('字符串')                  #给请求返回一个字符串   
redirect(request,'html文件')           #给请求返回一个html文件               
rende(重定向地址)                        #重定向

requset对象

request属性

    request.method        请求方法 GET POST PUT

    request.GET             URL上携带的参数

    request.POST           POST请求提交的数据

    request.path    返回用户访问url路径,不包括域名和参数信息   (和request.path_info一样)

    request.body              请求体,byte类型,即 POST请求传过来的参数

class AddC(View):
    @Time
    def get(self,request):
        print(request.GET)
        return render(request, 'add.html')
    @method_decorator(Time)
    def post(self,request):
        print(request.method)
        print(request.path_info)
        print(request.body)
        print(request.POST)
        newname = request.POST.get('newname')
        models.tusu.objects.create(mane=newname)
        return redirect(reverse('app1:zhanshi'))
# 打印出的参数
(<WSGIRequest: POST '/app1/add2/'>,) #url上带的参数 request.GET 由于没有在get上传参 所以这个例子没有参数 POST    #请求方式 request.method /app1/add2/ #url路径 request.path_info b'newname=%E4%BA%BA%E6%B0%91%E5%87%BA%E7%89%88%E7%A4%BE' #请求主体 byte请求体 request.body <QueryDict: {'newname': ['人民出版社']}> #post请求出来的键值, request.POST

    request. scheme      表示请求方案的字符串 (通常为http或https)

def Zhan_shi(request):
    all_tusu = models.tusu.objects.all()
    print(request.scheme)
    return render(request,'zhanshi.html',{'all': all_tusu})

http

     request.FILES

一个类似于字典的对象,包含所有的上传文件信息。 FILES 中的每个键为<input type="file" name="" /> 中的name,值则为对应的数据。   注意,FILES 只有在请求的方法为POST 且提交的<form> 带有enctype="multipart/form-data" 的情况下才会 包含数据。否则,FILES 将为一个空的类似于字典的对象。

    request.META

一个标准的Python 字典,包含所有的HTTP 首部。具体的头部信息取决于客户端和服务器

def Zhan_shi(request):
    all_tusu = models.tusu.objects.all()
    print(request.scheme)
    print(request.META)
    return render(request,'zhanshi.html',{'all': all_tusu})

{'ALLUSERSPROFILE': 'C:\ProgramData', 'APPDATA': 'C:\Users\22490\AppData\Roaming', 'COMMONPROGRAMFILES': 'C:\Program Files\Common Files', 'COMMONPROGRAMFILES(X86)': 'C:\Program Files (x86)\Common Files', 'COMMONPROGRAMW6432': 'C:\Program Files\Common Files', 'COMPUTERNAME': 'DESKTOP-G8I5SER', 'COMSPEC': 'C:\WINDOWS\system32\cmd.exe', 'CONFIGSETROOT': 'C:\WINDOWS\ConfigSetRoot', 'DJANGO_SETTINGS_MODULE': 'tushu.settings', 'DRIVERDATA': 'C:\Windows\System32\Drivers\DriverData', 'FPS_BROWSER_APP_PROFILE_STRING': 'Internet Explorer', 'FPS_BROWSER_USER_PROFILE_STRING': 'Default', 'HOMEDRIVE': 'C:', 'HOMEPATH': '\Users\22490', 'LOCALAPPDATA': 'C:\Users\22490\AppData\Local', 'LOGONSERVER': '\\DESKTOP-G8I5SER', 'MOZ_PLUGIN_PATH': 'D:\福喜\Foxit Reader\plugins\', 'NUMBER_OF_PROCESSORS': '4', 'ONEDRIVE': 'C:\Users\22490\OneDrive', 'OS': 'Windows_NT', 'PATH': 'C:\Python27\;C:\Python27\Scripts;C:\Python36\Scripts\;C:\Python36\;C:\Program Files (x86)\Intel\iCLS Client\;C:\Program Files\Intel\iCLS Client\;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\IPT;C:\Program Files\Intel\Intel(R) Management Engine Components\IPT;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;D:\shexiangt\3rdparty\lib\Win32\;D:\shexiangt\Redist\Win32\;C:\Users\22490\AppData\Local\Microsoft\WindowsApps;;D:\pycharm\PyCharm 2018.3.2\bin;;C:\Python36\lib\site-packages\numpy\.libs;C:\Python36\lib\site-packages\numpy\.libs', 'PATHEXT': '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.PY;.PYW', 'PROCESSOR_ARCHITECTURE': 'AMD64', 'PROCESSOR_IDENTIFIER': 'Intel64 Family 6 Model 142 Stepping 9, GenuineIntel', 'PROCESSOR_LEVEL': '6', 'PROCESSOR_REVISION': '8e09', 'PROGRAMDATA': 'C:\ProgramData', 'PROGRAMFILES': 'C:\Program Files', 'PROGRAMFILES(X86)': 'C:\Program Files (x86)', 'PROGRAMW6432': 'C:\Program Files', 'PSMODULEPATH': 'C:\Program Files\WindowsPowerShell\Modules;C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules', 'PT5HOME': 'D:\思科交换机模拟器\Cisco Packet Tracer 6.0', 'PT6HOME': 'D:\思科交换机模拟器\Cisco Packet Tracer 6.0', 'PUBLIC': 'C:\Users\Public', 'PYCHARM': 'D:\pycharm\PyCharm 2018.3.2\bin;', 'PYCHARM_HOSTED': '1', 'PYCHARM_MATPLOTLIB_PORT': '55621', 'PYTHON36': 'C:\Python36', 'PYTHONIOENCODING': 'UTF-8', 'PYTHONPATH': 'D:\django\tushu;D:\pycharm\PyCharm 2018.3.2\helpers\pycharm_matplotlib_backend', 'PYTHONUNBUFFERED': '1', 'SESSIONNAME': 'Console', 'SYSTEMDRIVE': 'C:', 'SYSTEMROOT': 'C:\WINDOWS', 'TEMP': 'C:\Users\22490\AppData\Local\Temp', 'TMP': 'C:\Users\22490\AppData\Local\Temp', 'USERDOMAIN': 'DESKTOP-G8I5SER', 'USERDOMAIN_ROAMINGPROFILE': 'DESKTOP-G8I5SER', 'USERNAME': '22490', 'USERPROFILE': 'C:\Users\22490', 'WINDIR': 'C:\WINDOWS', 'RUN_MAIN': 'true', 'SERVER_NAME': 'DESKTOP-G8I5SER', 'GATEWAY_INTERFACE': 'CGI/1.1', 'SERVER_PORT': '8000', 'REMOTE_HOST': '', 'CONTENT_LENGTH': '', 'SCRIPT_NAME': '', 'SERVER_PROTOCOL': 'HTTP/1.1', 'SERVER_SOFTWARE': 'WSGIServer/0.2', 'REQUEST_METHOD': 'GET', 'PATH_INFO': '/app1/zhanshi/', 'QUERY_STRING': '', 'REMOTE_ADDR': '127.0.0.1', 'CONTENT_TYPE': 'text/plain', 'HTTP_HOST': '127.0.0.1:8000', 'HTTP_CONNECTION': 'keep-alive', 'HTTP_CACHE_CONTROL': 'max-age=0', 'HTTP_UPGRADE_INSECURE_REQUESTS': '1', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36', 'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate, br', 'HTTP_ACCEPT_LANGUAGE': 'zh-CN,zh;q=0.9', 'wsgi.input': <_io.BufferedReader name=464>, 'wsgi.errors': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>, 'wsgi.version': (1, 0), 'wsgi.run_once': False, 'wsgi.url_scheme': 'http', 'wsgi.multithread': True, 'wsgi.multiprocess': False, 'wsgi.file_wrapper': <class 'wsgiref.util.FileWrapper'>}

 简单的上传服务

def upload(request):
    """
    保存上传文件前,数据需要存放在某个位置。默认当上传文件小于2.5M时,django会将上传文件的全部内容读进内存。从内存读取一次,写磁盘一次。
    但当上传文件很大时,django会把上传文件写到临时文件中,然后存放到系统临时文件夹中。
    :param request: 
    :return: 
    """
    if request.method == "POST":
        # 从请求的FILES中获取上传文件的文件名,file为页面上type=files类型input的name属性值
        filename = request.FILES["file"].name
        # 在项目目录下新建一个文件
        with open(filename, "wb") as f:
            # 从上传的文件对象中一点一点读
            for chunk in request.FILES["file"].chunks():
                # 写入本地文件
                f.write(chunk)
        return HttpResponse("上传OK")

request方法

request.get_full_path()         获取全路径 即路径和参数

print(request.get_full_path())

/app1/update/?zj=16    

request.is_secure()                 如果请求时是https,则返回True;反之False

response对象

JsonResponse是HttpResponse的子类,专门用来生成JSON编码的响应。

from django.http import JsonResponse     #引用JsonResponse
def json_text(request):
    data = {'name':'wk','age':18}
    return JsonResponse(data)            #这样前端就能接收到json格式的数据 

默认只能传递字典类型,如果要传递非字典类型需要设置一下safe关键字参数。
JsonResponse([1, 2, 3], safe=False)

Django模板系统

Django模板中只需要记两种特殊符号:

{{  }}和 {% %}

{{ }}表示变量,在模板渲染的时候替换成值,{% %}表示逻辑相关的操作。

变量

{{ 变量名 }}

变量名由字母数字和下划线组成。

点(.)在模板语言中有特殊的含义,用来获取对象的相应属性值。

def test(request):
    l = [1, 2, 3]
    d = {'name':'wk'}

    class dd_a():
        def __init__(self, name, age):
            self.name = name
            self.age = age
        def dream(self):
            return "%s 1111" %(self.name)

    Wk = dd_a('wk',15)
    wc = dd_a('wc',13)
    ww = dd_a('ww',18)
    pp = [Wk,wc,ww]
    return render(request, "test.html",{'l':l,'d':d, 'pp':pp} )

 在html 取变量

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{{ l.0 }}            #根据索引取列表的值
<br> 
{{ l.1 }}             #取列表的第一个值
<br>
{{ d.name }}         #根据key取字典的值
<br> 
{{ d.keys }}           #取字典的所有key   values 取字典所有的值     items取字典的键值
<br>
{{ pp.0.name }}        #取列表pp第一个对象的 name属性
<br>
{{ pp.0.age }}           
<br>
{{ pp.0.dream }}        #使用pp列表第一个对象的dream方法
</body>
</html>

注:当模板系统遇到一个   .(点)时,会按照如下的顺序去查询:

  1. 在字典中查询
  2. 属性或者方法
  3. 数字索引

Filters   过滤器

翻译为过滤器,用来修改变量的显示结果。

语法: {{ value|filter_name:参数 }}

'|'左右没有空格没有空格没有空格

default  

{{ value|default:"nothing"}}

如果value值没传的话就显示nothing

注:TEMPLATES的OPTIONS可以增加一个选项:string_if_invalid:'找不到',可以替代default的的作用。

filesizeformat

将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)。例如:

{{ value|filesizeformat }}

如果 value 是 123456789,输出将会是 117.7 MB。

add

给变量加参数

{{ value|add:"2" }}

value是数字4,则输出结果为6。

{{ first|add:second }}

如果first是 [1,.2,3] ,second是 [4,5,6] ,那输出结果是 [1,2,3,4,5,6] 。

lower

小写

{{ value|lower }}

upper

大写

{{ value|upper}}

title

标题

{{ value|title }}

ljust

左对齐

"{{ value|ljust:"10" }}"

rjust

右对齐

"{{ value|rjust:"10" }}"

center

居中

"{{ value|center:"15" }}"

length

{{ value|length }}

返回value的长度,如 value=['a', 'b', 'c', 'd']的话,就显示4.

slice  

切片

{{value|slice:"2:-1"}}

first

取第一个元素

{{ value|first }}

last

取最后一个元素

{{ value|last }}

join

使用字符串拼接列表。同python的str.join(list)。

{{ value|join:" // " }}

truncatechars

如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾。

参数:截断的字符数

{{ value|truncatechars:9}}

date

views视图添加时间

import datetime

def test(request):
    Date = datetime.datetime.now()
    return render(request, "test.html",{'date':Date})

日期格式化

{{ value|date:"Y-m-d H:i:s"}}

可格式化输出的字符:点击查看

日期也可以改配置文件显示

修改settings.py文件

USE_L10N = False 
DATETIME_FORMAT = 'Y-m-d H:i:s'

 此时html只需要写   {{ date }}

就显示格式化的日期

safe (转译,把传进来的字符串转译为html可识别的语言)

Django的模板中会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全。但是有的时候我们可能不希望这些HTML元素被转义,比如我们做一个内容管理系统,后台添加的文章中是经过修饰的,这些修饰可能是通过一个类似于FCKeditor编辑加注了HTML修饰符的文本,如果自动转义的话显示的就是保护HTML标签的源文件。为了在Django中关闭HTML的自动转义有两种方式,如果是一个单独的变量我们可以通过过滤器“|safe”的方式告诉Django这段代码是安全的不必转义。

比如:

value = "<a href='#'>点我</a>"

{{ value|safe}}

Tags

for循环

<ul>
{% for user in user_list %}
    <li>{{ user.name }}</li>
{% endfor %}
</ul>

for循环可用的一些参数:

VariableDescription
forloop.counter 当前循环的索引值(从1开始)
forloop.counter0 当前循环的索引值(从0开始)
forloop.revcounter 当前循环的倒序索引值(从1开始)
forloop.revcounter0 当前循环的倒序索引值(从0开始)
forloop.first 当前循环是不是第一次循环(布尔值)如果是第一次显示True  后边的每次循环显示Flase
forloop.last 当前循环是不是最后一次循环(布尔值)
forloop.parentloop 本层循环的外层循环
def test(request):
    class dd_a():
        def __init__(self, name, age):
            self.name = name
            self.age = age
        def dream(self):
            return "%s 1111" %(self.name)
    Wk = dd_a('wk',15)
    wc = dd_a('wc',13)
    ww = dd_a('ww',18)
    pp = [Wk,wc,ww]
    return render(request, "test.html",{'pp':pp} )


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <ul>
        {% for ps in pp %}
            <li>{{ forloop.counter }} = {{ ps.name }}</li>
        {% endfor %} 
    </ul>
</body>
</html>

for ... empty   当循环为空时走empty

  {% for foo in all %}
                        <tr>
                            <td>{{ forloop.counter }}</td>
                            <td>{{ foo.pk }}</td>
                            <td>{{ foo.mane }}</td>
                            <td>
                                <a href="{% url 'app1:del' %}?sh={{ foo.pk }}" class="btn btn-danger btn-sm">删除</a>
                                <a href="{% url 'app1:update' %}?zj={{ foo.pk }}" class="btn btn-primary btn-sm">编辑</a>
                            </td>
                            <td>
                                {% empty %}             {# 当for循环为空时,显示empty的内容 #}
                                <td>空的</td>
                            </td>
                        </tr>
                    {% endfor %}

if,elif和else

  {% for foo in all %}
                        <tr {% if forloop.first %} style="color: red" {% endif %}>       #如果是第一次循环得出的结果则显示红色
                            <td>{{ forloop.counter }}</td>
                            <td>{{ foo.pk }}</td>
                            <td>{{ foo.mane }}</td>
                            <td>
                                <a href="{% url 'app1:del' %}?sh={{ foo.pk }}" class="btn btn-danger btn-sm">删除</a> 
                                <a href="{% url 'app1:update' %}?zj={{ foo.pk }}" class="btn btn-primary btn-sm">编辑</a>
                            </td>
                            <td>
                                {% empty %}
                                <td>空的</td>
                            </td>
                        </tr>
                    {% endfor %}
复制代码
{% if user_list %}
  用户人数:{{ user_list|length }}
{% elif black_list %}
  黑名单数:{{ black_list|length }}
{% else %}
  没有用户
{% endif %}
复制代码

当然也可以只有if和else

{% if user_list|length > 5 %}
  七座豪华SUV
{% else %}
    黄包车
{% endif %}

if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断。

 with 给变量起别名

{% with oldname as newname %}
    {{ newname }}
{% endwith %}

csrf_token

这个标签用于跨站请求伪造保护。

在页面的form表单里面写上{% csrf_token %} ,这样不用注释中间件 也可以提交post请求

   <form class="form-horizontal" action="" method="post">  
                    {% csrf_token %}           {# 加在form表单下 #}

母板

 母版就是一个普通的页面,存放所有页面公共的代码,定义好block块,让子页面进行重写

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/css/bootstrap.min.css">
    <link rel="stylesheet" href="/static/css/das.css">
</head>
<body>

<nav class="navbar navbar-inverse navbar-fixed-top">
    <div class="container-fluid">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
                    aria-expanded="false" aria-controls="navbar">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="#">出版社管理</a>
        </div>
        <div id="navbar" class="navbar-collapse collapse">
            <ul class="nav navbar-nav navbar-right">
                <li><a href="#">Dashboard</a></li>
                <li><a href="#">Settings</a></li>
                <li><a href="#">Profile</a></li>
                <li><a href="#">Help</a></li>
            </ul>
            <form class="navbar-form navbar-right">
                <input type="text" class="form-control" placeholder="Search...">
            </form>
        </div>
    </div>
</nav>

<div class="container-fluid">
    <div class="row">
        <div class="col-sm-3 col-md-2 sidebar">
            <ul class="nav nav-sidebar">
                <li class="active"><a href="{% url 'app1:zhanshi' %}">出版社列表 <span class="sr-only">(current)</span></a></li>
            </ul>
        </div>
        <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
            {% block main %}
            {% endblock %}                 {# 母版只保留公共部分,并且定义block来定位不同的部分#}
        </div>
    </div>
</div>

继承{% extends 'layouts.html' %}    子页面继承母版,并且在block块里加上不同的东西

{% extends 'muban.html' %}              {# 继承母版 #}

{% block main %}           {# 在blick 定位的地方加上不通的部分#}
            <h2 class="sub-header">出版社信息</h2>
            <div class="table-responsive">
            <a href="{% url 'app1:add2' %}" class="btn btn-primary">添加</a>
                <table class="table table-striped table-hover">
                    <thead>
                    <tr>
                        <th>序号<th>
                        <th>ID</th>
                        <th>出版社名称</th>
                        <th>操作</th>
                    </tr>
                    </thead>
                    <tbody>
                    {% for foo in all %}
                        <tr {% if forloop.first %} style="color: red" {% endif %}>
                            <td>{{ forloop.counter }}</td>
                            <td>{{ foo.pk }}</td>
                            <td>{{ foo.mane }}</td>
                            <td>
                                <a href="{% url 'app1:del' %}?sh={{ foo.pk }}" class="btn btn-danger btn-sm">删除</a>
                                <a href="{% url 'app1:update' %}?zj={{ foo.pk }}" class="btn btn-primary btn-sm">编辑</a>
                            </td>
                            <td>
                                {% empty %}
                                <td>空的</td>
                            </td>
                        </tr>
                    {% endfor %}
                    </tbody>
                </table>
            </div>
{% endblock %}

注意点:

  1.  {% extends 'muban.html' %} 写在第一行

  2.   不同的内容写在这中间{% block main %}

   3.子页面和主页面不同的静态css js也可以通过block 添加

组件

一小段公用的html代码 很多页面要用的  把这段代码保存到html文件里

可以将常用的页面内容如导航条,页尾信息等组件保存在单独的文件中,然后在需要使用的地方按如下语法导入即可。

{% include 'toubuxinxi.html' %}

 公共头部文件代码 toubuxinxi.html

<nav class="navbar navbar-inverse navbar-fixed-top">
    <div class="container-fluid">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
                    aria-expanded="false" aria-controls="navbar">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="#">出版社管理</a>
        </div>
        <div id="navbar" class="navbar-collapse collapse">
            <ul class="nav navbar-nav navbar-right">
                <li><a href="#">Dashboard</a></li>
                <li><a href="#">Settings</a></li>
                <li><a href="#">Profile</a></li>
                <li><a href="#">Help</a></li>
            </ul>
            <form class="navbar-form navbar-right">
                <input type="text" class="form-control" placeholder="Search...">
            </form>
        </div>
    </div>
</nav>

在修改页面添加头部

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/css/bootstrap.min.css">
    <link rel="stylesheet" href="/static/css/das.css">
</head>
<body>
    {% include 'toubuxinxi.html' %}
    <br>
<form class="form-horizontal" action="" method="post">
    {% csrf_token %}
    <div class="form-group">
        <label for="inputEmail3" class="col-sm-2 control-label">出版社名称</label>
        <div class="col-sm-10">
            <input type="text" class="form-control" id="inputEmail3" placeholder="出版社名称" name="newname"
                   value="{{ obj.mane }}">
        </div>
    </div>
    <div class="form-group">
        <div class="col-sm-offset-2 col-sm-10">
            <button type="submit" class="btn btn-default">修改</button>
        </div>

</body>
</html>

静态文件相关

{% load static %}

head里得引用静态文件的static是写死了

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/css/bootstrap.min.css">
    <link rel="stylesheet" href="/static/css/das.css">
</head>

如果settings.py文件里的static修改了则每个引用都要改

STATIC_URL = '/static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR,'static')

因此使用{% load static %}来解决

<head>
    <meta charset="UTF-8">
    <title>Title</title>
    {% load static %}             
{#    <link rel="stylesheet" href="/static/css/bootstrap.min.css">#}
      <link rel="stylesheet" href={% static "css/bootstrap.min.css"%}>   {#变量名拼接相对路径#}
{#    <link rel="stylesheet" href="/static/css/das.css">#}
     <link rel="stylesheet" href={% static "css/das.css"%}>
</head>

此时改变STATIC_URL = 的值页面也照常访问

STATIC_URL = '/11111/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR,'static')

{% load static %}的使用

{% load static %}
<img src="{% static "images/hi.jpg" %}" alt="Hi!" />

引用JS文件时使用:

{% load static %}
<script src="{% static "mytest.js" %}"></script>

某个文件多处被用到可以存为一个变量

{% load static %}
{% static "images/hi.jpg" as myphoto %}
<img src="{{ myphoto }}"></img>

使用get_static_prefix   取的是settings.py里STATIC_URL 的值

这种用法相当于使用绝对路径

{% load static %}
<img src="{% get_static_prefix %}images/hi.jpg" alt="Hi!" />

或者

{% load static %}
{% get_static_prefix as STATIC_PREFIX %}

<img src="{{ STATIC_PREFIX }}images/hi.jpg" alt="Hi!" />
<img src="{{ STATIC_PREFIX }}images/hi2.jpg" alt="Hello!" />

 外键的操作

 在数据库增加关联表

from django.db import models

# Create your models here.
class tusu(models.Model):
    pid = models.AutoField(primary_key=True)
    mane = models.CharField(max_length=32)
class Book(models.Model):                 #新增表Book title = models.CharField(max_length=32) #定义书名 tusu = models.ForeignKey('tusu',on_delete=models.CASCADE) #定义外键连接 连接的的表是tusu, on_delete=models.CASCADE 即如果出版社删除了对应的书也删除

变更数据库

 python3 manage.py makemigrations
 python3 manage.py migrate

新建的book表

加入数据后

  

做展示页

url略

views.py

def newzs(request):
    books = models.Book.objects.all()       #查出book表的信息
    return render(request,'newzs.html',{'books':books})  #传到前端

前端 用母版  拿外键的值直接点外键名(不要加_id)得到外键表的对象再点对应的key拿值

{% extends 'muban.html' %}
{% block main %}
            <h2 class="sub-header">书籍信息</h2>
            <div class="table-responsive">
{#            <a href="{% url 'app1:add2' %}" class="btn btn-primary">添加</a>#}
                <table class="table table-striped table-hover">
                    <thead>
                    <tr>
                        <th>序号<th>
                        <th>ID</th>
                        <th>出版社名称</th>
                        <th>书名 </th>
                        <th>操作</th>
                    </tr>
                    </thead>
                    <tbody>
                    {% for book in books %}
                        <tr {% if forloop.first %} style="color: red" {% endif %}>
                            <td>{{ forloop.counter }}</td>
                            <td>{{ book.pk }}</td>
                            <td>{{ book.tusu.mane }}</td> {# book.tusu点出来的不是外键的值而是对应的tusu表的对象,通过对象.key拿对应的值 #}
                            <td>{{ book.title }}</td>
                            <td>
                                <a href="{% url 'app1:del' %}?sh={{ foo.pk }}" class="btn btn-danger btn-sm">删除</a>
                                <a href="{% url 'app1:update' %}?zj={{ foo.pk }}" class="btn btn-primary btn-sm">编辑</a>
                            </td>
                            <td>
                                {% empty %}
                                <td>空的</td>
                            </td>
                        </tr>
                    {% endfor %}
                    </tbody>
                </table>
            </div>
{% endblock %}

删除出版社 ,对应的书也没了

 添加功能

url略

views.py

class newadd(View):
    def get(self,request): 
        tusu = models.tusu.objects.all()  #获取所有出版社的信息返回给前端
        return render(request,'newadd.html',{'tusu':tusu})
    def post(self,request):                #post请求添加出版舍
        newname = request.POST.get('newname')      #获取要添加的书的名字
        put = request.POST.get('put')              #获取要添加的书名对应的外键的值
        models.Book.objects.create(title=newname,tusu_id=put)     #创建新数据
        return redirect(reverse('app1:newzs'))

前端展示页功能 直接跳转

   <a href="{% url 'app1:newadd' %}" class="btn btn-primary">添加</a>

添加页功能

 <div class="table-responsive">
                <form class="form-horizontal" action="" method="post">
                    <div class="form-group">
                        <label for="inputEmail3" class="col-sm-2 control-label">书名</label>
                        <div class="col-sm-10">
                            <input type="text" class="form-control" id="inputEmail3" placeholder="书名" name="newname">
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="inputEmail3" class="col-sm-2 control-label">出版社</label>
                        <div class="col-sm-10">
                            <select name="put" id="inputEmail3" class="form-control">
                                {% for i in tusu %}
                                    <option value="{{ i.pk }}">{{ i.mane }}</option>
                                {% endfor %}
                            </select>
                        </div>
                    </div>
                    <div class="form-group">
                        <div class="col-sm-offset-2 col-sm-10">
                            <button type="submit" class="btn btn-default">添加</button>
                        </div>
                    </div>
                </form>
            </div>

 修改功能

url

    url(r'upda/(d+)$', aap1vw.upda.as_view(),name='upda'),   #使用分组的方法

views.py

class upda(View):
    def get(self,request,zh):           #分组要在这里接收前端传来的分组的位置参数 Book表的主键
         # zh = request.GET.get('zh')        #这是之前的接受前端传来的?号的方法 现在用分组的方法
        book_obg = models.Book.objects.get(pk=zh)
        tusu = models.tusu.objects.all()
        return render(request,'upda.html',{'book_obg':book_obg,'tusu':tusu})
    def post(self,request,zh):
        book_obg = models.Book.objects.get(pk=zh)  #拿到原有的书的对象
        upname = request.POST.get('upname')   #拿到修改后的书名
        put = request.POST.get('put')         #拿到修改后的书的对应的外键的值
        book_obg.title = upname
        book_obg.tusu_id = put
        book_obg.save()
        return redirect(reverse('app1:newzs'))

展示页提交信息          #分组url得到的参数是Book表的主键

<a href="{% url 'app1:upda' book.pk %}" class="btn btn-primary btn-sm">编辑</a>  

修改页功能

<div class="col-sm-10">
<input type="text" class="form-control" id="inputEmail3" placeholder="书名" name="upname" value="{{ book_obg.title }}"> 
</div>
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label">出版社</label>
<div class="col-sm-10">
<select name="put" id="inputEmail3" class="form-control">
     {% for i in tusu %}
     {% if book_obg.tusu == i %}   {# book_obg是前端提交的对象,加点外键对应的键即得到对应链接的对象 然后对比前端发来的对象是不是当次循环的对象 #}
      <option selected value="{{ i.pk }}">{{ i.mane }}</option>   {# 如果循环列表该次循环的对象是前端get提交来的对象 是就 selected 选中 #}
      {% else %}
      <option value="{{ i.pk }}">{{ i.mane }}</option>   {# 如果不是就不选中 #}
      {% endif %}
      {% endfor %}
 </select>
</div>
</div>

删除功能将出版社和图书的删除合并

url    定义两个分组分别传数据库对面的名字和对应的主键

url(r'del_(tusu|book)/(d+)/$', aap1vw.Del,name='Del'),

前端传出的值

    1.出版社传出的值为 对应的数据库名 和对应 的主键值 

<a href="{% url 'app1:Del' 'tusu' foo.pk %}" class="btn btn-danger btn-sm">删除</a>

    2. 图书传出的值为 对应的数据库名 和对应的 主键值

<a href="{% url 'app1:Del' 'book' book.pk %}" class="btn btn-danger btn-sm">删除</a>

views.py 文件逻辑

def Del(request,zz,hh):       #分别接收前端传来的两个参数
    if zz == 'tusu':          #图书的返回图书的展示页,出版社的返回出版社的  
        dd = 'app1:zhanshi' 
    elif zz == 'Book':        #此处可以优化 把展示页的别名改为对应数据库对象的名字
        dd = 'app1:newzs'     #可以省略以上4行代码
    Obj = getattr(models,zz)    #反射得到models 里的对应的图书的或出版社的数据库对象
    Obj.objects.get(pk=hh).delete()    #删除对应的数据库对象的选中的主键
    return redirect(reverse(dd))  #返回对应的展示页





原文地址:https://www.cnblogs.com/ywrj/p/10412993.html