1. 程式人生 > >python 全棧開發,Day80(部落格系統分析,部落格主頁展示)

python 全棧開發,Day80(部落格系統分析,部落格主頁展示)

一、部落格系統分析

資料庫的構建

首先,我們分析一個部落格系統的功能:

  • 一個部落格可以有多個標籤(多對多)
  • 一個部落格可以有多條評論(一對多)
  • 一個部落格只可以有一個類別(多對一)

接下來,我們分析關係的屬性:
部落格:標題,作者,內容,釋出時間,分類(外來鍵),標籤(多對多)等
標籤:標籤名
類別:分類名
評論:作者,部落格(外來鍵),郵箱,內容,釋出時間等。

有8張表,表關係如下:

 

圖中箭頭開始的英文字母表示關聯欄位

按照箭頭方向查詢,表示正向查詢,否則為反向查詢

 

新建專案cnblog,應用名為blog

修改models.py,必須匯入模組

from django.contrib.auth.models import AbstractUser

因為有一個表userinfo需要繼承它。django自帶的auth_user表也是繼承AbstractUser

表模型如下:

from django.db import models

# Create your models here.


from django.db import models

# Create your models here.


from django.contrib.auth.models import
AbstractUser class UserInfo(AbstractUser): """ 使用者資訊 """ nid = models.AutoField(primary_key=True) telephone = models.CharField(max_length=11, null=True, unique=True) avatar = models.FileField(upload_to='avatars/', default="avatars/default.png") create_time = models.DateTimeField(verbose_name='
建立時間', auto_now_add=True) blog = models.OneToOneField(to='Blog', to_field='nid', null=True, on_delete=models.CASCADE) def __str__(self): return self.username class Blog(models.Model): """ 部落格資訊 """ nid = models.AutoField(primary_key=True) title = models.CharField(verbose_name='個人部落格標題', max_length=64) site_name = models.CharField(verbose_name='站點名稱', max_length=64) theme = models.CharField(verbose_name='部落格主題', max_length=32) def __str__(self): return self.title class Category(models.Model): """ 博主個人文章分類表 """ nid = models.AutoField(primary_key=True) title = models.CharField(verbose_name='分類標題', max_length=32) blog = models.ForeignKey(verbose_name='所屬部落格', to='Blog', to_field='nid', on_delete=models.CASCADE) def __str__(self): return self.title class Tag(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField(verbose_name='標籤名稱', max_length=32) blog = models.ForeignKey(verbose_name='所屬部落格', to='Blog', to_field='nid', on_delete=models.CASCADE) def __str__(self): return self.title class Article(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField(max_length=50, verbose_name='文章標題') desc = models.CharField(max_length=255, verbose_name='文章描述') create_time = models.DateTimeField(verbose_name='建立時間', auto_now_add=True) content = models.TextField() comment_count = models.IntegerField(default=0) up_count = models.IntegerField(default=0) down_count = models.IntegerField(default=0) user = models.ForeignKey(verbose_name='作者', to='UserInfo', to_field='nid', on_delete=models.CASCADE) category = models.ForeignKey(to='Category', to_field='nid', null=True, on_delete=models.CASCADE) tags = models.ManyToManyField( to="Tag", #through引數可以指定用作中介的中間模型 through='Article2Tag', ) def __str__(self): return self.title class Article2Tag(models.Model): nid = models.AutoField(primary_key=True) article = models.ForeignKey(verbose_name='文章', to="Article", to_field='nid', on_delete=models.CASCADE) tag = models.ForeignKey(verbose_name='標籤', to="Tag", to_field='nid', on_delete=models.CASCADE) class Meta: #組合唯一約束 unique_together = [ ('article', 'tag'), ] def __str__(self): v = self.article.title + "---" + self.tag.title return v class ArticleUpDown(models.Model): """ 點贊表 """ nid = models.AutoField(primary_key=True) user = models.ForeignKey('UserInfo', null=True, on_delete=models.CASCADE) article = models.ForeignKey("Article", null=True, on_delete=models.CASCADE) is_up = models.BooleanField(default=True) class Meta: # 組合唯一約束 unique_together = [ ('article', 'user'), ] class Comment(models.Model): """ 評論表 """ nid = models.AutoField(primary_key=True) article = models.ForeignKey(verbose_name='評論文章', to='Article', to_field='nid', on_delete=models.CASCADE) user = models.ForeignKey(verbose_name='評論者', to='UserInfo', to_field='nid', on_delete=models.CASCADE) content = models.CharField(verbose_name='評論內容', max_length=255) create_time = models.DateTimeField(verbose_name='建立時間', auto_now_add=True) parent_comment = models.ForeignKey('Comment', null=True, on_delete=models.CASCADE) def __str__(self): return self.content
View Code

相關引數解釋:

through 表示orm,不要建立關係表。而制定一個表,這個表自己來建立!為什麼呢?因為orm建立多對多關係表時,只有3個欄位。那麼需要關係表需要擴充欄位時,就不行了!

所以設定through 欄位,是為了方便新增額外的欄位。使用through,那麼這個表,稱之為中間模型。

在Comment模型表中,有一個欄位parent_comment。它關聯的是本身表中的主鍵nid,它是一個父級評論id,用來展示誰評論誰!to='Comment'等同於to='self'

 

修改settings.py配置檔案,覆蓋預設的User模型最後一行新增,否則執行建立表命令時會報錯!

AUTH_USER_MODEL="blog.UserInfo"

Django允許你通過修改setting.py檔案中的 AUTH_USER_MODEL 設定覆蓋預設的User模型,其值引用一個自定義的模型。

bolg,是應用名。

 

使用下面2個命令,生成表

python manage.py makemigrations
python manage.py migrate

生成的表如下:

 注意:django自帶的auth_user表沒有了,取而代之的是blog_userinfo表。

查看錶欄位

它在auth_user表的基礎上,增加了5個欄位!

 

登入驗證

新增超級使用者,密碼必須是8位或者以上!

python manage.py createsuperuser

效果如下:

再建立2個使用者,zhang和lisi。用來測試多個使用者登入! 

lisi使用者

 

修改urls.py,增加路徑

from blog import views
urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', views.index),
    path('login/', views.login),
]
View Code

