Django_mysql


 數據庫相關軟件

MySQL數據庫介紹:

 在網站開發中,數據庫是網站的重要組成部分。只有提供數據庫,數據才能夠動態的展示,而不是在網頁中顯示一個靜態的頁面。數據庫有很多,比如有 SQL Server 、 Oracle 、 PostgreSQL 以及 MySQL 等等。 MySQL 由於價格實惠、簡單易用、不受平台限制、靈活度高等特性,目前已經取得了絕大多數的市場份額。因此我們在 Django 中,也是使用 MySQL 來作為數據存儲。

MySQL驅動程序安裝:

我們使用 Django 來操作 MySQL ,實際上底層還是通過 Python 來操作的。因此我們想要用 Django 來操作 MySQL ,首先還是需要安裝一個驅動程序。在 Python3 中,驅動程序有多種選擇。比如有 pymysql 以及 mysqlclient 等。這里我們就使用 mysqlclient 來操作。 mysqlclient 安裝非常簡單。只需要通過 pip install mysqlclient 即可安裝。

注意:musqlclient遇到以下問題:

 問題:building 'MySQLdb._mysql' extension     error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools": http://landinghub.visualstudio.com/visual-cpp-build-tools

解決辦法:

先查看我的python版本信息為:

Python 3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 16:07:46) [MSC v.1900 32 bit (Intel)] on win32

下載whl文件手動安裝

下載地址:https://www.lfd.uci.edu/~gohlke/pythonlibs/#mysql-python

選擇版本(選擇的版本cp后的值要和python版本對應,否則會報錯“is not a supported wheel on this platform.”)

  • mysqlclient-1.4.2-cp36-cp36m-win32.whl

到下載目錄下執行命令D:\flower\download

  • pip install mysqlclient-1.4.2-cp36-cp36m-win32.whl

Django操作MySQL常見驅動介紹:

1、MySQL-python :也就是 MySQLdb 。是對 C 語言操作 MySQL 數據庫的一個簡單封裝。遵循了 Python DB API v2 。但是只支持 Python2 ,目前還不支持 Python3 。
2、mysqlclient :是 MySQL-python 的另外一個分支。支持 Python3 並且修復了一些 bug 。
3、pymysql :純 Python 實現的一個驅動。因為是純 Python 編寫的,因此執行效率不如 MySQLpython 。並且也因為是純 Python 編寫的,因此可以和 Python 代碼無縫銜接。
4、MySQL Connector/Python : MySQL 官方推出的使用純 Python 連接 MySQL 的驅動。因為是純 Python 開發的。效率不高。

Django使用原生sql語句操作數據庫

使用navicat連接數據庫

1. 點擊連接,連接Mysql

2.創建數據庫

3.創建表,

 

Django配置連接數據庫:

在操作數據庫之前,首先先要連接數據庫。這里我們以配置 MySQL 為例來講解。 Django 連接數據庫,不需要單獨的創建一個連接對象。只需要在 settings.py 文件中做好數據庫相關的配置就可以了。代碼如下:

settings.py

DATABASES = {
     'default': {
         #數據庫引擎(sqlite3/mysql/oracle等)
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'db1',
        'USER': 'root',
        'PASSWORD': 'root',
        'HOST': '127.0.0.1',
        'PORT': '3306'
    }
}

在Django中操作數據庫:

在 Django 中操作數據庫有兩種方式。第一種方式就是使用原生 sql 語句操作,第二種就是使用 ORM 模型來操作。在 Django 中使用原生 sql 語句操作其實就是使用 python db api 的接口來操作。如果你的 mysql 驅動使用的是 pymysql ,那么你就是使用 pymysql 來操作的,只不過 Django 將數據庫連接的這一部分封裝好了,我們只要在 settings.py 中配置好了數據庫連接信息后直接使用 Django 封裝好的接口就可以操作了。示例代碼如下:

 views.py

from django.shortcuts import render

from django.shortcuts import render
# 使用django封裝好的connection對象,會自動讀取settings.py中數據庫的配置信息
from django.db import connection


