bolg項目

寫代碼要儘量的捕獲異常




模板的路徑能夠直接放到TEMPLATES裏面的DIRS當中,TEMPLATE_DIRS能夠取消掉
設置static靜態文件STATICFILES_DIRS裏面,這是一個元組
> virtualenv  env
# 以後會自動建立一個 env 文件夾
     # 下面,有: Include,Lib,Scripts 三個文件夾
 
# 若要進入隔離環境
env \Scripts\activate 
( env ) > 
# 此時便進入了隔離環境

virtualenv安裝到了python2.7裏面的site-package裏面了 site-packages裏面放的是第三方包。


而後設置靜態文件和模板,
url還能夠這樣寫,是什麼意思?這麼寫的意思是訪問localhost:8000而後訪問index,這個index是從blog.views裏面導入的,另外一種方式就是
直接手寫index的路徑,寫成blog.views.index都是同樣的

{% static  '.js' %}這樣寫會被翻譯成/static/.js

使用日誌器

在settings.py裏進行設置,對其中文件路徑進行修改
裏面的路徑若是不存在會在輸出錯誤日誌時建立
日誌器有不一樣級別
在views.py裏引入日誌器,經過import logging
logger = loggin.getLogger('blog.views')

經過錯誤日誌,能夠很好的把幫助咱們分析爲何出錯?

能夠把信息保存在settings.py裏面,也能夠保存在數據表當中
設置在settings裏面等因而至關於設置全局變量
在views.py當中引用
先import django.conf import settings
經過這種方式引用:site_name = settings.SITE_NAME
不過這種方式引用太麻煩
能夠直接定義一個函數,將settings內容讀取出來,進行輸出
   
   
   
   
def global_setting(): return{'SITE_NAME':settings.SITE_NAME,'SITE_DESC':settings.SITE_DESC,}
把這個方法加到settings.py裏面的TEMPLATES的OPTIONS的上下文處理器這個配置
在這個處理器執行的時候,每一個頁面均可以用到,
   
   
   
   
'blog.views.global_setting',
因而我能夠直接在模板當中調用global裏面的變量,字典的名字
如html當中
  
  
  
  
SITE_NAME


models設計:
當定義__unicode__的時候,return返回的爲字符串
用戶模型,能夠直接從Django裏面繼承,也能夠採用關聯的方式
用戶模型:
第一種:採用的繼承方式擴展用戶信息(本系統採用)須要在settings裏面進行設置
第二種:擴展,關聯的方式去擴展用戶信息
什麼意思?模型從Django裏面繼承,爲何不本身寫了而後繼承?
採用繼承的方式擴展用戶信息,幫咱們封裝了一些用戶分組和權限機制在裏面
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
在setttings裏面聲明AUTH_USER_MODEL = 'blog.User'
關聯表又是什麼東西?    
兩個表有聯繫,這個聯繫先理解爲外鍵,這兩個表就能夠叫作關聯表,能夠是多對一,多對多,一對一
migration又是什麼?

1. 新的命令

Django 1.7 爲咱們帶來了三個新命令:php

  • migrate: 用於執行遷移動做html

  • makemigrations: 基於當前的model建立新的遷移策略文件python

  • sqlmigrate: 顯示遷移的SQL語句mysql

值得注意的是, migration是基於App的, 所以, 咱們能夠針對某些app不啓用migration功能.web

2. 如何使用

migrations的使用很是簡單: 修改model, 好比增長field, 而後運行sql

    python manager.py makemigrations

你的mmodel會被掃描, 而後與以前的版本做比較, 在app的migrations目錄下生成本次遷移文件.shell

咱們建議查看一下該遷移文件, 確保沒有問題. 而後運行:數據庫

    python manager.py migrate

migrate命令會進行比較, 並應用該遷移.django

django.contirb標準庫是什麼?

Django標準庫

Django的標準庫存放在 django.contrib 包中。每一個子包都是一個獨立的附加功能包。 這些子包通常是互相獨立的,不過有些django.contrib子包須要依賴其餘子包。數組

在 django.contrib 中對函數的類型並無強制要求 。其中一些包中帶有模型(所以須要你在數據庫中安裝對應的數據表),但其它一些由獨立的中間件及模板標籤組成。

django.contrib 開發包共有的特性是: 就算你將整個django.contrib開發包刪除,你依然可使用 Django 的基礎功能而不會遇到任何問題。 當 Django 開發者向框架增長新功能的時,他們會嚴格根據這一原則來決定是否把新功能放入django.contrib中。

 