修改views.py,增加檢視函式

from django.shortcuts import render,HttpResponse,redirect
from django.contrib import auth
from blog.models import Article,UserInfo

# Create your views here.
def login(request):

    if request.method=="POST":
        user=request.POST.get("user")
        pwd=request.POST.get("pwd")
        # 使用者驗證成功,返回user物件,否則返回None
        user=auth.authenticate(username=user,password=pwd)
        if user:
            # 登入,註冊session
            # 全域性變數 request.user=當前登陸物件(session中)
            auth.login(request,user)
            return redirect("/index/")

    return render(request,"login.html")

def index(request):
    return render(request,"index.html")
View Code

修改login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="" method="post">
    {% csrf_token %}
    <lable>使用者名稱</lable><input type="text" name="user">
    <lable>密碼</lable><input type="password" name="pwd">
    <input type="submit">
</form>
</body>
</html>
View Code

修改index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h3>INDEX</h3>
</body>
</html>
View Code

訪問登入頁面

跳轉到首頁

 

首頁修飾

修改settings.py,設定靜態檔案目錄。最後一行新增:

STATICFILES_DIRS=[
    os.path.join(BASE_DIR,"static")
]
View Code

下載bootsrtap,將壓縮的包內容放到satic目錄

img和js是新建的

目錄如下:

修改urls.py,增加路徑

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', views.login),
    path('index/', views.index),
    path('logout/', views.logout),
    path('', views.index),
]
View Code

修改views.py,增加註銷

def logout(request):  # 登出
    auth.logout(request)
    return redirect("/index/")
View Code