def index(request):

    cursor = connection.cursor() # 獲取游標對象
    cursor.execute("insert into book(name,auther) values ('python','flowers')")
    # 拿到游標對象后執行sql語句
    #cursor.execute("select * from book")
    # result = cursor.fetcall()  # 獲取所有的數據
    # for row in result:
    #     print(row)
    return render(request,'index.html')

以上的 execute 以及 fetchall 方法都是 Python DB API 規范中定義好的。任何使用 Python 來操作 MySQL 的驅動程序都應該遵循這個規范。所以不管是使用 pymysql 或者是 mysqlclient 或者是 mysqldb ,他們的接口都是一樣的。更多規范請參考:https://www.python.org/dev/peps/pep-0249/。

urls.py

from django.urls import path
from sq1 import views

urlpatterns = [
    path('', views.index),
]

執行項目,打開http://127.0.0.1:8000

效果圖如下:

Python DB API下規范下cursor對象常用接口:

1、description :如果 cursor 執行了查詢的 sql 代碼。那么讀取 cursor.description 屬性的時候,將返回一個列表,這個列表中裝的是元組,元組中裝的分別是 (name,type_code,display_size,internal_size,precision,scale,null_ok) ,其中 name 代表的是查找出來的數據的字段名稱,其他參數暫時用處不大。
2、rowcount :代表的是在執行了 sql 語句后受影響的行數。
3、close :關閉游標。關閉游標以后就再也不能使用了,否則會拋出異常。
4、execute(sql[,parameters]) :執行某個 sql 語句。如果在執行 sql 語句的時候還需要傳遞參數,那么可以傳給 parameters 參數。示例代碼如下:

cursor.execute("select * from article where id=%s",(1,))

5、fetchone :在執行了查詢操作以后,獲取第一條數據。

6、fetchmany(size) :在執行查詢操作以后,獲取多條數據。具體是多少條要看傳的 size 參數。如果不傳 size 參數,那么默認是獲取第一條數據。
7、fetchall :獲取所有滿足 sql 語句的數據。

 圖書管理系統案例

 原生Django使用原生sql操作數據庫,主要實現如下功能:圖書查看(包括詳情)、添加和刪除

目錄如下:

urls.py

from django.urls import path
from sq2 import views

urlpatterns = [
    path('', views.index,name='index'),
    path('add_book/', views.add_book,name='add_book'),
    path('book_detail/<book_id>', views.book_detail,name='book_detail'),
    path('del_book', views.del_book,name='del_book'),

]

setting.py中,MySQL數據庫配置,同時關閉中間件的csrf功能:

 

#mysql數據庫配置

DATABASES = {
     'default': {
         #數據庫引擎(sqlite3/mysql/oracle等)
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'book_manage',
        'USER': 'root',
        'PASSWORD': 'root',
        'HOST': '127.0.0.1',
        'PORT': '3306'
    }
}

MIDDLEWARE = [
   # 'django.middleware.csrf.CsrfViewMiddleware',

]

靜態文件模板——base.html

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>圖書管理系統</title>
    <link rel="stylesheet" href="{% static 'css/base.css' %}">
</head>
<body>
    <nav>
        <ul class="nav">
            <li><a href="/">首頁</a></li>
            <li><a href="{% url 'add_book' %}">發布圖書</a></li>
        </ul>
    </nav>
{% block content %}
{% endblock %}
</body>
</html>

index.css 內容

* {
    margin: 0;
    padding: 0;
}

.nav{
    background: #3a3a3a;
    height: 65px;
    overflow: hidden;
}

.nav li{
    float: left;
    list-style: none;
    margin: 0 20px;
    line-height: 65px;
}

.nav li a{
    color: #fff;
    text-decoration: none;
}

.nav li a:hover{
    color: lightblue;
}

index.html首頁內容

{% extends 'base.html' %}
{% block content %}
    <table>
        <thead>
            <tr>
                <td>序號</td>
                <td>書名</td>
                <td>作者</td>
            </tr>
        </thead>
        <tbody>
            {% for book in books %}
                <tr>
                    <td>{{ forloop.counter }}</td>
                    <td><a href="{% url 'book_detail' book_id=book.0 %}">{{ book.1 }}</a></td>
                    <td>{{ book.2 }}</td>
                </tr>
            {% endfor %}

        </tbody>
    </table>
{% endblock %}