須要安裝的庫Django MySQL-python pip setuptoolls virtualenv wheel
pillow
安裝庫的過程mysqldb安裝不上:

pycharm虛擬環境virtualnv安裝MySQL擴展http://my.oschina.net/NoSay/blog/474567

這裏有教程

easy_install MySQL-python這個能夠用,大聲說一聲NB

關於Django Models的設計和使用,關於在Django中配置mysql數據庫,以及如何生成數據庫。

# -*- coding:utf-8 -*-
from django.db import models
from django.contrib.auth.models import AbstractUser


# 用戶模型.
class User(AbstractUser):
    avatar = models.ImageField(upload_to='avatar/%Y/%m', default='avatar/default.png', max_length=200, blank=True, null=True, verbose_name='用戶頭像')
    qq = models.CharField(max_length=20, blank=True, null=True, verbose_name='QQ號碼')
    mobile = models.CharField(max_length=11, blank=True, null=True, unique=True, verbose_name='手機號碼')

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

    def __unicode__(self):
        return self.username

還須要在settings裏面進行設置,#自定義用戶model
AUTH_USER_MODEL = 'blog.User'
avatar = models.ImageField(upload_to='avatar/%Y/%m', default='avatar/default.png', max_length=200, blank=True, null=True, verbose_name='用戶頭像')
ImageField是圖像字段 upload_to是上傳路徑 default默認圖片
須要在settings裏面設置上傳路徑

配置admin
裝Django1.9時,建立的superuser帳號和密碼不能相同,臥槽,1.9版本的密碼要求很規範

    from models import *   admin.site.register(User)  在admin當中進行設置
models若是不加修改,以默認選擇設置admin,還能夠自定義models
在admin裏面進行自定義
class ArticleAdmin(admin.ModelAdmin):
fields = ('title','desc','content')

admin.site.register(Article,ArticleAdmin)
若是不加後面的ArticleAdmin,就默認的形式進行設定
fields 顯示指定字段  exclude 出了指定字段,顯示其餘字段
fieldsets能夠對要設定的字段作一個很好的劃分,把一部分隱藏,一部分顯示
list_display能夠顯示指定的列
list_display_links指定列能夠點擊
還有不少屬性,須要用的時候查閱官方文檔