修改index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
    <script src="/static/js/jquery.js"></script>
    <script src="/static/bootstrap/js/bootstrap.js"></script>
    <style>
        .desc{
            text-align: justify;
        }

        .info{
            margin-top: 10px;
        }

    </style>
</head>
<body>
<nav class="navbar navbar-default">
    <div class="container-fluid">
        <!-- Brand and toggle get grouped for better mobile display -->
        <div class="navbar-header">
            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                    data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                <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>

        <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
            <ul class="nav navbar-nav">
                <li class="active"><a href="#">新聞 <span class="sr-only">(current)</span></a></li>
                <li><a href="#">博問</a></li>

            </ul>

            <ul class="nav navbar-nav navbar-right">
                {% if request.user.username %}
                    <li><a href="#"><span class="glyphicon glyphicon-user"></span>&nbsp;{{ request.user.username }}</a>
                    </li>
                    <li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
                           aria-expanded="false">Dropdown <span class="caret"></span></a>
                        <ul class="dropdown-menu">
                            <li><a href="#">修改密碼</a></li>
                            <li><a href="#">個人資訊</a></li>
                            <li><a href="/logout/">登出</a></li>
                            <li role="separator" class="divider"></li>
                            <li><a href="#">Separated link</a></li>
                        </ul>
                    </li>

                {% else %}
                    <li><a href="/login/">登陸</a></li>
                    <li><a href="#">註冊</a></li>
                {% endif %}


            </ul>
        </div><!-- /.navbar-collapse -->
    </div><!-- /.container-fluid -->
</nav>

<div class="container-fluid">
    <div class="row">
        <div class="col-md-3">
            <div class="panel panel-primary">
                <div class="panel-heading">
                    <h3 class="panel-title">Panel title</h3>
                </div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>

            <div class="panel panel-danger">
                <div class="panel-heading">
                    <h3 class="panel-title">Panel title</h3>
                </div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
        </div>
        <div class="col-md-6">

            222

        </div>
        <div class="col-md-3">

            <div class="panel panel-warning">
                <div class="panel-heading">
                    <h3 class="panel-title">Panel title</h3>
                </div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
            <div class="panel panel-info">
                <div class="panel-heading">
                    <h3 class="panel-title">Panel title</h3>
                </div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
            <div class="panel panel-success">
                <div class="panel-heading">
                    <h3 class="panel-title">Panel title</h3>
                </div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>

        </div>
    </div>
</div>

</body>
</html>
View Code

重新登入,效果如下:

 

新增內容

 使用django自帶的admin後臺,快速新增資料。

訪問後臺頁面,這裡必須是超級使用者。上面已經建立了超級使用者xiao

預設是空的

操作表,必須要註冊

修改views.py同級目錄下的admin.py

註冊所有的模型表

from django.contrib import admin

# Register your models here.

from blog import models

admin.site.register(models.UserInfo)
admin.site.register(models.Blog)
admin.site.register(models.Category)
admin.site.register(models.Tag)
admin.site.register(models.Article2Tag)
admin.site.register(models.Article)
admin.site.register(models.ArticleUpDown)
admin.site.register(models.Comment)
View Code

再次重新整理頁面

 

點選Articles,新增文章

 

從http://www.py3study.com 上面copy一篇部落格

注意內容都是html程式碼

 新增分類

 新增站點

 

 儲存

點選儲存

 新增成功

多新增幾篇部落格

首頁文章展示

修改settings.py,更改時區

TIME_ZONE = 'Asia/Shanghai'

修改index檢視函式

def index(request):
    article_list=Article.objects.all()
    return render(request,"index.html",{"article_list":article_list})
View Code

修改index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
    <script src="/static/js/jquery.js"></script>
    <script src="/static/bootstrap/js/bootstrap.js"></script>
    <style>
        .desc{
            text-align: justify;
        }

        .info{
            margin-top: 10px;
        }

    </style>
