繼續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':
  app01\migrations\0001_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)

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM