zoukankan      html  css  js  c++  java
  • 继续Django

    环境准备

    1、    创建一个Django后,Django的目录:

    │  manage.py
    │
    ├─Django_s1
    │      settings.py
    │      urls.py
    │      wsgi.py
    │      __init__.py
    │
    │  templates

    创建app,通过命令:

    python manage.py startapp app01 

    创建app之后的目录结构如下:

    │  manage.py
    │
    ├─app01
    │  │  admin.py
    │  │  apps.py
    │  │  models.py
    │  │  tests.py
    │  │  views.py
    │  │  __init__.py
    │  │
    │  └─migrations
    │          __init__.py
    │
    ├─Django_s1
    │  │  settings.py
    │  │  urls.py
    │  │  wsgi.py
    │  │  __init__.py
    │  │
    │
    └─templates

    2、    创建一个项目之后首先需要做的配置

    Django_s1目录下settings.py文件中需要做如下配置:

    • 找到MIDDLEWARE部分,将第四行内容注释掉:

    'django.middleware.csrf.CsrfViewMiddleware',

    • 找到TEMPLATES部分,如果没有如下代码,则需要添加:

    'DIRS': [os.path.join(BASE_DIR, 'templates')]

    • 文件的最后添加静态文件目录,需要注意的是这里是一个元组没所以后面的逗号必须添加
    STATICFILES_DIRS=(
        os.path.join(BASE_DIR,"static"),
    )

    同时需要创建一个名字为static的文件夹,用于存放静态文件

    3、    到此为止基本的配置就已经完成,最后的目录结构如下:

    │  manage.py
    │
    ├─app01
    │  │  admin.py
    │  │  apps.py
    │  │  models.py
    │  │  tests.py
    │  │  views.py
    │  │  __init__.py
    │  │
    │  └─migrations
    │          __init__.py
    │
    ├─Django_s1
    │  │  settings.py
    │  │  urls.py
    │  │  wsgi.py
    │  │  __init__.py
    │
    │
    ├─static
    └─templates

    4、    创建一个测试页面,验证:

    • 主要的业务代码是放在app01目录下view.py文件中,先在view.py中写如下测试代码:
    from django.shortcuts import HttpResponse
    def index(request):
        return HttpResponse("index")
    • 同时在url.py中添加上对应关系:
    from app01 import views
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^index/', views.index),
    ]

    登录http://127.0.0.1:8000/index/

    5、    写一个简单的登录页面

    这里我们需要记住:

    templates目录中放的是html文件

    static中放的是静态文件即css,以及js文件

    views.py中写业务代码

    urls.py中写路由关系

    首先在templates里写login.html,代码如下:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <form action="/login/" method="post">
        <p>
            <input type="text" name="user" placeholder="用户名">
        </p>
        <p>
            <input type="password" name="pwd" placeholder="密码">
        </p>
        <input type="submit" value="提交">
    </form>
    </body>
    </html>

    在views,添加如下代码:

    def login(request):
        if request.method=="GET":
            return render(request,"login.html")
        elif request.method == "POST":
            u = request.POST.get("user")
            p = request.POST.get("pwd")
            if u == "zhaofan" and p == "123":
                return redirect('/index/')
            else:
                return render(request,"login.html")
        else:
            return redirect('/index/')

    在urls路由关系里添加如下代码,黄色背景部分:

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^index/', views.index),
        url(r'^login/', views.login),
    ]

    这样通过浏览器访问效果如下:

    关于获取数据和文件上传

    实现的代码如下:

    1、    在views.py里写如下函数

    def login(request):
        if request.method=="GET":
            return render(request,"login.html")
        elif request.method == "POST":
            # v = request.POST.get("gender")
            # print(v)
            # f = request.POST.getlist("city")
            # print(f)
            # file = request.POST.get("upload")
            # print(file)
            obj = request.FILES.get("upload")
            print(obj,type(obj),obj.name)
            import os
            file_path = os.path.join("upload_dir",obj.name)
            f = open(file_path,mode="wb")
            for i in obj.chunks():
                f.write(i)
            f.close()
            return render(request, "login.html")
        else:
            return redirect('/index/')

    2、    login.html文件中代码如下;

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <form action="/login/" method="post" enctype="multipart/form-data">
        <p>
            <input type="text" name="user" placeholder="用户名">
        </p>
        <p>
            <input type="password" name="pwd" placeholder="密码">
        </p>
        <p>
            男:<input type="radio" name="gender" value="1">
            女:<input type="radio"  name="gender" value="2">
        </p>
        <p>
            乒乓球:<input type="checkbox" name = "favor" value="1">
            篮球:<input type="checkbox" name = "favor" value="2">
            羽毛球:<input type="checkbox" name = "favor" value="3">
        </p>
        <p>
            <select name="city" multiple>
                <option value="sh">上海</option>
                <option value="bj">北京</option>
                <option value="tj">天津</option>
            </select>
        </p>
        <p>
            <input type="file" name="upload">
        </p>
        <input type="submit" value="提交">
    </form>
    </body>
    </html>

    3、    关于上述代码中知识点的总结:

    • 当获取单个值的时候类似单选框,可以给标签设置name属性,然后通过类似request.POST.get("gender")方式获取相应的值即:

    request.POST.get("标签name属性值")

    • 当获取多个值的时候类似复选框以及可以多选的select的时候,通过request.POST.getlist("city")的方式获取相应的内容,这样得到的是一个列表,即:

    request.POST.getlist("标签name属性值")

    • 当时获取上传文件的时候

    首先form表单中应该有如下属性:enctype="multipart/form-data"

    然后在views.py中通过obj = request.FILES.get("upload")获取文件的一个对象,通过打印可以看出这个对象的详细内容为:<class 'django.core.files.uploadedfile.InMemoryUploadedFile'>即:

    request.FILES.get("标签name属性值")

    最后通过如下方式循环将文件接收:

            import os
            file_path = os.path.join("upload_dir",obj.name)
            f = open(file_path,mode="wb")
            for i in obj.chunks():
                f.write(i)
            f.close()

    这样最后所有的上传文件都会放在upload_dir目录下,当然这个目录需要自己提前创建

    关于FBV和CBV

    1、    FBV

    FBV对应的是function base view

    urls.py

    index--->函数名

    views.py

    def 函数(request)

    2、    CBV

    CBV对应的是class base view

    3、    之前写的都是FBV的方式多点,下面通过一个CBV的例子来理解CBV

    • 首先先写一个home.html文件,代码如下:
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <form action="/home/" method="post">
        <input type="text" name="user">
        <input type="submit">
    </form>
    </body>
    </html>
    • views.py中写如下代码:
    from django.views import View
    # 这里Home需要继承View
    class Home(View):
        def get(self,request):
            print(request.method)
            return render(request,"home.html")
        def post(self,request):
            print(request.method)
            return render(request, "home.html")
    • urls.py中写如下代码高亮部分:
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^index/', views.index),
        url(r'^login/', views.login),
        url(r'^home/', views.Home.as_view()),
    
    ]
    • 效果如下

    当访问页面内容时:

    查看django打印的日志可以看出都是的get请求:

    当点击提交的时候:查看django的日志可以看出是post请求;

    4、    关于CBV,django在内部是如何实现的?

     分析:

    当访问页面的时候:头部中请求的方法是GET方式:

    当点击提交的时候:头部中的请求的方法是POST方式:

    其实当发送请求的时候,是将Request URL以及Request Method同时传递给django,先匹配url,然后去找对应的类,然后找相应的方法,也就是post或者get等,这里判断是post还是get是通过反射实现的。

    查看view类里面有一个函数:dispatch函数

        def dispatch(self, request, *args, **kwargs):
            # Try to dispatch to the right method; if a method doesn't exist,
            # defer to the error handler. Also defer to the error handler if the
            # request method isn't on the approved list.
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed
            return handler(request, *args, **kwargs)

    从函数可以看出是dispatch先做了一个反射的功能

    所以这个请求的过程是:请求--->dispatch--->get/post

    将views.py中的代码更改为如下:

    from django.views import View
    # 这里Home需要继承View
    class Home(View):
        # 这样这里就相当于一个装饰器的功能,可以自己定制化内容
        def dispatch(self, request, *args, **kwargs):
            # 调用父类中dispatch方法
            print("before")
            result = super(Home, self).dispatch(request,*args,**kwargs)
            print("after")
            return result
        def get(self,request):
            print(request.method)
            return render(request,"home.html")
        def post(self,request):
            print(request.method)
            return render(request, "home.html")

    这样从效果就可以看出当再次访问home页面的时候,每次都需要打印before以及after

    5、    模板语言中字典的循环

    views.py中写如下代码:

    USER_DICT = {
        "k1":"root1",
        "k2":"root2",
        "k3":"root3",
        "k4":"root4",
        "k5":"root5",
    }
    
    def index(request):
        return render(request,"index.html",{"user_dict":USER_DICT})

    创建一个index.html文件,代码如下:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <ul>
            {% for k,row in user_dict.items  %}
                <li>{{ k }}-{{ row }}</li>
            {% endfor %}
        </ul>
    </body>
    </html>

    按照上面的循环方式结果如下:

    同样的字典循环包含以下几种方式:

    user_dict.items ---- 这样循环row为(k,value)

    user_dict.values ---- 这样循环row为value值

    user_dict ----这样循环的话row为k值

    关于URL路由系统

    1、    实现一个点击查看详情的例子(方法一)

    views.py中的代码如下;

    USER_DICT = {
        "k1":{"name":"root1","email":"root1@qq.com"},
        "k2":{"name":"root2","email":"root2@qq.com"},
        "k3":{"name":"root3","email":"root3@qq.com"},
        "k4":{"name":"root4","email":"root4@qq.com"},
    
    }
    
    def index(request):
        return render(request,"index.html",{"user_dict":USER_DICT})
    
    def detail(request):
        nid = request.GET.get("nid")
        detail_info = USER_DICT[nid]
        return render(request,"detail.html",{"detail_info":detail_info})

    index.html文件中的代码如下;

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <ul>
            {% for k,row in user_dict.items  %}
                <li><a target="_blank" href="/detail/?nid={{ k }}">{{ row.name }}</a></li>
            {% endfor %}
        </ul>
    </body>
    </html>

    detail.html代码为如下:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h1>详细信息</h1>
        <h6>用户名:{{ detail_info.name }}</h6>
        <h6>邮箱:{{ detail_info.email }}</h6>
    </body>
    </html>

    urls.py中写如下代码高亮部分:

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^index/', views.index),
        url(r'^login/', views.login),
        url(r'^home/', views.Home.as_view()),
        url(r'^detail/', views.detail),
    
    ]

    实现效果为当打开index主页的时候显示:

    点击某个选项,则可以显示详细信息

    2、    实现一个点击查看详情的例子(方法二)

    urls.py中的代码如下高亮部分;

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^index/', views.index),
        url(r'^login/', views.login),
        url(r'^home/', views.Home.as_view()),
        #url(r'^detail/', views.detail),
        url(r'^detail-(d+).html', views.detail),
    
    ]

    views.py中的代码如下:

    USER_DICT = {
        "1":{"name":"root1","email":"root1@qq.com"},
        "2":{"name":"root2","email":"root2@qq.com"},
        "3":{"name":"root3","email":"root3@qq.com"},
        "4":{"name":"root4","email":"root4@qq.com"},
    
    }
    
    def index(request):
        return render(request,"index.html",{"user_dict":USER_DICT})
    def detail(request,nid):
        # return HttpResponse(nid)
        detail_info = USER_DICT[nid]
        return render(request,"detail.html",{"detail_info":detail_info})

    index.html中的代码为:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <ul>
            {% for k,row in user_dict.items  %}
                <li><a target="_blank" href="/detail-{{ k }}.html">{{ row.name }}</a></li>
            {% endfor %}
        </ul>
    </body>
    </html>

    detail.html中代码不变

    最终的效果,点击详细页面之后,地址变为/detail-2.html而不是之前的/detail?nid-2.html:

    3、    针对上述的例子,我们将urls.py进行修改:

    将url(r'^detail-(d+).html', views.detail),修改为:

    url(r'^detail-(d+)-(d+).html', views.detail),

    这样就存在两个正则,这样在views.py中获取到的时候也需要两个参数,def detail(request,nid,uid),并且这两个参数和顺序有关,第一个参数就是匹配的第一个正则,第二个匹配第二个正则,这样就会有个弊端,一旦调用函数的时候参数传递错误,那个真个函数里设计这两个参数的计算都会出现问题。

    所以我们通常用如下方法:

    url(r'^detail-(?P<nid>d+)-(?P<uid>d+).html', views.detail),

    这样就相当于分组,这样就不会应该顺序问题而影响结果

    其实在views.py中有一个终极的方法:

    def detail(*args,**kwargs),这样当多个参数的就会传递到*args里,当传递字典类型的参数的时候就会传递到**kwargs

    4、    name

    name是对URL路由关系进行命名,以后可以根据此名称生成自己想要的URL

    • url(r'^sdfffddddd/', views.index,name="i1"),
    • url(r'^sdfffddddd/(d+)/(d+)/', views.index,name="i2"),
    • url(r'^sdfffddddd/(?P<nid>d+)/(?P<uid>d+)/', views.index,name="i3"),

    注意:

    获取当前URL

    request.path_info

    如果def func(request,*args,**kwargs)

    from django.urls impore reverse

    url1 = reverse("i1")  ----这样就会生成/sdfffddddd/

    url2 = reverse("i2",args=(1,2,)) ---生成/1/2/

    url3 = reverse("i3",kwargs={"pid":1, "uid":9}) ---生成/1/9

    在模板语言中:

    {% url "i1" %}    ---生成/sdfffddddd/

    {% url "i2" 1 2 %}  --生成/1/2/

    {% url "i3" pid=1 uid=3 %} ---生成/1/3/

    5、    路由分发

    当有 多个app的时候

    当请求来的时候先到项目的urls.py里,这里的配置如下:

    from django.conf.urls import url,include
    from django.contrib import admin
    
    urlpatterns = [
        url(r'^app01/',include("app01.urls")),
        url(r'^app02/',include("app02.urls")),
    
    ]

    根据不同的app去不同的app下找相应的app级别的urls

    这样就实现了路由的分发

    Django的ORM

    1、    创建类

    根据类自动创建数据库表

    创建类的位置是在你创建的app目录下有一个models.py,就在这个文件中创建类,写一个简单的类的例子:

    class UserInfo(models.Model):
        #django会默认创建一个id列,并且是自增,主键
    
        #创建用户名列,字符类型,指定长度
        username = models.CharField(max_length=32)
        #c创建密码列,字符类型,指定长度
        password = models.CharField(max_length=64)

    创建过之后执行:

    python manage.py makemigrations

    执行这个命令之后,Django会去找models.py文件

    因为我们是在app01下的models.py,所以需要在settings.py中进行指定,找到:

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
    ]

    在最后添加"app01",

    这样当执行python manage.py makemigrations,就会找到app01下的models.py从而在app01目录下的migrations目录下生成对应的文件,这个文件就是用于创建数据库表用的,执行过程如下:

    D:python培训Django_s1>python manage.py makemigrations                                                                                   
    Migrations for 'app01':
      app01migrations001_initial.py:
        - Create model UserInfo
    
    D:python培训Django_s1>  

    然后执行python manage.py migrate,这样就会在数据库中创建表结构,执行过程如下:

    D:python培训Django_s1>python manage.py migrate                                                                                          
    Operations to perform:
      Apply all migrations: admin, app01, auth, contenttypes, sessions
    Running migrations:
      Applying contenttypes.0001_initial... OK
      Applying auth.0001_initial... OK
      Applying admin.0001_initial... OK
      Applying admin.0002_logentry_remove_auto_add... OK
      Applying app01.0001_initial... OK
      Applying contenttypes.0002_remove_content_type_name... OK
      Applying auth.0002_alter_permission_name_max_length... OK
      Applying auth.0003_alter_user_email_max_length... OK
      Applying auth.0004_alter_user_username_opts... OK
      Applying auth.0005_alter_user_last_login_null... OK
      Applying auth.0006_require_contenttypes_0002... OK
      Applying auth.0007_alter_validators_add_error_messages... OK
      Applying auth.0008_alter_user_username_max_length... OK
      Applying sessions.0001_initial... OK
    
    D:python培训Django_s1>  

    因为Django默认使用的是sqlite数据库库,所以这个时候会在项目目录下生成一个db.sqlite3的文件,如果想要查看需要第三方程序查看,如果想要用mysql数据库,则需要更改配置。

    更改配置如下:

    找打settings.py中的如下内容,并注释:

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

    添加如下内容:并配置自己的数据库信息

    DATABASES = {
        'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME':'dbname',
        'USER': 'root',
        'PASSWORD': 'xxx',
        'HOST': '',
        'PORT': '',
        }
    }

    由于Django内部连接mysql用的是MySQLdb模块,而python3中已经没有了这个模块,所以需要使用pymysql来代替MySQLdb,配置如下:

    在与项目同名的文件目录下的__init__.py文件中添加如下内容:

    import pymysql
    pymysql.install_as_MySQLdb()

    这样重新执行python manage.py migrate即可

    查看数据你会看到如下表:

    其中只有一个表app01_userinfo是你自己通过类创建的其他都是django自己创建的,查看app01_userinfo表结构信息:

    2、    添加数据

    方法一:(推荐这种方法)

    models.UserInfo.objects.create(username = "root", password = "123",)

    首先在app01下的urls.py中添加如下内容:

    url(r'^app02/',include("app02.urls")),

    然后在views.py中添加如下内容:

    from app01 import models
    def orm(request):
        models.UserInfo.objects.create(
            username = "root",
            password = "123",
        )
        return HttpResponse("orm is ok")

    然后通过浏览器访问http://127.0.0.1:8000/app01/orm/

    这样就在数据库里添加了一条数据数据

    方法二:

    • obj = models.UserInfo(username="dean",password = "123456")

     obj.save()

    然后通过浏览器访问http://127.0.0.1:8000/app01/orm/

    这样就在数据库里添加了一条数据数据

    方法三:

    dic={"username":"erric","password":"555"}、models.UserInfo.objects.create(**dic)

    return HttpResponse("orm is ok")

    然后通过浏览器访问http://127.0.0.1:8000/app01/orm/

    这样就在数据库里添加了一条数据数据

    3、    查询数据

    查询所有数据

    result = models.UserInfo.objects.all()

    这样得到的result通过打印时如下:

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

    这个QuerySet是Django创建的一种类似列表的格式,这里面每个元素就是数据库每行的一个对象,这样我们就能通过循环获取每行的数据,方法如下:

        result = models.UserInfo.objects.all()
        print(result)
        for row_obj in result:
            print(row_obj.id,row_obj.username,row_obj.password)
        return HttpResponse("orm is ok")

    根据条件 查询数据

    result =models.UserInfo.objects.filter(username="root")

    这里的filter就相当于sql语句中的where条件

    4、    删除数据

    models.UserInfo.objects.delete() 删除所有数据

    models.UserInfo.objects.filter(id=2).delete() 通过条件删除

    5、    更新数据

    models.UserInfo.objects.all().update(password=222)

    上面是将所有的的密码都更改,

    如果想要根据条件更改则可以:

    models.UserInfo.objects.filter(id=2).update(password=888)

  • 相关阅读:
    如何制作URL文件
    对象映射工具AutoMapper介绍
    C#高阶函数介绍
    System.Web.Caching.Cache
    系统架构设计:进程缓存和缓存服务,如何抉择?
    System.Web.Caching.Cache类 缓存 各种缓存依赖
    max server memory (MB)最大服务器内存配置--缓解内存压力
    第0节:.Net版基于WebSocket的聊天室样例
    第六节:Core SignalR中的重连机制和心跳监测机制详解
    第五节:SignalR完结篇之依赖注入和分布式部署
  • 原文地址:https://www.cnblogs.com/zhaof/p/6182908.html
Copyright © 2011-2022 走看看