</head>
<body>
<nav class="navbar navbar-default">
    <div class="container-fluid">
        <!-- Brand and toggle get grouped for better mobile display -->
        <div class="navbar-header">
            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                    data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                <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>

        <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
            <ul class="nav navbar-nav">
                <li class="active"><a href="#">新聞 <span class="sr-only">(current)</span></a></li>
                <li><a href="#">博問</a></li>

            </ul>

            <ul class="nav navbar-nav navbar-right">
                {% if request.user.username %}
                    <li><a href="#"><span class="glyphicon glyphicon-user"></span>&nbsp;{{ request.user.username }}</a>
                    </li>
                    <li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
                           aria-expanded="false">Dropdown <span class="caret"></span></a>
                        <ul class="dropdown-menu">
                            <li><a href="#">修改密碼</a></li>
                            <li><a href="#">個人資訊</a></li>
                            <li><a href="/logout/">登出</a></li>
                            <li role="separator" class="divider"></li>
                            <li><a href="#">Separated link</a></li>
                        </ul>
                    </li>

                {% else %}
                    <li><a href="/login/">登陸</a></li>
                    <li><a href="#">註冊</a></li>
                {% endif %}


            </ul>
        </div><!-- /.navbar-collapse -->
    </div><!-- /.container-fluid -->
</nav>

<div class="container-fluid">
    <div class="row">
        <div class="col-md-3">
            <div class="panel panel-primary">
                <div class="panel-heading">
                    <h3 class="panel-title">Panel title</h3>
                </div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>

            <div class="panel panel-danger">
                <div class="panel-heading">
                    <h3 class="panel-title">Panel title</h3>
                </div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
        </div>
        <div class="col-md-6">

            <div class="article_list">
                {% for article in article_list %}
                 <div class="article_item">
                      <h5><a href="">{{ article.title }}</a></h5>
                      <div>
                          <span class="media-left"><a href=""><img width="60" height="60" src="https://ss0.baidu.com/6ONWsjip0QIZ8tyhnq/it/u=1758343206,1224786249&fm=58&bpow=1024&bpoh=1536" alt=""></a></span>

                          <span class="media-right small desc ">
                              {{ article.desc }}
                          </span>

                      </div>
                      <div class="info small">
                            <span><a href="">{{ article.user.username }}</a></span> &nbsp;
                            釋出於 <span>{{ article.create_time|date:'Y-m-d H:i' }}</span>&nbsp;&nbsp;
                           <span class="glyphicon glyphicon-comment"></span><a href="">評論({{ article.comment_count }})</a>&nbsp;&nbsp;
                           <span class="glyphicon glyphicon-thumbs-up"></span><a href="">點贊({{ article.up_count }})</a>
                      </div>
                 </div>
                    <hr>
                {% endfor %}
            </div>



        </div>
        <div class="col-md-3">

            <div class="panel panel-warning">
                <div class="panel-heading">
                    <h3 class="panel-title">Panel title</h3>
                </div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
            <div class="panel panel-info">
                <div class="panel-heading">
                    <h3 class="panel-title">Panel title</h3>
                </div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
            <div class="panel panel-success">
                <div class="panel-heading">
                    <h3 class="panel-title">Panel title</h3>
                </div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>

        </div>
    </div>
</div>

</body>
</html>
View Code

訪問首頁,效果如下:

 

 

個人站點展示

比如部落格園範圍個人站點是域名加使用者名稱,就可以了,比如:

https://www.cnblogs.com/xiao987334176

如果使用者不存在,會提示404頁面

增加404頁面

修改urls.py,增加路徑。注意匯入re_path

from django.contrib import admin
from django.urls import path,re_path
from blog import views
urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', views.login),
    path('index/', views.index),
    path('logout/', views.logout),
    path('', views.index),
    re_path('(?P<username>\w+)', views.homesite),
]
View Code

修改views.py,增加檢視函式

