Django學習筆記(11)——開發圖書管理頁面

一,項目題目: 開發圖書管理頁面

  該項目主要練習Django對多個數據庫進行增刪改查的操做。css

二,項目需求:

基礎需求:75%
1. 列出圖書列表、出版社列表、做者列表
2. 點擊做者,會列出其出版的圖書列表
3. 點擊出版社,會列出旗下圖書列表
4. 能夠建立、修改、刪除 圖書、做者、出版社

升級需求:10%
1. 點擊修改按鈕,彈出模塊框,模態框中展現該書的信息且信息能夠修改,
2. 書名不可重複,不可修改
3. 修改圖書信息時,使用ajax請求發送信息

  

三,編碼規範需求:

編碼規範需求:15%
1. 代碼規範遵照pep8 (https://python.org/dev/peps/pep-0008/)
2. 函數有相應的註釋
3. 程序有文檔說明文件(README.md參考:https://github.com/csrftoken/vueDrfDemo)
4. 程序的說明文檔必須包含的內容:程序的開發環境(django版本)、程序的實現的功能、程序的啓動方式、登陸用戶信息、程序的運行效果
5. 程序設計的流程圖:
(能夠參考:https://www.processon.com/view/link/589eb841e4b0999184934329)

  

四,項目思路

   首先作這個項目以前,推薦看一下我以前的博客:Django學習筆記(7):單表操做和多表操做,甚至有必要練習一遍。html

  其次,前期的基本操做,我在這裏再也不累贅,若是不會的話,能夠參考我以前的博客:Django學習筆記(10)——Book單表的增刪改查頁面,固然,要是單表操做的增刪改查都不會,我以爲先練習一遍沒有壞處。前端

  最後這裏寫一下此項目的思路。此項目就是對多表操做的再鞏固。vue

4.1 建立模型

  咱們先來設定概念,字段和關係python

做者模型            :   姓名  年齡
 
 
做者詳細模型      :   生日   手機號碼   家庭住址等等
 
 
出版商模型          :   出版商名稱   所在城市   email
 
 
書籍模型            :   書名  出版日期
 

用戶信息模型       :用戶名  密碼
(登陸註冊的用戶信息)


 
(做者模型  和 做者詳細模型     一對一關係        one - to - one)

(一本書可能會有多個做者, 一個做者也能夠寫多本書  )
(   做者  和 書籍                    多對多的關係  many - to - many)

(一本書只應該由一個出版商出版) 
(    出版商和書籍                  一對多關聯關係  one - to  - many)    

  代碼以下:jquery

from django.db import models

# Create your models here.

# 出版社類
class Publish(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)

    def __str__(self):
        return self.name

# 書類
class Book(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32)
    publishDate = models.DateField()
    price = models.DecimalField(max_digits=8, decimal_places=2)

    # 書只能關聯一個出版社,外鍵一般創建在多的那一邊
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)

  # 多對多,做者和書是多對多的關係
    books = models.ManyToManyField(to='Book', related_name='authors')
    
    def __str__(self):
        return self.title

# 做者類
class Author(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    # 做者和做者詳細信息 是一對一的關係
    authordetail = models.OneToOneField(to='AuthorDetail', null=True, 
on_delete=models.CASCADE)


# 做者詳細信息
class AuthorDetail(models.Model):
    nid = models.AutoField(primary_key=True)
    birthday = models.DateField()
    telephone = models.BigIntegerField()
    addr = models.CharField(max_length=64)

  

  最後運行下面代碼,生成數據表:git

python manage.py  makemigrations


python manage.py migrate

  咱們能夠添加數據,我添加的數據以下:github

insert into user1_authordetail values(1, '2019-11-12', '12345', 'boston');
insert into user1_authordetail values(2, '2014-11-12', '12312', 'houston');
insert into user1_authordetail values(3, '2013-11-12', '12432', 'ripcity');

insert into user1_author values(1, 'james', 34, 1);
insert into user1_author values(2, 'durant', 31, 2);
insert into user1_author values(3, 'curry', 30, 3);

insert into user1_publish values(1, '機械出版社');
insert into user1_publish values(2, '草堂出版社');
insert into user1_publish values(3, '人民出版社');

  

4.2 APP下的URL具體內容整理

1,註冊
    /register/

2,登陸
    /login/

3,註銷
    /logout/

4,圖書列表
    /book_list/
    /add_book/
    /update_book/101/
    /del_book/

5,出版社列表
    /publisher_list/
    /add_publisher/
    /update_publisher/101/
    # 經過出版社,修改該書,以後返回出版社頁面
    /update_book/101/202/publisher/
    /del_publisher/
    # 經過出版社,查看該出版社的圖書列表
    /book_list/101/publisher/
    # 經過出版社,增長該出版社的某本書
    /add_book/101/publisher/
    # 經過出版社,刪除該出版社的某本書
    /del_book/101/publisher/

6,做者列表
    /author_list/
    /add_author/
    /update_author/101/
    #經過做者,修改該書,以後返回做者頁面
    /update_book/101/21/author
    /del_author
    # 經過做者,查看該做者的圖書列表
    /book_list/101/author/
    # 經過做者,增長該做者的某本書
    /add_book/101/author/
    # 經過做者,刪除該做者的某本書
    /del_book/101/author/

  這裏咱們以book單表的增刪改查頁面爲例,而後增長連表操做,由於做者模型和做者詳細模型是一對一關係,並且書籍和做者是多對多的關係。咱們這裏以書籍,做者,做者詳細信息和出版社四張表的關係爲例。ajax

4.3  多表的查看操做

  查看操做比較簡單,首先在view視圖函數中獲取全部book數據,將其顯示在頁面中,代碼以下:正則表達式

 book_list = Book.objects.all()

  經過上面代碼獲取數據,拿到數據後,渲染給前端,前端經過for循環的方式,取出數據。目的就是經過Book這個數據表裏面的字段拿到對應的數據。

  前端代碼中,咱們使用Bootstrap加入簡單的樣式,而後經過for循環拿出數據,將其顯示在前端頁面上。

  注意1:這裏Book表中,拿出的publishDate數據咱們能夠改爲本身想要顯示的模型。

  這裏咱們可使用變量的過濾器(filter)。將數據顯示成 「xxxx-xx-xx」,代碼以下:

{{ book.publishDate|date:'Y-m-d' }}

  注意2:這裏的Book表中,由於一本書可能對應多個做者,因此咱們在前端顯示的時候,想要給每一個做者後面添加一個逗號(,),好看一下,可是最後一個不顯示逗號(,)。咱們可使用一個for循環,將其循環顯示:

{% for author in book.authors.all %}
       {% if forloop.last %}
             <span>{{ author.name }}</span>
        {% else %}
               <span>{{ author.name }}</span>,
        {% endif %}
{% endfor %}

  其餘就沒什麼難點,這裏將books的HTML代碼顯示以下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/bootstrap-3.3.7/dist/css/bootstrap.min.css">
</head>
<body>
<h3>查看書籍</h3>

<div class="container">
    <div class="row">
        <div class=" col-md-6 col-md-offset-3">
            <a href="" class="form-group btn btn-primary">添加頁面</a>
           <table class="table table-bordered table-hover table-striped">
               <thead>
                    <tr>
                        <th>編號</th>
                        <th>書籍名稱</th>
                        <th>價格</th>
                        <th>出版日期</th>
                        <th>出版社</th>
                        <th>做者</th>
                        <th>修改操做</th>
                        <th>刪除操做</th>
                    </tr>
               </thead>
               <tbody>
                    {% for book in book_list %}
                    <tr>
                        <td>{{ forloop.counter }}</td>
                        <td>{{ book.title }}</td>
                        <td>{{ book.price }}</td>
                        <td>{{ book.publishDate|date:'Y-m-d' }}</td>
                        <td>{{ book.publish.name }}</td>
                        <td>{% for author in book.authors.all %}
                            {% if forloop.last %}
                                <span>{{ author.name }}</span>
                            {% else %}
                            <span>{{ author.name }}</span>,
                            {% endif %}
                            {% endfor %}
                        </td>
                        
                    </tr>
                    {% endfor %}
               </tbody>
           </table>
        </div>
    </div>
</div>
</body>
</html>

  

4.4  多表的增長操做

   添加操做的話,咱們能夠從前端寫起,咱們獲取數據的各個變量,將其寫在form表單裏面,而後傳到後臺,若是是post的數據,咱們能夠將其獲取到,而後添加到數據庫中。

  可是首先,咱們須要獲取出版社的信息和做者的信息,由於出版社和Book是一對多的關係,做者和Book是多對多的關係,因此這裏不是單純的添加,而是須要選擇。獲取Publish和Author信息的代碼以下:

    publish_list = Publish.objects.all()

    author_list = Author.objects.all()

  而後,將信息展現在前端,從前端獲取的數據經過post傳到後臺,進而寫入數據庫。

    if request.method == 'POST':
        title = request.POST.get('title')
        price = request.POST.get('price')
        pub_date = request.POST.get('pub_date')
        publish_id = request.POST.get('publish_id')
        # checkbox  多選的話,取值方式以下
        authors_id_list = request.POST.getlist('authors_id_list')

        # 添加到數據庫中,前面是數據庫的名字 =後面是上面變量的名字
        book_obj = Book.objects.create(title=title, price=price, publishDate=pub_date,
                            publish_id=publish_id)

        book_obj.authors.add(*authors_id_list)
        return HttpResponse("OK")

  注意1:因爲一本書能夠對應多個做者,因此咱們獲取的做者數據多是多個,那麼咱們不能直接get數據,這裏使用 gstlist獲取多選數據。

authors_id_list = request.POST.getlist('authors_id_list')

  注意2:因爲做者和書是多對多的關係,因此咱們添加數據,不止給Book表裏添加,還將會添加Book和Authors表的關係,這裏使用.add() 添加。代碼以下:

book_obj.authors.add(*authors_id_list)

  最後這裏展現一下添加數據的HTML代碼,(一樣這裏使用Bootstrap渲染了頁面):

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

</head>
<body>
<h3>添加書籍</h3>

<div class="container">
    <div class="row">
        <div class="col-md-6 col-md-offset-3">
            <form action="" method="post">
            {% csrf_token %}
                <div class="form-group">
                    <label for="">名稱</label>
                    <input type="text" name="title" class="form-control">
                </div>
                <div class="form-group">
                    <label for="">價格</label>
                    <input type="text" name="price" class="form-control">
                </div>
                <div class="form-group">
                    <label for="">出版日期</label>
                    <input type="date" name="pub_date" class="form-control">
                </div>
                <div class="form-group">
                    <label for="">出版社</label>
                    <select name="publish_id"  id="" class="form-control">
                        {% for publish in publish_list %}
                        <option value="{{ publish.pk }}">{{ publish.name }}</option>
                        {% endfor %}
                    </select>
                </div>
                <div class="form-group">
                    <label for="">做者</label>
                    <select  name="authors_id_list" multiple class="form-control">
                        {% for author in author_list %}
                        <option value="{{ author.pk }}">{{ author.name }}</option>
                        {% endfor %}
                    </select>
                </div>
                <input type="submit" class="btn btn-default">
            </form>
        </div>
    </div>
</div>
</body>
</html>

  

4.5  多表的編輯操做和刪除操做

  這裏將編輯操做和刪除操做放在一塊兒寫,確定有其道理的。由於編輯操做和刪除操做,只須要在查看書籍的HTML上添加兩個按鈕,也就是編輯按鈕和刪除按鈕。

 <table class="table table-bordered table-hover table-striped">
               <thead>
                    <tr>
                        
                            ......
    
                        <th>修改操做</th>
                        <th>刪除操做</th>
                    </tr>
               </thead>
               <tbody>
                    {% for book in book_list %}
                    <tr> 

                       ......

                        <td>
                            <a href="{{ book.pk }}/change" class="btn btn-warning">編輯</a>
                        </td>
                        <td>
                            <a href="{{ book.pk }}/delete" class="btn btn-danger">刪除</a>
                        </td>
                    </tr>
                    {% endfor %}
               </tbody>
           </table>

  

4.5.1 編輯功能的製做

  首先,咱們須要拿到須要編輯的ID,而後在數據庫中找到對應的ID字段,最後對內容進行修改。

   edit_book_obj = Book.objects.filter(pk=edit_id).first()
    publish_list = Publish.objects.all()
    author_list = Author.objects.all()

  這裏再重複一次,由於Book和Publish是一對多的關係,Book和author是多對多的關係,因此同時須要將publish和author的數據取出來,同時進行update。

def change_books(request,edit_id):
    edit_book_obj = Book.objects.filter(pk=edit_id).first()
    publish_list = Publish.objects.all()
    author_list = Author.objects.all()

    if request.method == 'POST':
        title = request.POST.get('title')
        price = request.POST.get('price')
        pub_date = request.POST.get('pub_date')
        publish_id = request.POST.get('publish_id')
        # checkbox  多選的話,取值方式以下
        authors_id_list = request.POST.getlist('authors_id_list')

        # 添加到數據庫中,前面是數據庫的名字 =後面是上面變量的名字
        book_obj = Book.objects.filter(pk=edit_id).update(title=title, price=price, publishDate=pub_date,
                                       publish_id=publish_id)
        # 先把更新過的數據清空掉,而後再添加信息
        # edit_book_obj.authors.clear()
        # edit_book_obj.authors.add(*authors_id_list)
        # set方法 能夠取代上面的兩行代碼。
        edit_book_obj.authors.set(authors_id_list)

        return redirect('/user1/books/')

    return render(request, 'user1/editbook.html', locals())

  除了以前須要注意的問題以外,這裏咱們還須要注意兩點。

  注意1:咱們將數據update以後,咱們須要展現的編輯以後的Book頁面,因此這裏使用redirect,返回到book表中:

return redirect('/user1/books/')

  注意2:咱們添加author表的數據,因此咱們不能拿到更新以後的信息,這裏須要更新以前的信息,因此咱們須要把更新過的數據清空掉,而後再添加數據。這裏有兩種方法:

        # 先把更新過的數據清空掉,而後再添加信息

#  方法一
        edit_book_obj.authors.clear()
        edit_book_obj.authors.add(*authors_id_list)

# 方法二
        # set方法 能夠取代上面的兩行代碼。
        edit_book_obj.authors.set(authors_id_list)

  最後展現完整的編輯視圖函數:

def change_books(request,edit_id):
    edit_book_obj = Book.objects.filter(pk=edit_id).first()
    publish_list = Publish.objects.all()
    author_list = Author.objects.all()

    if request.method == 'POST':
        title = request.POST.get('title')
        price = request.POST.get('price')
        pub_date = request.POST.get('pub_date')
        publish_id = request.POST.get('publish_id')
        # checkbox  多選的話,取值方式以下
        authors_id_list = request.POST.getlist('authors_id_list')

        # 添加到數據庫中,前面是數據庫的名字 =後面是上面變量的名字
        book_obj = Book.objects.filter(pk=edit_id).update(title=title, price=price, 
publishDate=pub_date,
                                       publish_id=publish_id)
        # 先把更新過的數據清空掉,而後再添加信息
        # edit_book_obj.authors.clear()
        # edit_book_obj.authors.add(*authors_id_list)
        # set方法 能夠取代上面的兩行代碼。
        edit_book_obj.authors.set(authors_id_list)

        return redirect('/user1/books/')

    return render(request, 'user1/editbook.html', locals())

  

4.5.2 刪除功能的製做

  刪除就很是簡單了,咱們只須要經過查找須要編譯的ID,而後在數據庫找到對應ID字段,刪除ID字段對應的數據便可。最後返回Book表就行。

  這裏展現刪除視圖的完整代碼:

def delete_books(request,delete_id):
    Book.objects.filter(pk=delete_id).delete()

    return redirect('/user1/books/')

  

五,注意事項

 1,ORM表關係

一對一(author authordetail)

  刪除author表時,應該刪除authordetail表,關聯的author就被刪除了!

一對多(book  publisher)

  刪除出版社下面的某本書,拿到書的id,刪除這本書

多對多(book author)

  清楚綁定關係,不是刪除書

1.1 打印ORM轉換過程當中SQL的代碼

  若是不瞭解其關係,能夠在控制檯打印其SQL語句,也就是打印ORM轉換過程當中的SQL,咱們能夠在Settings中配置一下:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
}

  

1.2  related_name的應用

  在反向查詢的時候,若是定義了related_name,則使用 related_name替換表名,例如:

publish = ForeignKey(Blog, related_name='bookList')

  練習:

# 練習: 查詢人民出版社出版過的全部書籍的名字與價格(一對多)
 
# 反向查詢 再也不按表名:book,而是related_name:bookList
 
 
    queryResult=Publish.objects
              .filter(name="人民出版社")
              .values_list("bookList__title","bookList__price")

  

2,引入Bootstrap文件

2.1 配置搜索目錄

  在項目的根目錄下新建一個static目錄,而後打開項目的settings文件,在最下面添加配置,用於指定靜態文件的搜索目錄:

STATIC_URL = '/static/'

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

  

2.2 下載Bootstrap文件

  找到Bootstrap官網:點擊我

  而後下載Bootstrap,將其解壓,而後放到static下面便可。

 2.3 使用Bootstrap文件

  注意:Bootstrap的全部JavaScript插件都依賴jQuery,因此必須將jQuery放在前面,否則bootstrap永遠引入失敗。

<!-- jQuery (Bootstrap 的全部 JavaScript 插件都依賴 jQuery,因此必須放在前邊) -->
<script src="/static/JS/jquery-3.2.1.min.js"></script>

<!-- 加載 Bootstrap 的全部 JavaScript 插件。你也能夠根據須要只加載單個插件。 -->
<script src="/static/bootstrap-3.3.7/js/bootstrap.min.js"></script>

  

3,locals()函數的使用技巧

  對於添加函數,咱們發現了其return的時候,賦值操做以下:

return render(request, 'user1/addbook.html', {'publish_list': publish_list,
 'author_list': author_list})

  咱們會發現,若是臨時變量和臨時模板有不少的時候,輸起來就很是麻煩,因此爲了代碼看起來更加簡潔,咱們可使用Python的內建函數 locals(),它返回的字典對全部局部變量的名稱和值進行映射。所以上面的代碼能夠重構以下:

return render(request, 'user1/addbook.html', locals())

  在上面的代碼中,咱們沒有手工指定其字典形式,而是傳入了locals()的值,他包括了函數執行的一切變量。

 

六,筆記

1,Django中timezone和Python中datatime的區別與聯繫

  • 進入django數據庫中的時候必定是timezone aware的時間,若是要生成時間,要經過replace timezone設置爲本地失去。
  • 數據庫中的時間都是UTC時間  

1.1  Django中的timezone

1.2  Python中的datetime

 2,def  __str__(self): 是什麼意思?

  Python3.x中使用的是__str__ 函數 ,而Python2.x中使用的是__unicode__函數。

  推薦定義Model的時候,寫一個__str__函數,它的做用是美化打印出來的結果,使咱們更方便查看。

  從最基本的提及,首先舉個例子:

class Test1:
    def __init__(self, name, age):
        self.name = name
        self.age = age

class Test2:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return "Name: " + self.name

res1 = Test1('james', 32)
print(res1)
res2 = Test2('durant', 30)
print(res2)
'''
<__main__.Test1 object at 0x00000000025700B8>
Name: durant
'''

  咱們能夠看到:若是沒有__str__方法,打印出來的是<__main__.Test1 object at 0x00000000025700B8>格式,而有__str_-方法,打印出來是按照__str__定義的格式來打印,打印結果是Name: durant。

  看看文檔

   那麼具體到Django中,在Models中定義這個__str__方法,最直接的感覺就是你訪問admin所看到的的內容是否友好。

  下面舉個例子:

class Question(models.Model):
    question_text = models.CharField('question text', max_length=200)
    pub_date = models.DateTimeField('date published')

    class Meta:
        verbose_name = 'question'
        verbose_name_plural = verbose_name
        ordering = ['-id']

    def __str__(self):
        return self.question_text

  上面的models來自Django的官方教程(本人沒有實踐,只是拿過來作個筆記而已),在上面的models中,我定義了一個名爲Question的models,此時訪問Django的後臺admin,看到的內容是這樣的:

  能夠發現,Question看到的內容就是咱們上面返回的self.question_text(若是返回的是其餘形式,則結果是其餘形式),那麼若是此時將上述代碼註釋掉,也就是變成下面這樣:

class Question(models.Model):
    question_text = models.CharField('question text', max_length=200)
    pub_date = models.DateTimeField('date published')

    class Meta:
        verbose_name = 'question'
        verbose_name_plural = verbose_name
        ordering = ['-id']

  再去看看後臺admin裏面查看Question,則變成這樣:

  咱們定義的問題,看到的內容所有變成了Question object,這樣的表達方式,對人來講,是至關的不友好,因此這就是定義一個__str__函數的必要性。

 

 3,使用類視圖:減小重複代碼

   當視圖裏面代碼類似的時候,就顯得有點冗餘。由於他們都具備相似的業務邏輯,實現相似的功能:經過從URL傳遞過來的參數去數據庫查詢數據,加載一個模板,利用剛纔的數據渲染模板,返回這個模板,因爲這個過程是如此的常見,Django很善解人意的幫助咱們想辦法偷懶,因而提供了一種快捷方式,名爲「類視圖」。

  如今咱們能夠試試將原來代碼改成使用類視圖的方式,整個過程分三步走:

  • 修改URLconf設置
  • 刪除一些舊的無用的視圖
  • 採用基於類視圖的新視圖

 3.1 改良路由配置系統URLconf

  URL配置(URLConf)就像是Django所支撐網站的目錄。它的本質是URL與要爲該URL調用的視圖函數之間的映射表;你就是以這種方式告訴Django,對於客戶端發來的某個URL調用哪一段邏輯代碼對應執行。

  好比下面代碼:

from django.conf.urls import url
from . import views
 
app_name = 'polls'
urlpatterns = [
    url(r'^$', views.IndexView.as_view(), name='index'),
    url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='detail'),
    url(r'^(?P<pk>[0-9]+)/results/$', views.ResultsView.as_view(), name='results'),
    url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]

  請注意:在上面的第2,3條目中將原來的question_id 改爲了pk。若要從URL中捕獲一個值,只須要在它的周圍放置一對圓括號,不須要添加一個前導的反斜槓,由於每一個URL都有。好比應該是^articles 而不是 ^/articles。  

  注意:每一個正則表達式前面的 r 是可選的額可是建議加上,他告訴Python這個字符串是「原始的」——字符串中任何字符都不該該轉義。

 

七,結果展現

1,數據庫建好的表展現

1.1 插入數據以前,表格展現以下:

  這次項目建立的全部的表格展現以下:

  author表

  author_books表

  

   authordetail表

  book表

  publisher表

  userinfo表

 

2,前端頁面展現以下:

Book表:

編輯頁面:

添加頁面:

 

八,代碼

8.1 簡易版本的增傷改查Book表

models.py

from django.db import models

# Create your models here.

# 出版社類
class Publish(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)

    def __str__(self):
        return self.name

# 書類
class Book(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32)
    publishDate = models.DateField()
    price = models.DecimalField(max_digits=8, decimal_places=2)

    # 書只能關聯一個出版社,外鍵一般創建在多的那一邊
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)

    def __str__(self):
        return self.title

