摘要:使用的形式捕獲值給中得參數(shù),比如,當(dāng)訪問(wèn)時(shí),將會(huì)將捕獲給這個(gè)值會(huì)傳到。表示刪除某個(gè)分類后該分類下所有的的外鍵設(shè)為空,所以我們同時(shí)設(shè)置了。多對(duì)多就不同,兩邊都要進(jìn)行配置。增加基本的用戶認(rèn)證功能。
準(zhǔn)備工作
新建一個(gè)Django項(xiàng)目
# 新建一個(gè)django項(xiàng)目 $ django-admin startproject mysite # 新建一個(gè)app $ django-admin startapp blog
項(xiàng)目的結(jié)構(gòu)
├── blog │?? ├── admin.py │?? ├── apps.py │?? ├── __init__.py │?? ├── migrations │?? │?? └── __init__.py │?? ├── models.py │?? ├── tests.py │?? └── views.py ├── manage.py └── mysite ├── __init__.py ├── settings.py ├── urls.py └── wsgi.py
# mysite/settings.py INSTALLED_APPS = [ "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", "blog", "markdown2" ]
$ python3 manage.py runserver $ python manage.py collectstatic
一般在urls.py中配置url,在models.py中配置model,在views.py中配置View。
urls.pyFunction views
1. Add an import: from my_app import views 2. Add a URL to urlpatterns: url(r"^$", views.home, name="home")
Class-based views
1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: url(r"^$", Home.as_view(), name="home")
Including another URLconf
1. Import the include() function: from django.conf.urls import url, include 2. Add a URL to urlpatterns: url(r"^blog/", include("blog.urls"))
# blog/urls.py from django.conf.urls import url from blog import views urlpatterns = [ url(r"^blog/$", views.IndexView.as_view(), name="index"), url(r"^blog/article/(?Pd+)$", views.ArticleDetailView.as_view(), name="detail"), url(r"^blog/category/(?P d+)$", views.CategoryView.as_view(), name="category"), url(r"^blog/tag/(?P d+)$", views.TagView.as_view(), name="tag"), ]
使用(?P<>d+)的形式捕獲值給<>中得參數(shù),比如(?P
# mysite/urls.py from django.conf.urls import url, include from django.contrib import admin from blog import views urlpatterns = [ url(r"^admin/", admin.site.urls), url(r"", include("blog.urls", namespace="blog", app_name="blog")) ]
其中namespace參數(shù)為我們指定了命名空間,這說(shuō)明這個(gè)urls.py中的url是blog app下的,這樣即使不同的app下有相同url也不會(huì)沖突了。
假設(shè)用戶要訪問(wèn)某篇文章,它會(huì)自動(dòng)解析 blog:detail 這個(gè)視圖函數(shù)對(duì)應(yīng)的 url,并且把 article.pk(文章的主鍵)傳遞給detail視圖函數(shù),details就是我們?cè)?b>blog/urls.py中指定的name。
{{ article.title }}
如果要訪問(wèn)某個(gè)目錄
{{ category.name }}models.py
django.db.models是orm框架的基礎(chǔ),在blog/models.py中新建Article, Category, Tag三個(gè)model。
class Article(models.Model): STATUS_CHOICES = ( ("d", "Draft"), ("p", "Published"), ) # 仍然使用默認(rèn)的 objects 作為 manager 的名字 objects = ArticleManager() title = models.CharField("標(biāo)題", max_length=70) body = models.TextField("正文") created_time = models.DateTimeField("創(chuàng)建時(shí)間", auto_now_add=True) last_modified_time = models.DateTimeField("修改時(shí)間", auto_now=True) status = models.CharField("文章狀態(tài)", max_length=1, choices=STATUS_CHOICES) # blank和null要同時(shí)設(shè)置為null,詳情參考官方文檔 abstract = models.CharField("摘要", max_length=54, blank=True, null=True, help_text="可選,如若為空將摘取正文的前54個(gè)字符") views = models.PositiveIntegerField("瀏覽量", default=0) likes = models.PositiveIntegerField("點(diǎn)贊數(shù)", default=0) topped = models.BooleanField("置頂", default=False) category = models.ForeignKey("Category", verbose_name="分類", null=True, on_delete=models.SET_NULL) tags = models.ManyToManyField("Tag", verbose_name="標(biāo)簽集合", blank=True) def __str__(self): return self.title class Meta: ordering = ["-last_modified_time"] # 新增 get_absolute_url 方法 def get_absolute_url(self): # 這里 reverse 解析 blog:detail 視圖函數(shù)對(duì)應(yīng)的 url return reverse("blog:detail", kwargs={"article_id": self.pk})
Django給我們提供了很多有用的字段,比如上面提到的CharFiled, TestField, DateTimeFiled等等,詳情請(qǐng)參考官方文檔。
Django中的一對(duì)多是在一中進(jìn)行設(shè)置,這里對(duì)應(yīng)于文章的分類,F(xiàn)oreignKey即數(shù)據(jù)庫(kù)中的外鍵。on_delete=models.SET_NULL表示刪除某個(gè)分類(category)后該分類下所有的Article的外鍵設(shè)為null(空),所以我們同時(shí)設(shè)置了null=True。多對(duì)多就不同,兩邊都要進(jìn)行配置。詳情請(qǐng)參考官方文檔。
class Category(models.Model): name = models.CharField("類名", max_length=20) created_time = models.DateTimeField("創(chuàng)建時(shí)間", auto_now_add=True) last_modified_time = models.DateTimeField("修改時(shí)間", auto_now=True) def __str__(self): return self.name
class Tag(models.Model): name = models.CharField("標(biāo)簽名", max_length=20) created_time = models.DateTimeField("創(chuàng)建時(shí)間", auto_now_add=True) last_modified_time = models.DateTimeField("修改時(shí)間", auto_now=True) def __str__(self): return self.name
評(píng)論功能的實(shí)現(xiàn)
class BlogComment(models.Model): user_name = models.CharField("評(píng)論者名字", max_length=100) user_email = models.EmailField("評(píng)論者郵箱", max_length=255) body = models.TextField("評(píng)論內(nèi)容") created_time = models.DateTimeField("評(píng)論發(fā)表時(shí)間", auto_now_add=True) article = models.ForeignKey("Article", verbose_name="評(píng)論所屬文章", on_delete=models.CASCADE) def __str__(self): return self.body[:20]
class ArticleManage(models.Manager): """ 繼承自默認(rèn)的 Manager ,為其添加一個(gè)自定義的 archive 方法 """ def archive(self): date_list = Article.objects.datetimes("created_time", "month", order="DESC") # 獲取到降序排列的精確到月份且已去重的文章發(fā)表時(shí)間列表 # 并把列表轉(zhuǎn)為一個(gè)字典,字典的鍵為年份,值為該年份下對(duì)應(yīng)的月份列表 date_dict = defaultdict(list) for d in date_list: date_dict[d.year].append(d.month) # 模板不支持defaultdict,因此我們把它轉(zhuǎn)換成一個(gè)二級(jí)列表,由于字典轉(zhuǎn)換后無(wú)序,因此重新降序排序 return sorted(date_dict.items(), reverse=True)
我們首先要在project_name/settings.py中配置好相應(yīng)的配置文件
DATABASES = { "default": { "ENGINE": "django.db.backends.mysql", "NAME": "DB_NAME", "USER": "DB_USER", "PASSWORD": "DB_PASSWORD", "HOST": "localhost", # Or an IP Address that your DB is hosted on "PORT": "3306", } }
定義完畢后,我們執(zhí)行下面的命令就在數(shù)據(jù)庫(kù)中可以生成相應(yīng)的數(shù)據(jù)表:
$ python manage.py makemigrations $ python manage.py migrateadmins.py
參考Mozila的教程以及結(jié)合官方文檔。
views.py下面要使用markdown2,所以在INSTALLED_APP里面要添加markdown2,不過(guò)這個(gè)mardown解析非常的不好,并且弄完還要去下載相應(yīng)的markdown的css文件,有個(gè)專門的網(wǎng)站。
from blog.models import Article, Tag, Category from django.views.generic import ListView, DetailView import markdown2 class IndexView(ListView): # template_name屬性用于指定使用哪個(gè)模板進(jìn)行渲染 template_name = "blog/index.html" # context_object_name屬性用于給上下文變量取名(在模板中使用該名字) context_object_name = "article_list" def get_queryset(self): article_list = Article.objects.filter(status="p") for article in article_list: article.body = markdown2.markdown(article.body, ) return article_list def get_context_data(self, **kwargs): kwargs["category_list"] = Category.objects.all().order_by("name") # 調(diào)用 archive 方法,把獲取的時(shí)間列表插入到 context 上下文中以便在模板中渲染 kwargs["date_archive"] = Article.objects.archive() kwargs["tag_list"] = Tag.objects.all().order_by("name") return super(IndexView, self).get_context_data(**kwargs)
上面因?yàn)槲覀円M(jìn)行markdown處理,所以重新自定義了get_queryset,如果不要進(jìn)行相應(yīng)的處理,直接制定model就行了,get_context_data可以添加一些額外的字段,比如以后我們要在首頁(yè)的側(cè)邊欄顯示目錄和標(biāo)簽,所以這里要添加一個(gè)category_list和tag_list。
class ArticleDetailView(DetailView): model = Article template_name = "blog/detail.html" context_object_name = "article" # pk_url_kwarg會(huì)自動(dòng)和model中相應(yīng)的主鍵對(duì)應(yīng),aritlce_id就是下面配置的URLCONF pk_url_kwarg = "article_id" # 為了讓文章以markdown形式展現(xiàn),我們重寫get_object()方法 def get_object(self): obj = super(ArticleDetailView, self).get_object() obj.body = markdown2.markdown(obj.body) return obj # 新增 form 到 context def get_context_data(self, **kwargs): kwargs["comment_list"] = self.object.blogcomment_set.all() kwargs["form"] = BlogCommentForm() return super(ArticleDetailView, self).get_context_data(**kwargs)
class CategoryView(ListView): template_name = "blog/index.html" context_object_name = "article_list" def get_queryset(self): # url里的cate_id傳遞給CategoryView,傳遞的參數(shù)在kwargs屬性中獲取 article_list = Article.objects.filter(category=self.kwargs["cate_id"],status="p") for article in article_list: article.body = markdown2.markdown(article.body, ) return article_list def get_context_data(self, **kwargs): # 增加一個(gè)category_list,用于在頁(yè)面顯示所有分類,按照名字排序 kwargs["category_list"] = Category.objects.all().order_by("name") return super(CategoryView, self).get_context_data(**kwargs)
class TagView(ListView): template_name = "blog/index.html" context_object_name = "article_list" def get_queryset(self): """ 根據(jù)指定的標(biāo)簽獲取該標(biāo)簽下的全部文章 """ article_list = Article.objects.filter(tags=self.kwargs["tag_id"], status="p") for article in article_list: article.body = markdown2.markdown(article.body, extras=["fenced-code-blocks"], ) return article_list def get_context_data(self, **kwargs): kwargs["tag_list"] = Tag.objects.all().order_by("name") return super(TagView, self).get_context_data(**kwargs)
from django.views.generic.edit import FormView class CommentPostView(FormView): form_class = BlogCommentForm template_name = "blog/detail.html" def form_valid(self, form): target_article = get_object_or_404(Article, pk=self.kwargs["article_id"]) # 調(diào)用ModelForm的save方法保存評(píng)論,設(shè)置commit=False則先不保存到數(shù)據(jù)庫(kù), # 而是返回生成的comment實(shí)例,直到真正調(diào)用save方法時(shí)才保存到數(shù)據(jù)庫(kù)。 comment = form.save(commit=False) # 把評(píng)論和文章關(guān)聯(lián) comment.article = target_article comment.save() # 評(píng)論生成成功,重定向到被評(píng)論的文章頁(yè)面,get_absolute_url 請(qǐng)看下面的講解。 self.success_url = target_article.get_absolute_url() return HttpResponseRedirect(self.success_url) def form_invalid(self, form): target_article = get_object_or_404(Article, pk=self.kwargs["article_id"]) # 不保存評(píng)論,回到原來(lái)提交評(píng)論的文章詳情頁(yè)面 return render(self.request, "blog/detail.html", { "form": form, "article": target_article, "comment_list": target_article.blogcomment_set.all(), })template
{% for %}循環(huán)標(biāo)簽,{% if %}判斷標(biāo)簽. {{ variable }}是一些非常常用的標(biāo)簽
在模板文件中我們可以這樣使用,views.py中已經(jīng)指定了context_object_name = "article_list",并且已經(jīng)在get_queryset()中進(jìn)行了markdown處理
{% for article in article_list %} {{article.title}}
通常都會(huì)設(shè)置一個(gè)通用的父模板:
{% extends "base_generic.html" %} {% block content %} ... {% endblock %}
好像要這么這么設(shè)置:
TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", "DIRS": [os.path.join(BASE_DIR, "blog/templates")] , "APP_DIRS": True, ... ]靜態(tài)文件
由于源代碼丟失,具體情況記得不太清晰,靜態(tài)文件路徑要設(shè)置好,如果js文件加載異常,可能是加載順序的問(wèn)題。
base_generic.html大概就是下面這樣的格式:
{% load staticfiles %}Myblog ...
下面這樣設(shè)置貌似有點(diǎn)問(wèn)題:
# mysite/settings.py STATIC_URL = "/static/" STATICFILES = os.path.join(BASE_DIR, "blog/static")
具體參考官方文檔
部署使用uwsgi+nginx
/etc/nginx/sites-available/mysite.conf,blog是app名字,static文件放在了下面,建議直接放在mysite下面,template也是一樣:
server { listen 80; location /static/ { alias /home/omrsf/mysite/blog/static/; } location / { uwsgi_pass 127.0.0.1:8001; include /etc/nginx/uwsgi_params; } }
uwsgi -i uwsgi.ini來(lái)啟動(dòng)uwsgi進(jìn)程,結(jié)合nohup &:
[uwsgi] socket = 127.0.0.1:8001 chdir=/home/ormsf/mysite/ wsgi-file = mysite/wsgi.py processes = 2 threads = 4 chmod-socket = 664改進(jìn)
目前文章是直接在admin.py中注冊(cè)model,然后去admin后臺(tái)發(fā)布的,可以做成api接口,做一個(gè)在線的編輯器。增加基本的用戶認(rèn)證功能。
零碎知識(shí)點(diǎn) null和blank的區(qū)別null 是針對(duì)數(shù)據(jù)庫(kù)而言,如果 null=True, 表示數(shù)據(jù)庫(kù)的該字段可以為空。
blank 是針對(duì)表單的,如果 blank=True,表示你的表單填寫該字段的時(shí)候可以不填,比如 admin 界面下增加 model 一條記錄的時(shí)候。直觀的看到就是該字段不是粗體。
render與render_response優(yōu)先采用render。
get_absolute_urlmodel有一個(gè)get_absolute_url,它可以與reverse結(jié)合起來(lái)。
參考資料GitHub項(xiàng)目地址
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/38365.html
摘要:這里使用版本如果你使用是版本需將相關(guān)命令中的替換成替換成以及注意其它版本查差異性安裝安裝安裝查看版本創(chuàng)建項(xiàng)目為項(xiàng)目名創(chuàng)建數(shù)據(jù)庫(kù)默認(rèn)使用如果使用其它數(shù)據(jù)庫(kù)請(qǐng)配置相關(guān)設(shè)置文件查看項(xiàng)目開啟自帶的小型開發(fā)服務(wù)器為可選配置,不指定的話默認(rèn)為開 這里使用python3版本 如果你使用是python2.7版本 需將相關(guān)命令中的python3替換成python;pip3替換成pip;以及注意其它版本查...
摘要:項(xiàng)目地址部署的方案都在腳本里頭,說(shuō)明如下使用方法版本簡(jiǎn)單介紹是一個(gè)利用轉(zhuǎn)發(fā)操作系統(tǒng)中部署的基于框架和框架以及一個(gè)的服務(wù)。個(gè)服務(wù)是部署在環(huán)境中,通過(guò)和進(jìn)行發(fā)送和接收消息。在前臺(tái)以及整個(gè)主要利用去操作。 項(xiàng)目地址:https://github.com/yuyangit/BMProject 部署的方案都在腳本里頭,說(shuō)明如下: BMPlatform使用方法 版本 v0.2 1.簡(jiǎn)單介紹...
摘要:項(xiàng)目地址部署的方案都在腳本里頭,說(shuō)明如下使用方法版本簡(jiǎn)單介紹是一個(gè)利用轉(zhuǎn)發(fā)操作系統(tǒng)中部署的基于框架和框架以及一個(gè)的服務(wù)。個(gè)服務(wù)是部署在環(huán)境中,通過(guò)和進(jìn)行發(fā)送和接收消息。在前臺(tái)以及整個(gè)主要利用去操作。 項(xiàng)目地址:https://github.com/yuyangit/BMProject 部署的方案都在腳本里頭,說(shuō)明如下: BMPlatform使用方法 版本 v0.2 1.簡(jiǎn)單介紹...
摘要:靜態(tài)資源路徑可以有多個(gè),所以這里使用一個(gè)列表進(jìn)行配置再次進(jìn)入,完美后記現(xiàn)在只涉及到了項(xiàng)目的配置和一些基礎(chǔ)的配置,沒(méi)有涉及到請(qǐng)求從開始到完成的任何內(nèi)容。下篇教程將集中進(jìn)行記錄。 前言 推薦使用 virtualenv 創(chuàng)建 python 虛擬環(huán)境,防止因?yàn)槭褂?pip 安裝依賴到全局引起版本沖突的問(wèn)題,PyCharm 默認(rèn)會(huì)生成一個(gè) venv 目錄并創(chuàng)建虛擬環(huán)境,使用 IDE 自帶的終端...
閱讀 3703·2021-11-23 09:51
閱讀 1362·2021-11-10 14:35
閱讀 4009·2021-09-22 15:01
閱讀 1280·2021-08-19 11:12
閱讀 379·2019-08-30 15:53
閱讀 1690·2019-08-29 13:04
閱讀 3429·2019-08-29 12:52
閱讀 3055·2019-08-23 16:14