def homesite(request,username):
    """
    查詢
    :param request:
    :param username:
    :return:
    """

    # 查詢當前站點的使用者物件
    user=UserInfo.objects.filter(username=username).first()
    if not user:
        return render(request,"not_found.html")

    return render(request,"homesite.html",{"user":user})
View Code

在templates目錄建立檔案not_found.html

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


<div class="container" style="margin-top: 100px">
    <div class="text-center">
        <a href="http://www.cnblogs.com/"><img src="/static/img/logo_small.gif" alt="cnblogs"></a>
        <p><b>404.</b> 抱歉! 您訪問的資源不存在!</p>
        <p class="d">請確認您輸入的網址是否正確,如果問題持續存在,請發郵件至 [email protected] 與 <strong style="font-size: 28px">xiao</strong> 聯絡。</p>
        <p><a href="/">返回網站首頁</a></p>

    </div>
</div>
</body>
</html>
View Code

建立homesite.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h3>{{ user }}</h3>
</body>
</html>
View Code

訪問網頁:http://127.0.0.1:8000/xiao

訪問一個不存在的使用者

http://127.0.0.1:8000/123

頁面提示404

 

展示文章列表

修改homesite檢視函式

def homesite(request,username):
    """
    查詢
    :param request:
    :param username:
    :return:
    """

    # 查詢當前站點的使用者物件
    user=UserInfo.objects.filter(username=username).first()
    if not user:
        return render(request,"not_found.html")
    # 查詢當前站點物件
    blog=user.blog

    # 查詢當前使用者釋出的所有文章
    article_list=Article.objects.filter(user__username=username)

    return render(request,"homesite.html",{"blog":blog,"article_list":article_list})
View Code

修改homesite.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <style>
        *{
            margin: 0;
            padding: 0;
        }
        .header{
            width: 100%;
            height: 59px;
            background-color: #369;
        }
        .header .title{
            line-height: 59px;
            color: white;
            font-weight: lighter;
            margin-left: 20px;
            font-size: 18px;
        }

        .left_region{
            margin-top: 10px;
        }

        .info{
          margin-top: 10px;
          color: darkgray;

        }
    </style>
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
    <script src="/static/js/jquery.js"></script>
    <script src="/static/bootstrap/js/bootstrap.js"></script>
</head>
<body>
<div class="header">
    <p class="title">{{ blog.title }}</p>
</div>


<div class="container-fluid">
    <div class="row">
        <div class="col-md-3">
            <div class="left_region">
                 <div class="panel panel-success">
                <div class="panel-heading">
                    <h3 class="panel-title">Panel title</h3>
                </div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
                 <div class="panel panel-warning">
                    <div class="panel-heading">
                        <h3 class="panel-title">Panel title</h3>
                    </div>
                    <div class="panel-body">
                        Panel content
                    </div>
                </div>
                 <div class="panel panel-info">
                    <div class="panel-heading">
                        <h3 class="panel-title">Panel title</h3>
                    </div>
                    <div class="panel-body">
                        Panel content
                    </div>
                </div>
            </div>
        </div>
        <div class="col-md-9">

             <div class="article_list">
                {% for article in article_list %}
                 <div class="article_item clearfix">
                      <h5><a href="">{{ article.title }}</a></h5>
                      <div>

                          <span class="small desc ">
                              {{ article.desc }}
                          </span>

                      </div>
                      <div class="info small pull-right">
                            釋出於 <span>{{ article.create_time|date:'Y-m-d H:i' }}</span>&nbsp;&nbsp;
                           <span class="glyphicon glyphicon-comment"></span><a href="">評論({{ article.comment_count }})</a>&nbsp;&nbsp;
                           <span class="glyphicon glyphicon-thumbs-up"></span><a href="">點贊({{ article.up_count }})</a>
                      </div>
                 </div>
                    <hr>
                {% endfor %}
            </div>

        </div>
    </div>
</div>


</body>
</html>
View Code

訪問xiao的個人站點,效果如下:

 這個時候發現,左上角沒有顯示部落格標題。那是因為使用