富文本編輯器
能夠不只僅插入文字,還能夠插入圖片,視頻等
django-admin中添加富文本編輯器的幾種方式:
一、使用第三方的一些庫,如django-ckeditor
(https://pypi.python.org/pypi/django-ckeditor)
二、在admin中定義富文本編輯器的widget
三、經過定義ModelAdmin的媒體文件

步驟:
一、下載kindeditor
複製到static的js目錄下
二、定義ModelAdmin的媒體文件
這個是在 admin當中進行配置的
class ArticleAdmin(admin.ModelAdmin):
exclude = ('title','desc','content')
class Media:
js = (
'/static/js/kindeditor-4.1.10/kindeditor-min.js',
'/static/js/kindeditor-4.1.10/lang/zh_CN.js',
'/static/js/kindeditor-4.1.10/config.js',
        )三、修改kindeditor的配置文件
也就是在config.js文件中新建一個對象
asp asp.net examples jsp php 這些文件能夠刪除
在KinderEditor的官方文檔照到相應的配置
而後再 config.js當中進行配置
   
   
   
   
     
     
     
     
Pillow是python的一個圖像處理庫,django-ckeditor須要依賴該庫。最簡單的安裝方法,固然是使用pip,假設你裝過pip,能夠直接運行如下命令安裝:



上傳文件
KinderEditor沒有提供python的上傳文件的接口,因此須要本身進行配置
固定上傳的目錄爲uploads
url(r"^uploads/(?P<path>.*)$", \ "django.views.static.serve", \ {"document_root": settings.MEDIA_ROOT,}),

uploads 是說明這是一個路由的地址, (?P<path>.*)$"這裏能夠是任意字符,   "django.views.static.serve"是調用django裏面的server方法
"
document_root": settings.MEDIA_ROOT,這是對應路徑
avatar = models.ImageField(upload_to='avatar/%Y/%m', default='avatar/default.png', max_length=200, blank=True, null=True, verbose_name='用戶頭像')
upload_to='avatar/%Y/%m'自定義上傳路徑,上傳到指定文件


步驟
在settings.py文件裏面進行設置
MEDIA_URL = '/uploads/'

MEDIA_ROOT = os.path.join(BASE_DIR, 'uploads')
建立uploads文件夾
在url文件當中引入settings   from django.conf import settings

url(r"^uploads/(?P<path>.*)$", \ "django.views.static.serve", \ {"document_root": settings.MEDIA_ROOT,}),

avatar = models.ImageField(upload_to='avatar/%Y/%m',在models裏面已經設置了上傳路徑,是在settings裏面設置的路徑下面,這裏寫的是avatar/年/月 存儲
http://localhost:8000/uploads/avatar/2015/12/mamao.jpg 由於在url裏面有設置,因此能夠直接在輸入url也能夠訪問到

富文本編輯器上傳文件
在blog下面新建一個models.py文件,直接找寫好的代碼
kindeditor圖片上傳返回數據格式說明:
# {"error": 1, "message": "出錯信息"}
# {"error": 0, "url": "圖片地址"}
配置url
from blog.upload im @csrf_exempt 這個裝飾器的做用是 再也不作遠程表單提交驗證
port upload_image
url(r'^admin/upload/(?P<dir_name>[^/]+)$', upload_image, name='upload_image'),  
upload_image是upload.py裏面的方法   
dir_name 是和upload_image裏面的傳入參數相對應的

在KendEditor設置上傳路徑,也就是先前設置富文本編輯器建立的config.js文件
uploadJson: '/admin/upload/kindeditor',  這個路徑是先前在url已經定義好的,這裏定義了在uplaod文件夾下面的kindeditor文件夾dir_name = dir_name + '/%d/%d/' %(today.year,today.month)在uploads.py裏面已經進行了定義了在kindeditor目錄下的路徑


KindEditor.ready(function(K) { K.create('textarea[name=content]',{ width:800, height:200, }); });

基本查詢

導入models在views.py裏面,
在index裏面進行設置, category_list = Category.objects.all()[ : 1 ] 導入分類信息,
return render(request, 'index.html' ,{ 'category_list' : category_list})將信息傳入到category_list當中
QuerySet[:1]這是隻取出頭一條信息,只是從數據庫取出一條信息,而不是取出全部信息而後進行截取
直接在base.html當中進行引用
{% for category in category_list %}
    <a href="base.html" target="_blank">{{category.name}}</a>
{% endfor %}
怎麼理解QuerySet的查詢是惰性的(當咱們去執行all,filter,get,是不會去執行sql的,
當咱們去調用查詢結果集的時候會執行sql)

{% for category in category_list %}
<a href="base.html" target="_blank">{{category.name}}</a>
{% endfor %}
改成 <a href="base.html" target="_blank">{{category.name}}</a>
這樣不會執行sql語句,雖然views.py裏面的index方法中定義了查詢語句
category_liset = Category.objects.all()
這樣作的話是不會執行sql語句的
若是在後面加上
for c in category_list:
    print(c)
這樣就會執行sql語句

小技巧:type(category_list) 返回的是QuerySet   type('sss')返回str
先寫註釋,再寫代碼思路會更加清晰
以models當中的數據表爲對象,在html裏面進行操做,在views裏面進行邏輯操做,傳遞參數給html,
在views裏面先導入相關的模塊
from django.core.paginator import Paginator,InvalidPage,EmptyPage,PageNotAnInteger
article_list = Article.objects.all()
paginator = Paginator(article_list,2)
try:
page = int(request.GET.get('page',1))
article_list = paginator.page(page)
except (EmptyPage,InvalidPage,PageNotAnInteger):
article_list = paginator.page(1)

<p class="autor"><span class="lm f_l"><a href="/">
{% for tag in article.tag.all %}{{ tag.name }}</a></span>{% endfor %}
<span class="dtime f_l">{{ article.date_publish |date:'Y-m-d' }}</span>
<span class="viewnum f_r">瀏覽(<a href="/">{{ article.click_count }}</a>
</span><span class="pingl f_r">評論(<a href="/">{{ article.comment_set.all.count }}</a>
</span></p>
{{ article.comment_set.all.count }}這麼寫的緣由 是comment作爲子表,是ForeignKey關聯,內置有count方法,能夠直接調用
{% for tag in article.tag.all %} tag是表,是一個多對多的關係

去重複方法distinct是Django自帶的去重複方法,對整個字段進行去重
三、django中直接使用sql的兩種方式 SELECT DISTINCT DATE_FORMAT(date_publish, '%Y-%m') as col_date FROM blog_article ORDER BY date_publish 3.一、raw (異常:Raw query must include the primary key,返回結果必須包含主鍵) 3.二、excute
能夠直接在Django中寫sql語句進行查詢,但不推薦這種方式
如 Article.objects.raw('SELECT DISTINCT DATE_FORMAT(date_publish, '%Y-%m') as col_date FROM blog_article ORDER BY date_publish')
這樣能夠直接進行查詢

自定義文章model的管理器,由於想要實現按年月吧文章歸檔的操做實現不了,因此自定義一個model來實現這個功能
有兩種方式 
1:新加一個數據處理的方法
2.改變原有的queryset,就是從新定義這個方法,改變這個方法的返回
主要使用第一種方法
在models.py裏面自定義Model管理器
class ArticleManager(models.Manager):
distinct_date_list = []
    def distinct_date(self):
date_list = self.values('date_publish')
#把日期的結果取出來
for date in date_list:
date = date['date_publish'].strftime('%Y%m文章存檔')
if date not in distinct_date_list:
distinct_date_list.append(date)
return distinct_date_list
在Article的類中進行設置
objects = ArticleManager()
再views.py裏面進行設置archive_list = Article.objects.distinct_date()
在base.html當中進行設置
<ul>
{% for archive in archive_list %}
<li>
<p><span class="tutime font-size-18"><a href=''>{{ archive }}</a></span></p>
</li>
{% endfor %}
</ul>
這樣設置後網頁上不會出現須要顯示的歸檔信息,緣由是編碼問題
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
導入這個在models.py裏面就能夠了
   
   
   
   http://blog.csdn.net/crazyhacking/article/details/39375535
   
   
   
   http://blog.csdn.net/intel80586/article/details/8566057
python在解碼的時候默認 以ASCLL碼的方式進行解碼

靠,今天實在是太粗心了,好惡心,就這麼幾分鐘就能搞定的事情,花了我近一個小時,日
url(r'^archive/$',archive,name='archive') 
url配置的時候,前面要加上 ^ 後米加上/$ $不會影響傳入的參數

配置archive.html
複製了index.html到archive.html當中,在views.py寫下archive的函數,
在url當中進行引用,再到base.html當中進行設置
<p><span class="tutime font-size-18"><a href='{% url 'archive' %}?year={{ archive | slice:":4" }}&month={{ archive | slice:"5:7" }}'>{{ archive }}</a></span></p>
使點擊分類文章時會跳轉到archive.html當中,
再到views.html當中進行設置其邏輯結構
將index函數裏面的分頁查詢的代碼拷貝下來,就能夠顯示內容了
article_list = Article.objects.filter(date_publish__icontains=year+'-'+month)
修改查詢的操做,這樣只會照到指定參數的內容
到archieve.html當中作一些修改
<h2>{{ request.GET.year }}/{{ request.GET.month }}歸檔文章</h2>
發如今這裏也可使用傳進來的參數
這裏須要傳入參數,由於QuerySet查詢是惰性的,不會一會兒查詢出全部的記錄只會查詢出當前頁面的內容,因此當跳轉頁面的時候,應該從新傳入參數


重構代碼:將重複的代碼提取出來
臥槽,今天有點不順啊, url( r'$' ,index,name = 'index' ),這個前面不加^這個,然而剛剛我加上了,就報了一個404錯誤

把index和archive裏面相同的代碼提取出來放到global_settings裏面

def global_setting(request):
#分類信息獲取(導航數據)
category_list = Category.objects.all()
#文章歸檔數據
archive_list = Article.objects.distinct_date()
return {
'category_list':category_list,
'archive_list':archive_list,
'SITE_NAME':settings.SITE_NAME,
'SITE_DESC':settings.SITE_DESC,
}
還有一些數據也能夠放到global_settings裏面
如:廣告數據,標籤雲數據,友情連接數據,文章排行榜數據

優化url:
當app多了的時候維護url變得困難,因此就選擇在每一個app下面創建url進行優化這種操做
複製工程下面的url到app當中,在工程當中:刪除工程url當中app相關url改成include在本項目中
所作的修改是:url('^',include(blog.urls)) 還要導入include from django.conf.urls import url,include
app url  刪除相關引入import只保留和app相關的url和import,

在views.py裏面封裝分頁代碼
由於函數index和函數archive都有分頁代碼,因此能夠把分頁代碼分裝成一個函數來引用
def getPage(request,article_list):
paginator = Paginator(article_list,2)
try:
page = int(request.GET.get('page',1))
article_list = paginator.page(page)
except (EmptyPage,InvalidPage,PageNotAnInteger):
article_list = paginator.page(1)
return article_list
由於始終是對取出來的內容進行的修改因此就直接返回article_list,在article_list當中,還須要用到request,
因此這裏須要傳入request
archive.html和index.html都有上一頁,下一頁,因此能夠Include提取出來
新建一個pagination.html把分頁的代碼直接複製進去,在到相應的位置,以{% include 'pagination.html' %}代替
而後發現archive的頁面在按下一頁後,參數沒有傳遞過去,因此須要一個判斷拼接字符串
文章排行:order_by()須要指定字段,不能這樣使用Article.objects.all().order_by()
選擇將文章進行分組,而後使用count函數

我發現凡是涉及到顯示數據內容,都會牽扯到數據庫操做,不必定,能夠是settings裏面設置的全局變量

return {
'category_list':category_list,
'archive_list':archive_list,
'SITE_NAME':settings.SITE_NAME,
'SITE_DESC':settings.SITE_DESC,
}
#站點基本信息設置
SITE_NAME = settings.SITE_NAME
SITE_DESC = settings.SITE_DESC
comment_count_list = Comment.objects.values('article').annotate(comment_count=Count('article')).order_by('-comment_count')
article_comment_list = [Article.objects.get(pk=comment['article']) for comment in comment_count_list]
return locals()
經驗證,comment['article']爲Article當中的id編號

在到base.html當中進行修改
<ul>
{% for article in article_comment_list %}
<li><a href="/" target="_blank">{{ article.title | slice:':15' }}</a></li>
{% endfor %}
</ul>
comment_count_list = Comment.objects.values('article').annotatennotate(comment_count=Count('article')).order_by('-comment_count')
.annotate的使用方法,Count的使用方法,return locals()能夠直接返回當前做用域的變量,因此能夠把裏面的鍵值對的形式寫成變量的形式,
article_comment_list = [Article.objects.get(pk=comment['article']) for comment in comment_count_list]
以數組的方式返回排完序的文章對象

自定義過濾器:
DoseNotExist異常,若是使用get沒有得到對象,那麼返回一個DoseNotExist異常
safe過濾器,把html轉換成頁面信息,不會直接打印出來
在templatetags包裏面定義一個html使用的時候須要加載到html當中
在此html當中
from django import template
register = remplate.Library()

@register.filter
def month_to_upper(key):
    return[] [key.month-1]

register.filter(' month_to_upper ', month_to_upper )


瀏覽排行
瀏覽量能夠直接從Article的click_count中取出,因此能夠直接經過取出Article全部對象而後對click_count進行排序便可

評論排行
評論排行和瀏覽排行不一樣,Comment和Article是關聯表,須要進行間接的排序,這裏須要討論一下

標籤雲
 標籤有一個Tag的類,子表是Article,因此能夠在把tag_list取出放到global當中,而後在views.py當中定義tag函數,當點擊tag的時候能夠進行跳轉,因此還要一個tag.html,在tag函數中主要是取出Article的對象,其它不變,篩選條件是,先取出Tag對象,取出Tag的點擊對象,當點擊的時候,應該把點擊標籤的id傳過去,再取出對應的Article
友情連接
友情連接的數據都已經寫好了,因此能夠直接在global當中取出Links的對象
廣告
<img id="slide-img-{{ ad.id }}" src="uploads/{{ ad.image_url }}" 
圖片的src目前有三種狀況
1:絕對路徑
2:靜態文件的相對路徑<img id="slide-img-1" src="{% static 'images/a1.jpg' %}" alt="" />
3:上傳文件的路徑<img id="slide-img-{{ ad.id }}" src="uploads/{{ ad.image_url }}" 直接寫uploads文件夾加上傳文件地址至關於就是絕對路徑
src="../uploads/{{ ad.image_url }}"這裏面須要加引號,寫的就是絕對路徑

引用關聯外鍵裏面的內容
class Article(models.Model):
date_publish = models.DateTimeField(auto_now_add=True, verbose_name='發佈時間')
user = models.ForeignKey(User, verbose_name='用戶')
article = Article.objects.get(pk=id)
{{ article.user.username }}






相關文章
相關標籤/搜索