Django博客項目之個人站點
項目cnblog_s20的urls.py內容:
from django.conf.urls import url,include from django.contrib import admin from blog import views from django.views.static import serve from cnblog_s20 import settings urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^login/', views.login), url(r'^reg/', views.reg), url(r'^logout/', views.logout), url(r'^valid_img/', views.valid_img), url(r'^index/', views.index), url(r'^$', views.index), url(r'^blog/', include("blog.urls")), #做分發,訪問blog做分發 # media 配置 url(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}), ]
應用的urls.py內容:
from django.conf.urls import url, include from django.contrib import admin from blog import views from django.views.static import serve from cnblog_s20 import settings urlpatterns = [ url(r'^(?P<username>\w+)/$',views.homesite), url(r'^(?P<username>\w+)/(?P<condition>tag|cate|achrive)/(?P<params>.*)',views.homesite), url(r'^(?P<username>\w+)/articels/(?P<article_id>\d+)',views.article_detail), ]
二、日期歸檔
1、數據庫類型
表示時間值的日期和時間類型為DATETIME、DATE、TIMESTAMP、TIME和YEAR
date類型-------> 2018-05-01 time類型-------> 19:42:22 datetime類型-------> 2018-05-01 19:42:22 MySQL對應的方法: date_format sqlite對應的方法 :striftime
2、extra
extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
有些情況下,Django的查詢語法難以簡單的表達復雜的 WHERE 子句,對於這種情況, Django 提供了 extra() QuerySet修改機制 — 它能在 QuerySet生成的SQL從句中註入新子句
(1)參數之select
The select 參數可以讓你在 SELECT 從句中添加其他字段信息,它應該是一個字典,存放著屬性名到 SQL 從句的映射。
queryResult=models.Article
.objects.extra(select={'is_recent': "create_time > '2018-05-05'"})
結果集中每個 Entry 對象都有一個額外的屬性is_recent, 它是一個布爾值,表示 Article對象的create_time 是否晚於2018-05-05,true表示晚於2018-05-05
#sqlite數據庫: article_obj=models.Article.objects .extra(select={"standard_time":"strftime('%%Y-%%m-%%d',create_time)"}) .values("standard_time","nid","title") print(article_obj) # <QuerySet [{'title': 'MongoDb 入門教程', 'standard_time': '2018-05-05', 'nid': 1}]>
(2)參數之where / tables
您可以使用where定義顯式SQL WHERE子句 - 也許執行非顯式連接。您可以使用tables手動將表添加到SQL FROM子句。
where和tables都接受字符串列表。所有where參數均為“與”任何其他搜索條件。
queryResult=models.Article .objects.extra(where=['nid in (1,3) OR title like "py%" ','nid>2'])
3、ORM分組查詢
當前站點以年月形式顯示的日期以及對應的文章數 article_list=Article.objectsv.filter(user=user).extra(select={"time":"strftime('%%Y-%%m',create_time)"}).values("time").annotate(c=Count("title")).values_list("time", "c")
4、表關系練習
(1)創建表關系
models.py文件內容:
from django.db import models class Book(models.Model): title = models.CharField(max_length=32) price = models.DecimalField(max_digits=6, decimal_places=2) create_time = models.DateField() memo = models.CharField(max_length=32, default="") publish = models.ForeignKey(to="Publish", default=1) author = models.ManyToManyField("Author") def __str__(self): return self.title class Publish(models.Model): name = models.CharField(max_length=32) email = models.CharField(max_length=32) class Author(models.Model): name = models.CharField(max_length=32) def __str__(self): return self.name class AuthorDetail(models.Model): tel = models.CharField(max_length=32) email = models.EmailField() author = models.OneToOneField("Author") def __str__(self): return self.email
(2)ORM分組查詢
annotate():按annotate前面的select字段進行group by
多表: Publish.objects.all().annotate(c=Count(book)).values("name", "c") #每一個出版社出版的名字和對應的書籍個數 Book.objects.all().annotate(c=Count(authors)).values("title", "c") #每一本書籍和對應的作者的個數 Author.objects.all().annotate(x=Max(book__prcie)) #每一個作者出版書籍的最高價格 單表: Book.objects.all().values("publish").annotate(Count("title")) ret = Article.objects.all().values("user").annotate(c=Count("title")).values("user_id", "c") #每一個作者的user_id對應的文章數 ret = Category.objects.filter(blog=blog).annotate(c=Count("article")).values("title", "c") #當前站點的每一個分類名稱和對應的文章數 ret = Tag.objects.filter(blog=blog).annotate(c=Count("article")).values("title", "c") #當前站點的每一個標簽名稱和對應的文章數
三、個人站點函數及html頁面
views.py文件添加homesite視圖函數:
def homesite(request,username,**kwargs): # 查當前站點的用戶對象 user=UserInfo.objects.filter(username=username).first() # 查詢當前站點對象 blog=user.blog # 查詢當前站點的所有文章,實現點擊tag|cate|achrive中的a標簽可以查看對應的文章 if kwargs: condition=kwargs.get("condition") #得到url的路徑類型:tag|cate|achrive其中一個 params=kwargs.get("params") if condition=="cate": article_list=Article.objects.filter(user=user).filter(category__title=params) # 當前站點的所有文章的分類對象 elif condition=="tag": article_list=Article.objects.filter(user=user).filter(tags__title=params) # 當前站點的所有文章的標簽對象 else: year,month=params.split("-") article_list=Article.objects.filter(user=user).filter(create_time__year=year,create_time__month=month) # 當前站點的所有文章的日期對象 else: article_list=Article.objects.filter(user=user) #訪問的個人站點,顯示當前站點的所有文章 return render(request,"homesite.html",locals())
homesite.html頁面:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Title</title> <style> * { margin: 0; {#清除邊距#} padding: 0; } .header { width: 100%; height: 60px; background-color: #369; line-height: 60px; {#文本居住#} } .header .title { font-size: 20px; font-weight: 100; color: white; margin-left: 20px; {#向右偏移20px#} } </style> <link rel="stylesheet" href="/static/bs/css/bootstrap.css"> <script src="/static/js/jquery-3.2.1.min.js"></script> <script src="/static/bs/js/bootstrap.js"></script> </head> <body> <div> <p>{{ blog.title }}</p> </div> <div> <div> <div> <div class="panel panel-warning"> <div> <h3>我的分類</h3> </div> <div> {% for cate in cate_list %} <p><a href="/blog/{{ username }}/cate/{{ cate.0 }}">{{ cate.0 }}({{ cate.1 }})</a></p> {#分類及對應的文章數#} {% endfor %} </div> </div> <div class="panel panel-danger"> <div> <h3>文章標簽</h3> </div> <div> {% for tag in tag_list %} <p><a href="/blog/{{ username }}/tag/{{ tag.0 }}">{{ tag.0 }}({{ tag.1 }})</a></p> {#標簽及對應的文章數#} {% endfor %} </div> </div> <div class="panel panel-info"> <div> <h3>日期歸檔</h3> </div> <div> {% for date in date_list %} <p><a href="/blog/{{ username }}/achrive/{{ date.0 }}">{{ date.0 }}({{ date.1 }})</a></p> {% endfor %} </div> </div> </div> <div> <div> {% for article in article_list %} <div> <h5><a href="/blog/{{ username}}/articels/{{ article.pk }}">{{ article.title }}</a></h5> <div> <div> <div> <div> {{ article.desc }} </div> </div> </div> </div> <div class="small info pull-right"> 發布於 <span>{{ article.create_time|date:'Y-m-d H:i' }}</span> <span class="glyphicon glyphicon-comment" style="color: #1b6d85;vertical-align: -3px"></span>評論({{ article.comment_count }}) <span class="glyphicon glyphicon-thumbs-up" style="color: #1b6d85;vertical-align: -3px"></span>點贊({{ article.up_count }}) </div> </div> <hr> {% endfor %} </div> {% endblock %} </div> </div> </div> </body> </html>
四、頁面繼承
個人站點和文章詳情頁面左側部分都一樣,可以用頁面繼承防止代碼重復
base.html頁面:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Title</title> <style> * { margin: 0; padding: 0; } .header { width: 100%; height: 60px; background-color: #369; line-height: 60px; } .header .title { font-size: 20px; font-weight: 100; color: white; margin-left: 20px; } </style> <link rel="stylesheet" href="/static/bs/css/bootstrap.css"> <script src="/static/js/jquery-3.2.1.min.js"></script> <script src="/static/bs/js/bootstrap.js"></script> </head> <body> <div> <p>{{ blog.title }}</p> </div> <div> <div> <div> {% load my_tags %} {% get_query_data username %} </div> <div> {% block content %} {% endblock %} </div> </div> </div> </body> </html>
menu.html頁面:
<div> <div class="panel panel-warning"> <div> <h3>我的分類</h3> </div> <div> {% for cate in cate_list %} <p><a href="/blog/{{ username }}/cate/{{ cate.0 }}">{{ cate.0 }}({{ cate.1 }})</a></p> {% endfor %} </div> </div> <div class="panel panel-danger"> <div> <h3>文章標簽</h3> </div> <div> {% for tag in tag_list %} <p><a href="/blog/{{ username }}/tag/{{ tag.0 }}">{{ tag.0 }}({{ tag.1 }})</a></p> {% endfor %} </div> </div> <div class="panel panel-info"> <div> <h3>日期歸檔</h3> </div> <div> {% for date in date_list %} <p><a href="/blog/{{ username }}/achrive/{{ date.0 }}">{{ date.0 }}({{ date.1 }})</a></p> {% endfor %} </div> </div> </div>
homesite.html頁面:
{%extends "base.html" %} {% block content %} <div> {% for article in article_list %} <div> <h5><a href="/blog/{{ username}}/articels/{{ article.pk }}">{{ article.title }}</a></h5> <div> <div> <div> <div> {{ article.desc }} </div> </div> </div> </div> <div class="small info pull-right"> 發布於 <span>{{ article.create_time|date:'Y-m-d H:i' }}</span> <span class="glyphicon glyphicon-comment" style="color: #1b6d85;vertical-align: -3px"></span>評論({{ article.comment_count }}) <span class="glyphicon glyphicon-thumbs-up" style="color: #1b6d85;vertical-align: -3px"></span>點贊({{ article.up_count }}) </div> </div> <hr> {% endfor %} </div> {% endblock %}
五、文章詳情
views.py文件添加article_detail函數
def article_detail(request,username,article_id): # 查當前站點的用戶對象 user = UserInfo.objects.filter(username=username).first() # 查詢當前站點對象 blog = user.blog article_obj=Article.objects.filter(pk=article_id).first() #得到文章對象 return render(request,"article_detail.html",locals())
article_detail.html頁面:
{% extends "base.html" %} {% block content %} <h3>{{ article_obj.title }}</h3> {#標題居住#} <div> {{ article_obj.articledetail.content|safe }} </div> {% endblock %}
數據庫保存的是標簽,不加safe會顯示字符串,瀏覽器不能成功渲染,加上safe後就可以識別標簽,能夠渲染頁面,這樣就會執行可能存在的script等標簽,很不安全
所以我們必須加safe,但是要保證用戶存到數據庫的沒有script標簽,即將script標簽轉意或者過濾掉。
Django博客項目之個人站點