add_book.html

{% extends 'base.html' %}

{% block content %}
    <form action="" method="post">
    <table>
        <tbody>
            <tr>
                <td>書名:</td>
                <td><input type="text" name="name"></td>
            </tr>
            <tr>
                <td>作者:</td>
                <td><input type="text" name="author"></td>
            </tr>
            <tr>
                <td></td>
                <td><input type="submit" value="添加"></td>
            </tr>
        </tbody>
    </table>
    </form>
{% endblock %}

book_detail.html

{% extends 'base.html' %}

{% block content %}
    <p>書名:{{ book.1 }}</p>
    <p>作者:{{ book.2 }}</p>
    <form action="{% url 'del_book' %}" method="post">
        <input type="hidden" name="book_id" value="{{ book.0 }}">
        <input type="submit" value="刪除">
    </form>
{% endblock %}

views.py

from django.shortcuts import render, redirect, reverse
from django.db import connection

#將cursor定義函數
def get_cursor():
    return connection.cursor()

def index(request):
    cursor = get_cursor() #獲取cursor
    cursor.execute("select * from book")
    books=cursor.fetchall()
    return render(request,'index.html',context={'books':books})

def add_book(request):
    if request.method == 'GET':
        return render(request, 'add_book.html')
    else:
        name = request.POST.get('name')
        author = request.POST.get('author')
        cursor = get_cursor()
        cursor.execute("insert into book (name, author) VALUES ('%s', '%s')" % (name, author))
        return redirect(reverse('index'))


def book_detail(request, book_id):
    cursor = get_cursor()
    cursor.execute("select * from book where id=%s" % book_id)
    book = cursor.fetchone()
    # print(book[0],book[1],book[2])
    print(type(book))
    return render(request, 'book_detail.html', {'book': book})

def del_book(request):
    if request.method == "POST":
        book_id = request.POST.get("book_id")
        cursor = get_cursor()
        cursor.execute("delete from book where id=%s" % book_id)
        return redirect(reverse(index))
    else:
        raise RuntimeError("刪除圖書失敗!!!")

ORM模型介紹:

隨着項目越來越大,采用寫原生SQL的方式在代碼中會出現大量的SQL語句,那么問題就出現了:

1、SQL語句重復利用率不高,越復雜的SQL語句條件越多,代碼越長。會出現很多相近的SQL語句;
2、很多SQL語句是在業務邏輯中拼出來的,如果有數據庫需要更改,就要去修改這些邏輯,這會很容易漏掉對某些SQL語句的修改;
3、寫SQL時容易忽略web安全問題,給給未來造成隱患。SQL注入;

如何解決上面的問題:

ORM ,全稱 Object Relational Mapping ,中文叫做對象關系映射,通過 ORM 我們可以通過類的方式去操作數據庫,而不用再寫原生的SQL語句。通過把表映射成類,把行作實例,把字段作為屬性, ORM 在執行對象操作的時候最終還是會把對應的操作轉換為數據庫原生語句。使用 ORM 有許多優點:
1、易用性:使用 ORM 做數據庫的開發可以有效的減少重復SQL語句的概率,寫出來的模型也更加直觀、清晰;
2、性能損耗小: ORM 轉換成底層數據庫操作指令確實會有一些開銷。但從實際的情況來看,這種性能損耗很少(不足5%),只要不是對性能有嚴苛的要求,綜合考慮開發效率、代碼的閱讀性,帶來的好處要遠遠大於性能損耗,而且項目越大作用越明顯;
3、設計靈活:可以輕松的寫出復雜的查詢;
4、可移植性: Django 封裝了底層的數據庫實現,支持多個關系數據庫引擎,包括流行的 MySQL 、 PostgreSQL 和 SQLite 。可以非常輕松的切換數據庫;

 創建和映射ORM模型

ORM 模型一般都是放在 app 的 models.py 文件中。每個 app 都可以擁有自己的模型。並且如果這個模型想要映射到數據庫中,那么這個 app 必須要放在 settings.py 的 INSTALLED_APP 中進行安裝。首先創建一個數據庫,然后配置在settings.py中鏈接MYSQL;

 settings.py 