# 做者類
class Author(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    # 做者和做者詳細信息 是一對一的關係
    authordetail = models.OneToOneField(to='AuthorDetail', null=True, on_delete=models.CASCADE)

    # 多對多,做者和書是多對多的關係
    books = models.ManyToManyField(to='Book', related_name='authors')

# 做者詳細信息
class AuthorDetail(models.Model):
    nid = models.AutoField(primary_key=True)
    birthday = models.DateField()
    telephone = models.BigIntegerField()
    addr = models.CharField(max_length=64)

  

views.py

from django.shortcuts import render, HttpResponse,redirect

# Create your views here.
from user1.models import *

def add_book(request):
    if request.method == 'POST':
        title = request.POST.get('title')
        price = request.POST.get('price')
        pub_date = request.POST.get('pub_date')
        publish_id = request.POST.get('publish_id')
        # checkbox  多選的話,取值方式以下
        authors_id_list = request.POST.getlist('authors_id_list')

        # 添加到數據庫中,前面是數據庫的名字 =後面是上面變量的名字
        book_obj = Book.objects.create(title=title, price=price, publishDate=pub_date,
                            publish_id=publish_id)
        # print(authors_id_list)   #['2', '3']
        book_obj.authors.add(*authors_id_list)
        return HttpResponse("OK")

    publish_list = Publish.objects.all()
    print(publish_list)
    author_list = Author.objects.all()
    return render(request, 'user1/addbook.html', {'publish_list': publish_list, 'author_list': author_list})

def books(request):
    book_list = Book.objects.all()

    return render(request, 'user1/books.html',{'book_list': book_list})

def change_books(request,edit_id):
    edit_book_obj = Book.objects.filter(pk=edit_id).first()
    publish_list = Publish.objects.all()
    author_list = Author.objects.all()

    if request.method == 'POST':
        title = request.POST.get('title')
        price = request.POST.get('price')
        pub_date = request.POST.get('pub_date')
        publish_id = request.POST.get('publish_id')
        # checkbox  多選的話,取值方式以下
        authors_id_list = request.POST.getlist('authors_id_list')

        # 添加到數據庫中,前面是數據庫的名字 =後面是上面變量的名字
        book_obj = Book.objects.filter(pk=edit_id).update(title=title, price=price, publishDate=pub_date,
                                       publish_id=publish_id)
        # 先把更新過的數據清空掉,而後再添加信息
        # edit_book_obj.authors.clear()
        # edit_book_obj.authors.add(*authors_id_list)
        # set方法 能夠取代上面的兩行代碼。
        edit_book_obj.authors.set(authors_id_list)

        return redirect('/user1/books/')

    return render(request, 'user1/editbook.html', {'edit_book_obj': edit_book_obj,
                                                   'publish_list': publish_list,
                                                   'author_list': author_list})

def delete_books(request,delete_id):
    Book.objects.filter(pk=delete_id).delete()

    return redirect('/user1/books/')

  

urls.py

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('user1/', include('user1.urls')),
]

  

user1/urls.py

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

from user1 import views

urlpatterns = [
    path('add/', views.add_book),
    path('books/', views.books),
    path('books/<int:edit_id>/change', views.change_books),
    path('books/<int:delete_id>/delete', views.delete_books),
]

  

 

8.2 完整項目的代碼

  請移步小編的GitHub:傳送門

相關文章
相關標籤/搜索