前言
在学习Python的过程中,觉得有必要学一学Python做web开发,而django作为一种优秀的Python Web框架,自然成为了我的首选,经过不到一个月的学习,总算搞清楚了django的大部分结构和基本的语法,如果你想学django,就和我一起来做一个用django开发的小型个人博客吧!
了解django
django是遵循MVC设计模式的框架,MVC是Model、View、Controller这三个单词的缩写,分别代表了模型,视图,控制器。对于我个人的理解来讲,模型用来与数据库进行交互,视图用来封装html、js、css,控制器则用来处理程序的请求、逻辑结构等。
准备工作
Python3+django2.0+PycharmPro2018
创建项目
你可以使用Pycharm创建,更加方便。
你也可以使用命令行创建,django-admin startproject myblog,当然前提是你已经安装了django,并且cd到了你想把项目创建到哪个目录的具体位置。一行命令创建了一个myblog的项目,接下来我们就该创建app了,先来讲下app与项目之间的关系。
项目和app之间的关系
对于django来说,项目只是一个大框架,他的具体功能还需要在app里面实现,app所对应的就是一个一个的功能模块,比如拿chabug来说,有用户模块,也有文章模块,也有专题模块。
你可以进入到项目的目录,然后这样来创建app python3 manage.py startapp blog
运行
在Pycharm里面你只需要点击右上角的运行按钮就可以运行了,默认是运行在本地的8000端口,也就是127.0.0.1:8000,如果你需要在命令行里面运行,你可以这样python3 manage.py runserver 8000,当然这样运行的只能在本地访问,如何把我们的项目发布出去对公网用户开放呢?下面会讲到。
项目结构
manage.py 项目管理脚本,你可以通过python3 manage.py help查看你能够干什么 settings.py 项目的设置都存放在这 urls.py 这个是用来配置项目的url,例如127.0.0.1/chabug/,或者127.0.0.1/chuyu wsgi.py 部署的时候用到的,一般上用不到
URL与视图
视图
视图一般写在APP的views.py中,并且第一个参数永远是request对象,这个对象包含了一些请求信息,比如:请求方法GET、POST,头部headers信息等等,然后视图必须返回一个HttpResponseBase,比如下面这个:
from django.shortcuts import render,HttpResponse def hello(request): return HttpResponse("hello")
当然,你现在并不能在浏览器中看到HttpResponse返回的hello,因为我们还没有定义urls.py中的内容,下面就跟我来配置一波把!
URL映射
from django.contrib import admin from django.urls import path urlpatterns = [ path('admin/', admin.site.urls), ]
这是默认的配置,其中admin这一条是django系统自带的映射后台,不用管他。我们来添加一条url来映射我们的hello,首先从app导入views.py
form blog import views
然后添加一条映射关系
from django.contrib import admin from django.urls import path from blog import views urlpatterns = [ path('admin/', admin.site.urls), path('', views.hello), ]
django会自动从urlpatterns中寻找当前请求url所对应的规则,返回相应的信息。
这个时候在访问127.0.0.1:8000则会出现我们在视图中返回的HttpResponse信息hello
URL传参
两种方法
views.py
def A(request,id): text = "你请求的id是:%s " % id return HttpResponse(text) urls.py from django.contrib import admin from django.urls import path from blog import views urlpatterns = [ path('admin/', admin.site.urls), path('', views.hello), path('A/<id>', views.A), ]
你可以这样访问127.0.0.1/A/id
第二种
views.py
def B(request): id = request.GET.get['id'] text = "你请求的id是:%s " % id return HttpResponse(text) urls.py from django.contrib import admin from django.urls import path from blog import views urlpatterns = [ path('admin/', admin.site.urls), path('', views.hello), path('B/', views.B), ]
你可以这样访问 127.0.0.1:8000/B/?id=1
URL反转
之前我们都是通过url来访问视图函数。有时候我们知道这个视图函数,但是想反转回他的url。这时候就可以通过 reverse 来实现。示例代码如下:
reverse("list") > /book/list/ 传递参数 reverse("book:detail",kwargs={"book_id":1}) > /book/detail/1
URL和视图我们就暂时讲到这里,接下来我们要开始写了,模板的知识会融在其中。
创建模型
from django.db import models class Article(models.Model): title = models.CharField(max_length=50) #文章标题 category = models.CharField(max_length=50, blank=True) #文章分类 datetime = models.DateTimeField(auto_now_add=True) #文章发表日期 content = models.TextField(blank=True, null=True) #文章内容 def __str__(self): return self.title class Meta: ordering = ['-datetime'] #以日期倒序
创建完模型后我们需要把模型同步到数据库中
python3 manage.py makemigrations python3 manage.py migrate
然后在admin.py中注册下我们创建的模型
from django.contrib import admin from blog.models import Article # Register your models here. admin.site.register(Article)
注册模型让我们在django自带的后台管理中显示出来127.0.0.1:8000/admin
发布文章什么的都可以在这操作。
URL设计
我直接贴我的代码
from django.contrib import admin from django.urls import path from blog import views urlpatterns = [ path('admin/', admin.site.urls), path('', views.index, name='index'), path('<int:id>/', views.detail, name='detail'), path('archives/', views.archives, name='archives'), path('tag/<str:tag>', views.tags, name='tag'), path('search/', views.search, name='search') ]
视图设计
from django.shortcuts import render, redirect from blog.models import Article from django.http import Http404 # 首页视图,展示所有的文章 def index(request): sessionid = request.COOKIES.get('sessionid') post_list = Article.objects.all() return render(request,'index.html',{'post_list': post_list, 'sessionid':sessionid}) #文章详情视图,展示详细的文章内容 def detail(request,id): try: post=Article.objects.get(id=id) except: raise Http404 return render(request,'post.html',{'post':post}) #文章归档 def archives(request): try: post_list = Article.objects.all() except Article.DoesNotExist : raise Http404 return render(request, 'archives.html', {'post_list': post_list, 'error': False}) #分类作为标签,展示同分类下的文章 def tags(request, tag): post_list = Article.objects.filter(category__iexact=tag) return render(request,'tags.html', {'post_list': post_list}) #搜索 def search(request): if 's' in request.GET: s=request.GET['s'] if not s: return render(request,'index.html') else: post_list=Article.objects.filter(title__icontains=s) if len(post_list)==0: return render(request, 'archives.html',{'post_list':post_list,'error':True}) else: return render(request, 'archives.html',{'post_list':post_list,'error':False}) return redirect('index')
模板设计
父模板导航条完成
{% load static %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Index{% block title %} - MyBlog{% endblock %}</title> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"> <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> <link rel="stylesheet" href="http://picturebag.qiniudn.com/blog.css"> <link rel="stylesheet" href="{% static "vim.css" %}"> {% block head %}{% endblock %} <style> img{ margin-top: -20px; max-height: 60px; max-width: 150px; } .panel-body{ width: 750px; margin-left: auto; margin-right: auto; } </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"> <a class="navbar-brand" href="{% url 'index' %}"> <img src="{% static 'logo.png' %}" alt="logo"> </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="{% url 'index' %}">首页<span class="sr-only">(current)</span></a></li> <li><a href="{% url 'archives' %}">归档</a></li> </ul> <form class="navbar-form navbar-right" action="/search/" method="get"> <div class="form-group"> <input type="text" class="form-control" placeholder="Search" name="s"> </div> <button type="submit" class="btn btn-default">搜索</button> </form> <ul class="nav navbar-nav navbar-right"> {% block nav %} {% if sessionid %} <li><a href="/admin">进入后台</a></li> {% else %} <li><a href="/admin">登陆</a></li> {% endif %} {% endblock %} </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> {% block content %} {% endblock %} <footer class="footer hidden-xs"> <div class="container"> Copyright © 2013 ChaBug. All Rights Reserved. </div> </footer> </body> </html>
首页完成
{% extends 'base.html' %} {% block content %} <div class="container"> {% for post in post_list %} <div class="panel-body"> <div class="entry-header page-header"> <div class="entry-title h4"> <a href="{% url 'detail' id=post.id %}">{{ post.title }}</a> </div> <div class="entry-meta"> <p>Time:<time>{{ post.datetime|date:"Y-m-d" }}</time> 分类:<a href="{% url 'tag' tag=post.category %}">{{ post.category }}</a> </p> </div> <div class="entry-content" itemprop="description"> {% load markdown_deux_tags %} {{ post.content|truncatechars_html:50 }} <a href="{% url 'detail' id=post.id %}">Read More</a> </div> </div> </div> {% endfor %} </div> {% endblock %}
归档页面
{% extends "base.html" %} {% block content %} <div class="container"> {% if error %} <h1>没找到相关文章</h1> {% else %} <section class="posts-collapse" id="post"> <span class="archive-move-on"></span> <span class="archive-page-counter"> OK! 共找到 {{ post_list.count }} 篇日志。 继续努力。 </span> </section> {% endif %} {% for post in post_list %} <article class="post post-type-normal"> <header class="post-header"> <div class="entry-title h4"> <a href="{% url 'detail' id=post.id %}"> <span itemprop="name">{{ post.title }}</span></a> </div> <div class="post-meta"> <time class="post-time">{{ post.datetime|date:"Y-m-d" }}</time> </div> </header> </article> {% endfor %} </div> {% endblock %}
我把归档和同分类文章用了同一个模板,通过if判断来展示不同的页面。
标签页面
{% extends 'base.html' %} {% block content %} <div class="container"> 分类:<b>{{ post_list.first.category }}</b>下有{{ post_list.count }}篇日志。 继续努力。 {% for post in post_list %} <div class="panel-body"> <div class="entry-header page-header"> <div class="entry-title h4"> <a href="{% url 'detail' id=post.id %}">{{ post.title }}</a> </div> <div class="entry-meta"> <p>Time:<time>{{ post.datetime|date:"Y-m-d" }}</time> 分类:<a href="{% url 'tag' tag=post.category %}">{{ post.category }}</a> </p> </div> <div class="entry-content" itemprop="description"> {% load markdown_deux_tags %} {{ post.content|truncatechars_html:50 }} <a href="{% url 'detail' id=post.id %}">Read More</a> </div> </div> </div> {% endfor %} </div> {% endblock %}
文章页面
{% extends 'base.html' %} {% block content %} <div class="container"> <div class="panel-body"> <div class="entry-header page-header"> <h1 class="entry-title">{{ post.title }}</h1> </div> <div class="entry-meta"> <p>Time:<time>{{ post.datetime|date:"Y-m-d" }}</time> 分类:<a href="{% url 'tag' tag=post.category %}">{{ post.category|title }}</a> </p> </div> <div class="entry-content"> {% load markdown_deux_tags %} {{ post.content|markdown }} </div> </div> </div> {% endblock %}
markdown语法
安装markdown插件,
pip3 install django-markdown-deux
然后需要在settings.py中设置
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'article', 'markdown_deux' ]
在模板中像我那样调用
<div class="entry-content"> {% load markdown_deux_tags %} {{ post.content|markdown }} </div>
后记
我们的django开发个人博客总算是结束了,前端模板写的不好,你们可以自己写一波好看的。
原创文章,作者:Y4er,未经授权禁止转载!如若转载,请联系作者:Y4er