models.py

from django.db import models
from datetime import datetime
#如果要將普通類變成一個可以映射到數據庫中的ORM模型,那么必須要將弗雷設置為models.Model或者他的子類
class book(models.Model):
    id = models.AutoField(primary_key=True)   #AutoField代表自動增長,primary_key=True代表主鍵
    name= models.CharField(max_length=100,null=False)  #CharField可變長度,必須指定一個長度字符,null不能為空
    author= models.CharField(max_length=100,null=False)
    time = models.DateTimeField(default=datetime.now())   #數據類型是 datetime 類型
    price = models.FloatField(default=0,null=False)     #浮點類型,默認值0

#如果一個模型沒有定義主鍵,那么將會自動生成一個自動增長的 int 類型的主鍵,並且這個主鍵的名字就叫做 id
class publisher(models.Model):
    name = models.CharField(max_length=100,null=False)
    address = models.CharField(max_length=100,null=False)

映射模型到數據庫中:

將 ORM 模型映射到數據庫中,總結起來就是以下幾步:

1、在 settings.py 中,配置好 DATABASES ,做好數據庫相關的配置;
2、在 app 中的 models.py 中定義好模型,這個模型必須繼承自 django.db.models ;
3、將這個 app 添加到 settings.py 的 INSTALLED_APP 中;
4、在命令行終端,進入到項目所在的路徑,然后執行命令:python manage.py makemigrations 來生成遷移腳本文件。
5、同樣在命令行中,執行命令 python manage.py migrate 來將遷移腳本文件映射到數據庫中;

執行第一個命令,會生成一個文件,如下:

命令執行效果圖如下:

數據表結果圖如下:

ORM模型基本的增刪改查

實例代碼如下:

 settings.py配置數據庫以及添加app

INSTALLED_APPS = [
    'sq4',
]

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

models.py

from django.db import models

class book(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=100,null=False)
    author = models.CharField(max_length=100,null=False)
    price = models.FloatField(default=0)

    #查詢出來的數據為了更加美觀,打印對象的時候自動調用str方法
    def __str__(self):
        return "<book:({name},{author},{price})>".format(name=self.name,author=self.author,price=self.price)

view.py

from django.shortcuts import render
from django.http import HttpResponse
from .models import book

def index(request):
    # #1.使用ORM添加數據到數據庫中
    # book1 = book(name='python菜鳥教程',author='李寧',price=79)
    # book1.save()
    #2.查詢數據,根據主鍵id進行查詢,pk=primary key,同樣也可以使用id查找;
    # book2=book.objects.get(pk=1)
    # print(book2)
    # #根據其他條件進行查找,filter過濾,會查詢出name值=python的所有數據查出來;book.objects.filter(name='python').first()first()代表查出第一條數據
    # book3 = book.objects.filter(name='python')
    # print(book3)
    #3.刪除數據
    book4 = book.objects.get(pk=1)
    book4.delete()
    #4.修改數據
    book5 =  book.objects.get(pk=2)
    book5.price =80
    book5.save()
    return HttpResponse("操作成功!")

urls.py

from sq4 import views

urlpatterns = [
    path('', views.index),
]

注意:遇到一個坑,數據庫的字符集寫的不是utf-8,然后就出現了數據新增時報錯;

ORM常用Field詳解

AutoField:
  映射到數據庫中是 int 類型,可以有自動增長的特性。一般不需要使用這個類型,如果不指定主鍵,那么模型會自動的生成一個叫做 id 的自動增長的主鍵。如果你想指定一個其他名字的並且具有自動增長的主鍵,使用 AutoField 也是可以的。

BigAutoField:
  64位的整形,類似於 AutoField ,只不過是產生的數據的范圍是從 1-9223372036854775807 。

BooleanField:
  在模型層面接收的是 True/False 。在數據庫層面是 tinyint 類型。如果沒有指定默認值,默認值是 None 。

django.utils.timezone.now方法:

會根據settings.py中是否設置了USE_TZ=True獲取當前的時間。如果設置了,那么就獲取一個aware類型的UTC時間。如果沒有設置,那么就會獲取一個navie類型的時間。

django.utils.timezone.localtime方法:

會根據setting.py中的TIME_ZONE來將一個aware類型的時間轉換為TIME_ZONE指定時區的時間。

DateField:

日期類型。在Python中是datetime.date類型,可以記錄年月日。在映射到數據庫中也是date類型。使用這個Field可以傳遞以下幾個參數:

  1. auto_now:在每次這個數據保存的時候,都使用當前的時間。比如作為一個記錄修改日期的字段,可以將這個屬性設置為True
  2. auto_now_add:在每次數據第一次被添加進去的時候,都使用當前的時間。比如作為一個記錄第一次入庫的字段,可以將這個屬性設置為True

DateTimeField:

日期時間類型,類似於DateField。不僅僅可以存儲日期,還可以存儲時間。映射到數據庫中是datetime類型。這個Field也可以使用auto_nowauto_now_add兩個屬性。

TimeField:

時間類型。在數據庫中是time類型。在Python中是datetime.time類型。

EmailField:
類似於 CharField 。在數據庫底層也是一個 varchar 類型。最大長度是254個字符;

FileField:
用來存儲文件的。這個請參考后面的文件上傳章節部分;

ImageField:
用來存儲圖片文件的。這個請參考后面的圖片上傳章節部分;

FloatField:
浮點類型。映射到數據庫中是 float 類型;

IntegerField:
整形。值的區間是 -2147483648——2147483647 ;

BigIntegerField:
大整形。值的區間是 -9223372036854775808——9223372036854775807;

PositiveIntegerField:
正整形。值的區間是 0——2147483647 ;

SmallIntegerField:
小整形。值的區間是 -32768——32767 ;

PositiveSmallIntegerField:
正小整形。值的區間是 0——32767 ;

TextField:
大量的文本類型。映射到數據庫中是longtext類型;

UUIDField:
只能存儲 uuid 格式的字符串。 uuid 是一個32位的全球唯一的字符串,一般用來作為主鍵;

URLField:
類似於 CharField ,只不過只能用來存儲 url 格式的字符串。並且默認的 max_length 是200;

Field的常用參數:

null:如果設置為 True , Django 將會在映射表的時候指定是否為空。默認是為 False 。在使用字符串相關的 Field (CharField/TextField)的時候,官方推薦盡量不要使用這個參數,也就是保持默認值 False 。因為 Django 在處理字符串相關的 Field 的時候,即使這個 Field 的 null=False ,如果你沒有給這個 Field 傳遞任何值,那么 Django 也會使用一個空的字符串 "" 來作為默認值存儲進去。因此如果再使用 null=True , Django 會產生兩種空值的情形(NULL或者空字符串)。如果想要在表單驗證的時候允許這個字符串為空,那么建議使用 blank=True 。如果你的 Field 是 BooleanField ,那么對應的可空的字段則為 NullBooleanField 。

blank:標識這個字段在表單驗證的時候是否可以為空。默認是 False 。這個和 null 是有區別的, null 是一個純數據庫級別的。而 blank 是表單驗證級別的。

db_column:這個字段在數據庫中的名字。如果沒有設置這個參數,那么將會使用模型中屬性的名字。

default:默認值。可以為一個值,或者是一個函數,但是不支持 lambda 表達式。並且不支持列表/字典/集合等可變的數據結構。

primary_key:是否為主鍵。默認是 False 。

unique:在表中這個字段的值是否唯一。一般是設置手機號碼/郵箱等。

navie時間和aware時間詳解

navie時間和aware時間:

navie時間:不知道自己的時間表示的是哪個時區的。

aware時間:知道自己的時間表示的是哪個時區的。也就是比較清醒。

pytz庫:

專門用來處理時區的庫。這個庫會經常更新一些時區的數據,不需要我們擔心。並且這個庫在安裝Django的時候會默認的安裝。如果沒有安裝,那么可以通過pip install pytz的方式進行安裝。

astimezone方法:

將一個時區的時間轉換為另外一個時區的時間。這個方法只能被aware類型的時間調用。不能被navie類型的時間調用。示例代碼如下(Linux環境下進入python環境):

import pytz
from datetime import datetime
now = datetime.now() # 這是一個navie類型的時間
utc_timezone = pytz.timezone("UTC") # 定義UTC的時區對象
utc_now = now.astimezone(utc_timezone) # 將當前的時間轉換為UTC時區的時間
>> ValueError: astimezone() cannot be applied to a naive datetime # 會拋出一個異常,原因就是因為navie類型的時間不能調用astimezone方法

now = now.replace(tzinfo=pytz.timezone('Asia/Shanghai'))
utc_now = now.astimezone(utc_timezone)
# 這時候就可以正確的轉換。

replace方法:

可以將一個時間的某些屬性進行更改。

模型中 Meta 配置:

 對於一些模型級別的配置。我們可以在模型中定義一個類,叫做 Meta 。然后在這個類中添加一些類屬性來控制模型的作用。比如我們想要在數據庫映射的時候使用自己指定的表名,而不是使用模型的名稱。那么我們可以在 Meta 類中添加一個 db_table 的屬性。示例代碼如下:

class Book(models.Model):
  name = models.CharField(max_length=20,null=False)
  desc = models.CharField(max_length=100,name='description',db_column="description1")
  class Meta:
    db_table = 'book_model'

以下將對 Meta 類中的一些常用配置進行解釋。

db_table:這個模型映射到數據庫中的表名。如果沒有指定這個參數,那么在映射的時候將會使用模型名來作為默認的表名。

ordering:設置在提取數據的排序方式。后面章節會講到如何查找數據。比如我想在查找數據的時候根據添加的時間排序,那么示例代碼如下:

class Book(models.Model):
  name = models.CharField(max_length=20,null=False)
  desc = models.CharField(max_length=100,name='description',db_column="description1")
  pub_date = models.DateTimeField(auto_now_add=True)
  class Meta:
    db_table = 'book_model'
    ordering = ['pub_date']    # ordering = ['-pub_date']   加個-號就是倒序

 

ORM外鍵使用詳解

外鍵的使用:
在 MySQL 中,表有兩種引擎,一種是 InnoDB ,另外一種是 myisam 。如果使用的是 InnoDB 引擎,是支持外鍵約束的。外鍵的存在使得 ORM 框架在處理表關系的時候異常的強大。因此這里我們首先來介紹下外鍵在 Django 中的使用。注意:創建完數據模型需要執行遷移的兩個命令,將表映射到數據庫中。

主要包括以下三點:  

1、外鍵的引用

2、如何引用不同app外鍵,語法:app.模型名

3、外鍵引用的是本身自己這個模型,那么 to 參數可以為 'self'

類定義為 class ForeignKey(to,on_delete,**options) 。第一個參數是引用的是哪個模型,第二個參數是在使用外鍵引用的模型數據被刪除了,這個字段該如何處理,比如有 CASCADE 、 SET_NULL 等。

具體工程如下:

代碼如下:

 demo3/models.py

from django.db import models

class Category(models.Model):
    name = models.CharField(max_length=128)

class Article(models.Model):
    title = models.CharField(max_length=128)
    content = models.TextField()
    category = models.ForeignKey("Category",on_delete=models.CASCADE)    #同一個app外鍵
    author = models.ForeignKey("frontuser.FronUser",on_delete=models.CASCADE,null=True)   #如果想要引用另外一個 app 的模型,那么應該在傳遞 to 參數的時候,app.模型名字


#如果模型的外鍵引用的是本身自己這個模型,那么 to 參數可以為 'self' ,或者是這個模型的名字。在論壇開發中,一般評論都可以進行二級評論,即可以針對另外一個評論進行評論,那么在定義模型的時候就需要使用外鍵來引用自身
class comment(models.Model):
    content = models.TextField()
    origin_comment = models.ForeignKey('self', on_delete=models.CASCADE)
    #
    # origin_comment = models.ForeignKey('comment', on_delete=models.CASCADE)

demo3/views.py

from django.shortcuts import render
from .models import Category,Article
from django.http import HttpResponse

def index(request):
    category = Category(username='時政')      #判斷Category在數據庫中是否存在,不存在會拋異常,所以要先保存下category
    category.save()
    article = Article(title="abc",content='111')
    article.category = category         #Article指定category時,直接找到category這個模型就ok,不用找category_id
    article.save()
    return HttpResponse('success')

 

demo3/urls.py

from django.urls import path
from . import views

app_name = 'demo3'   #命名空間
urlpatterns = [
    path('', views.index,name='index')
]

urls.py

from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    path('', include('demo3.urls')),
]

frontuser/models.py   另外一個app的模型文件

from django.db import models

class FronUser(models.Model):
    username = models.CharField(max_length=200)

 外鍵刪除

如果一個模型使用了外鍵。那么在對方那個模型被刪掉后,該進行什么樣的操作。可以通過 on_delete 來指定。可以指定的類型如下:
1、CASCADE :級聯操作。如果外鍵對應的那條數據被刪除了,那么這條數據也會被刪除。
2、PROTECT :受保護。即只要這條數據引用了外鍵的那條數據,那么就不能刪除外鍵的那條數據。
3、SET_NULL:設置為空。如果外鍵的那條數據被刪除了,那么在本條數據上就將這個字段設置為空。如果設置這個選項,前提是要指定這個字段可以為空。
4、SET_DEFAULT:設置默認值。如果外鍵的那條數據被刪除了,那么本條數據上就將這個字段設置為默認值。如果設置這個選項,前提是要指定這個字段一個默認值。
5、SET() :如果外鍵的那條數據被刪除了。那么將會獲取 SET 函數中的值來作為這個外鍵的值。 SET 函數可以接收一個可以調用的對象(比如函數或者方法),如果是可以調用的對
象,那么會將這個對象調用后的結果作為值返回回去。
6、DO_NOTHING :不采取任何行為。一切全看數據庫級別的約束。

以上這些選項只是Django級別的,數據級別依舊是RESTRICT!

 表關系

表之間的關系都是通過外鍵來進行關聯的。而表之間的關系,無非就是三種關系:一對一、一對多(多對一)、多對多等。以下將討論一下三種關系的應用場景及其實現方式。

一對多:
1. 應用場景:比如文章和作者之間的關系。一個文章只能由一個作者編寫,但是一個作者可以寫多篇文章。文章和作者之間的關系就是典型的多對一的關系。
2. 實現方式:一對多或者多對一,都是通過 ForeignKey 來實現的。

  demo3/models.py

from django.db import models

class Category(models.Model):
    """文章分類表"""
    name = models.CharField(max_length=128)

class Article(models.Model):
    """文章表"""
    title = models.CharField(max_length=128)
    content = models.TextField()
    category = models.ForeignKey("Category",on_delete=models.CASCADE)    #同一個app外鍵
    #category = models.ForeignKey("Category", on_delete=models.CASCADE, related_name='articles')   #如果想通過文章拿到一些對象,可以通過related_name
    author = models.ForeignKey("frontuser.FronUser",on_delete=models.CASCADE,null=True)   #不同app引用外鍵時,app.模型名字

    #為了Article更加美觀,打印對象模型時自動調用該方法,
    def  __str__(self):
        return "<Article: title:%s, content:%s>" % (self.id,self.title)

 demo3/views.py

from frontuser.models import FronUser
from django.http import HttpResponse

#練習一對多
def on_to_many_view(request):
    """1.一對多關聯"""
    # article = Article(title='鬼谷子',content='111112')    #創建文章
    # #獲取文章分類和作者第一條數據
    # category = Category.objects.first()
    # author = FronUser.objects.first()
    #
    # article.category = category
    # article.author = author
    # article.save()
    # return HttpResponse('success')
    """2.獲取分類下所有文章"""
    category = Category.objects.first()
    article = category.article_set.all()                   # 誰引用了表的字段作為外鍵,就設置這個 "模型的_set" 方法獲取數據
    for article in article:
        print(article)

     # 第二種添加文章數據方式
    article1 = Article(title='5555', content="55577")
    category.article_set.add(article1,bulk=False)
    # category.articles.add(article1,bulk=False)            #如果模型中設置了: related_name='articles'
    return HttpResponse('success')

一對一:

 


免責聲明!

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



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