标签归档:Django

Django博客系统开发06

用户登录

博客作为内容管理系统(CMS)的一种形式,也应当具有CMS的两个功能:内容管理、权限管理。在之前的几篇中,我们已经实现了内容管理。现在实现用户管理,即用户的登录和登出以及页面权限管理。

首先我们现在一共有以下views: index(), post_view(), post_create(), post_edit(), post_drafts(), post_publish(), post_delete()。在这些views中,出了index()和post_views()这两个属于内容展现的方法以外,其他方法应该都受到登录保护。所以,我们引入django自带的@login_required注解来处理这些方法。

首先在hzblog/views.py中引入login_required,并在需要登录验证的方法前加上注解。

from django.contrib.auth.decorators import login_required

@login_required
def post_create(request):
    ...

@login_required
def post_edit(request, pk):
    ...

@login_required
def post_drafts(request):
    ...

@login_required
def post_publish(request, pk):
    ...

@login_required
def post_delete(request, pk):
    ...

然后,在hzsite/urls.py中引入登录登出的路由。注意,由于整个系统使用统一的登录登出路由,所以这里不是在app的urls.py中引入路由。

from django.contrib.auth import views

urlpatterns = [
    ...
    url(r'^accounts/login/$', views.login, name='login'),
    url(r'^accounts/logout/$', views.logout, name='logout'),
    ...
]

这里,我们还要修改一下hzsite/settings.py配置文件,将login/logout操作后的跳转页面定义到’/’目录,即首页。在settings.py中,加入两行:

LOGIN_REDIRECT_URL = '/'
LOGOUT_REDIRECT_URL = '/'

引入路由之后,我们创建一个登录页面进行登录。创建hzblog/templates/registration/目录,在目录下创建login.html模板

{% extends "blog/base.html" %}

{% block content %}

{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}

<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<table>
<tr>
    <td>{{ form.username.label_tag }}</td>
    <td>{{ form.username }}</td>
</tr>
<tr>
    <td>{{ form.password.label_tag }}</td>
    <td>{{ form.password }}</td>
</tr>
</table>

<input type="submit" value="login" />
<input type="hidden" name="next" value="{{ next }}" />
</form>

{% endblock %}

最后,我们修改base.html模板,在头部加上登录登出的按钮

...
    <div class="page-header">
        {% if user.is_authenticated %}
            <a href="{% url 'logout' %}" class="top-menu"><span class="glyphicon glyphicon-log-out"></span></a>
            <a href="{% url 'hzblog:post_create' %}" class="top-menu"><span class="glyphicon glyphicon-plus"></span></a>
            <a href="{% url 'hzblog:post_drafts' %}" class="top-menu"><span class="glyphicon glyphicon-list-alt"></span></a>
            <p class="top-menu">Hello {{ user.username }}</p>
        {% else %}
            <a href="{% url 'login' %}" class="top-menu"><span class="glyphicon glyphicon-log-in"></span></a>
        {% endif %}
        <h1><a href="/">ZIVER'S</a></h1>
    </div>
...

下面运行博客测试一下功能

 python manage.py runserver 0.0.0.0:8080

未登录状态点开首页时,右上角显示登录按钮

1

点击登录或者使用需要登录的功能(修改、删除等),跳转到登录页面

2

输入用户信息登录后,右上角出现欢迎信息和只有登录后才可见的按钮

3

登录功能完美实现。

Django博客系统开发05

文章的增删改发布

通过之前的步骤,我们已经有了一个初步的网站页面(首页+Django Admin),其实我们已经可以通过admin页面来对文章进行操作了,但是为了更像是一个真正的博客,我们应该能够从前端进行对文章的增删改查。

查看文章(post_view)

我们现在只有一个页面–首页。在首页中,我们获取到的是全部已经发布的文章列表。现在,我们创建一个文章详情页,当用户点击首页的文章标题时,将跳转到这个页面。

首先,我们为这个页面添加路由,在hzblog/urls.py中加入一行

url(r'^post/(?P<pk>[0-9]+)/$', views.post_view, name='post_view'),

然后,我们修改模板文件,增加跳转链接。在index.html中修改标题的href属性:

<h1><a href="{% url 'hzblog:post_view' pk=post.pk %}">{{ post.title }}</a></h1>

这里使用了url方法来获得post_view的真实url。hzblog:post_view(即AppName:RouterName)这种写法时因为我们之前在hzblog/urls.py中进行了如下定义:

...
app_name = 'hzblog'

urlpatterns = [
    ...
    url(r'^post/(?P<pk>[0-9]+)/$', views.post_view, name='post_view'),
    ...
]

如果是在hzsite/urls.py中定义的url,则不需要添加app前缀,直接使用’post_views’。

下面,创建列表页对应的view。修改views.py,加入post_view方法:

from django.shortcuts import render, get_object_or_404

def post_view(request, pk):
    post = get_object_or_404(Post, pk=pk)
    return render(request, 'blog/post_view.html', {'post': post})

通过view,请求将会被render到post_view.html这个模板。现在我们创建这个模板(hzblog/templates/blog/post_view.html):

{% extends 'blog/base.html' %}

{% block content %}
    <div class="date">
        {% if post.published_date %}
            {{ post.published_date }}
        {% endif %}
    </div>
    <h1>{{ post.title }}</h1>
    <p>{{ post.text|linebreaks }}</p>
{% endblock %}

这时候,我们访问

http://localhost:8080/post/2/

20161127145736

我们就能够看到文章详情页了。

Django小结

这里可以对创建一个页面/功能的流程进行一个小结。

  1. 在urls.py中添加新页面/功能的路由
  2. 在views.py中添加对应的方法来处理路由发送过来的请求,将数据渲染到对应模板
  3. 在templates文件夹下创建新页面/功能的模板,将views发送过来的数据进行展现

创建文章(post_create)

所谓的创建文章,我们可以理解成向服务器提交一个表单,表单中包含了文章的信息和内容。所以,我们先引入Django的Form来完成我们的功能。首先创建hzblog/forms.py

from django import forms
from .models import Post

class PostForm(forms.ModelForm):

    class Meta:
        model = Post
        fields = ('title', 'text',)

所以接下来,我们按照上面做的小结,开始增加创建文章功能的流程。首先,添加路由

url(r'^post/create/$', views.post_create, name='post_create'),

然后增加views

from django.shortcuts import redirect

def post_create(request):
    if request.method == "POST":
        form = PostForm(request.POST)
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            post.save()
            return redirect('hzblog:post_view', pk=post.pk)
    else:
        form = PostForm()
    return render(request, 'blog/post_edit.html', {'form': form})

这里使用了一个redirect方法,即创建完文章之后跳转到post_view页面。而在返回中,我们将请求发送到了post_edit模板。这个模板现在还没有创建,因为我们的新增文章和编辑文章都将使用这个模板,所以会在接下来的编辑文章功能部分创建。

最后我们修改模板base.html,在page-header这个div中,增加创建文章按钮:

...
    <div class="page-header">
        <a href="{% url 'hzblog:post_create' %}" class="top-menu"><span class="glyphicon glyphicon-plus"></span></a>
        <h1><a href="/">ZIVER'S</a></h1>
    </div>
...

编辑文章(post_edit)

在创建文章功能中,我们遗留了post_edit这个模板没有添加。在编辑文章功能中,我们将实现这个模板。还是之前的流程,我们先创建路由

url(r'^post/(?P<pk>[0-9]+)/edit/$', views.post_edit, name='post_edit'),

然后增加view方法

def post_edit(request, pk):
    post = get_object_or_404(Post, pk=pk)
    if request.method == "POST":
        form = PostForm(request.POST, instance=post)
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            post.save()
            return redirect('hzblog:post_view', pk=post.pk)
    else:
        form = PostForm(instance=post)
    return render(request, 'blog/post_edit.html', {'form': form})

最后增加post_edit.html模板

{% extends 'blog/base.html' %}

{% block content %}
    <h1>New post</h1>
    <form method="POST" class="post-form">{% csrf_token %}
        {{ form.as_p }}
        <button type="submit" class="save btn btn-default">Save</button>
    </form>
{% endblock %}

最后,在post_view.html中增加编辑文章的按钮

<a class="btn btn-default" href="{% url 'hzblog:post_edit' pk=post.pk %}"><span class="glyphicon glyphicon-pencil"></span></a>

修改完成后,post_views.html内容如下:

{% extends 'blog/base.html' %}

{% block content %}
    <div class="date">
        {% if post.published_date %}
            {{ post.published_date }}
        {% endif %}
        <a class="btn btn-default" href="{% url 'hzblog:post_edit' pk=post.pk %}"><span class="glyphicon glyphicon-pencil"></span></a>
    </div>
    <h1>{{ post.title }}</h1>
    <p>{{ post.text|linebreaks }}</p>
{% endblock %}

测试

在完成以上功能后,我们可以稍微测试一下效果。因为增加和修改文章都是需要以用户身份执行的,而我们的前端登陆功能还没有实现,所以我们首先用django自带的amin登陆到我们的博客:

http://localhost:8080/admin

然后访问首页

20161127152833

由于没有新文章的发布,首页依然只有一篇文章。右上角有了创建文章的按钮,点击按钮创建文章

20161127152939

这里就有一个可以填写的表单,填写后点击save

20161127153004

保存后,跳转到了文章的详情页。此时的文章还没有发布,所以不会在首页显示,发布后文章右上角将显示发布时间。现在右上角有编辑按钮,点击按钮将回到文章编辑页(和新建文章是同一个模板)。接下来,我们将实现发布功能。

草稿列表(post_drafts)

未发布的文章称为草稿,为了实现发布功能,我们先实现草稿列表页,将未发布的文章列出来。

首先添加路由

url(r'^drafts/$', views.post_drafts, name='post_drafts'),

然后增加view方法

def post_drafts(request):
    posts = Post.objects.filter(published_date__isnull=True).order_by('-created_date')
    return render(request, 'blog/post_drafts.html', {'posts': posts})

之后增加post_drafts.html模板

{% extends 'blog/base.html' %}
{% block content %}
    {% for post in posts %}
        <div class="post">
            <p class="date">created: {{ post.created_date|date:'d-m-Y' }}</p>
            <h1><a href="{% url 'hzblog:post_view' pk=post.pk %}">{{ post.title }}</a></h1>
            <p>{{ post.text|truncatechars:200 }}</p>
        </div>
    {% endfor %}
{% endblock %}

最后在base.html中增加草稿列表页入口按钮

...
    <div class="page-header">
        <a href="{% url 'hzblog:post_create' %}" class="top-menu"><span class="glyphicon glyphicon-plus"></span></a>
        <a href="{% url 'hzblog:post_drafts' %}" class="top-menu"><span class="glyphicon glyphicon-list-alt"></span></a>
        <h1><a href="/">ZIVER'S</a></h1>
    </div>
...

发布文章(post_publish)

增加路由

url(r'^post/(?P<pk>[0-9]+)/publish/$',views.post_publish, name='post_publish'),

增加view方法

def post_publish(request, pk):
    post = get_object_or_404(Post, pk=pk)
    post.publish()
    return redirect('hzblog:post_view', pk=pk)

在post_view页面中增加发布按钮

将下面内容

{% if post.published_date %}
    {{ post.published_date }}
{% endif %}

修改为

{% if post.published_date %}
    {{ post.published_date }}
{% else %}
    <a class="btn btn-default" href="{% url 'blog.views.post_publish' pk=post.pk %}">Publish</a>
{% endif %}

删除文章(post_delete)

增加路由

url(r'^post/(?P<pk>[0-9]+)/delete/$', views.post_delete, name='post_delete'),

增加view方法

def post_delete(request, pk):
    post = get_object_or_404(Post, pk=pk)
    post.delete()
    return redirect('hzblog:index')

在post_view页面中增加发布按钮

 ...  
    <div class="date">
    ...
    {% endif %}
        ...
        <a class="btn btn-default" href="{% url 'hzblog:post_delete' pk=post.pk %}"><span class="glyphicon glyphicon-remove"></span></a>
    </div>
...

至此,博客的基本功能:查看文章,创建文章,编辑文章,删除文章,发布文章功能完成。

Django博客系统开发04

前端改造

在之前的几篇完成后,我们得到了一个简陋的首页,下面我们使用Bootstrap来美化一下我们的前端。

下载Bootstrap

需要下载的是Bootstrap的css和js,以及jquery。这里就不仔细说明了,下载后放到新建的static/目录下即可。现在,整个项目的结构如下:

hzsite
├── hzblog
│   ├── admin.py
│   ├── apps.py
│   ├── __init__.py
│   ├── models.py
│   ├── templates
│   │   └── blog
│   │       └── index.html
│   ├── tests.py
│   ├── urls.py
│   └── views.py
├── hzsite
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── manage.py
└── static
    ├── css
    │   ├── bootstrap.min.css
    │   ├── bootstrap.min.css.map
    │   ├── bootstrap-theme.min.css
    │   ├── bootstrap-theme.min.css.map
    │   └── style.css
    └── js
        ├── bootstrap.min.js
        └── jquery-3.1.1.min.js

注意到这里还有一个style.css,我将在这个文件中定义主体css。

style.css内容如下:

.page-header {
    background-color: #417690;
    margin-top: 0;
    padding: 5px 20px 10px 40px;
}
.page-header h1, .page-header h1 a, .page-header h1 a:visited, .page-header h1 a:active {
    color: #ffffff;
    font-size: 28pt;
    text-decoration: none;
}
.content {
    margin-left: 40px;
}
h1, h2, h3, h4 {
    font-family: 'Microsoft YaHei', cursive;
}
.date {
    float: right;
    color: #828282;
}
.save {
    float: right;
}
.post-form textarea, .post-form input {
    width: 100%;
}
.top-menu, .top-menu:hover, .top-menu:visited {
    color: #ffffff;
    float: right;
    font-size: 26pt;
    margin-right: 20px;
}
.post {
    margin-bottom: 70px;
}
.post h1 a, .post h1 a:visited {
    color: #000000;
}

配置静态目录

下面我们把刚才创建的static目录添加到配置中,修改hzsite/settings.py增加以下内容:

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, "static"),
)

写入到配置后,我们就可以在模板中直接调用static目录下的css和js了。

修改template

修改index.html

{% load staticfiles %}
<html>
<head>
    <title>ZIVER'S</title>
    <script src="{% static 'js/jquery-3.1.1.min.js' %}"></script>
    <link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
    <link rel="stylesheet" href="{% static 'css/bootstrap-theme.min.css' %}">
    <script src="{% static 'js/bootstrap.min.js' %}"></script>
    <link rel="stylesheet" href="{% static 'css/style.css' %}">
</head>
<body>
    <div class="page-header">
        <h1><a href="/">ZIVER'S</a></h1>
    </div>
    <div class="content">
        <div class="row">
            <div class="col-md-8">
                {% for post in posts %}
                    <div class="post">
                        <h1><a href="">{{ post.title }}</a></h1>
                        <p>published: {{ post.published_date }}</p>
                        <p>{{ post.text|linebreaks }}</p>
                    </div>
                {% endfor %}
            </div>
        </div>
    </div>
</body>
</html>

现在,我们的博客首页看起来就舒服多了。

7

模板继承

Django的模板系统支持模板继承,所以我们可以使用继承的方法来减少前端代码的冗余。在index.html的基础上把页面上一般不改变的地方拆分出来创建base.html。内容如下:

<html>
<head>
    <title>ZIVER'S</title>
    <script src="{% static 'js/jquery-3.1.1.min.js' %}"></script>
    <link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
    <link rel="stylesheet" href="{% static 'css/bootstrap-theme.min.css' %}">
    <script src="{% static 'js/bootstrap.min.js' %}"></script>
    <link rel="stylesheet" href="{% static 'css/style.css' %}">
</head>
<body>
    <div class="page-header">
        <h1><a href="/">ZIVER'S</a></h1>
    </div>
    <div class="content">
        <div class="row">
            <div class="col-md-8">
            {% block content %}
            {% endblock %}
            </div>
        </div>
    </div>
</body>
</html>

然后删除掉index.html中的重复内容,并在开头加上模板引用。修改完后的index.html如下:

{% extends 'blog/base.html' %}
{% block content %}
{% for post in posts %}
    <div class="post">
        <h1><a href="">{{ post.title }}</a></h1>
        <p>published: {{ post.published_date }}</p>
        <p>{{ post.text|linebreaks }}</p>
    </div>
{% endfor %}
{% endblock content %}

修改完成后,刷新页面,应该不会有任何变化。

 

Django博客系统开发03

路由Django URL

Django框架通过urls.py文件中的规则对系统进行路由控制。首先我们在主路由hzsite/urls.py中引入hzblog的路由设置:

from django.conf.urls import url
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'', include('hzblog.urls')),
]

然后,在hzsite/urls.py中设置具体的路由规则

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.index, name='index'),
]

这里我们添加了一条规则,当用户访问网站根目录时,有views中的index方法处理。下面我们去views.py中添加index方法对请求进行处理。

from django.shortcuts import render
from .models import Post

def index(request):
    posts = Post.objects.filter(published_date__isnull=False).order_by('-published_date')
    return render(request, 'blog/index.html', {'posts': posts})

对于路由发来的请求,index函数先调用models查找出符合要求的文章list,然后调用render方法将获取到的数据render到index.html这个模板页面。

最后,我们只需要创建这个index.html模板文件即可。

mkdir -p hzblog/templates/blog
vim hzblog/templates/blog/index.html

模板如下

<html>
<head>
    <title>ZIVER'S</title>
</head>
<body>
    <div>
        <h1><a href="/">ZIVER'S</a></h1>
    </div>
    {% for post in posts %}
    <div>
        <p>published: {{ post.published_date }}</p>
            <h1><a href="">{{ post.title }}</a></h1>
            <p>{{ post.text|linebreaks }}</p>
    </div>
    {% endfor %}
</body>
</html>

这时候,开启服务器,访问我们的主页就能看到如下页面了

6

由于没有加入样式,所以现在的页面比较简陋。这里只显示了Sample 02这篇文章,是因为我们之前在shell中只publish了这一篇,而在index方法中使用过滤器只筛选出了published文章。

Django博客系统开发02

模型Model

Model即MVC模式中的模型,主要是通过ORM与数据库对接,执行对数据库的一些操作。博客系统的所有的模型都将在hzblog/models.py中定义。下面定义我们的第一个Model——Post:

from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User

class Post(models.Model):
    author = models.ForeignKey(User)
    title = models.CharField(max_length=200)
    text = models.TextField()
    created_date = models.DateTimeField(default=timezone.now)
    published_date = models.DateTimeField(blank=True, null=True)

    def publish(self):
        self.published_date = timezone.now()
        self.save()

    def __str__(self):
        return self.title

定义完成后,我们使用migrate命令在数据库中生成相应的表结构

python manage.py makemigrations hzblog
python manage.py migrate hzblog

第一步中,django将为我们创建model修改后需要更改的sql。第二步中将这些更改写入到数据库中。

下面我们在django shell中创建一篇文章

python manage.py shell
>>> from hzblog.models import Post
>>> Post.objects.all()
<QuerySet []>
>>> from django.contrib.auth.models import User
>>> User.objects.create(username='Henry')
<User: Henry>
>>> henry = User.objects.get(username='Henry')
>>> Post.objects.create(author = henry, title = 'Sample 01', text = 'Test')
<Post: Sample 01>
>>> Post.objects.all()
[<Post: Sample 01>]

同样的方法,创建其他Sample文章,现在我们就有了三篇文章

>>> Post.objects.filter(author=user)
[<Post: Sample 01>, <Post: Sample 02>, <Post: Sample 03>]

下面,我们筛选出其中的Sample 02这篇文章并发布

>>> post = Post.objects.get(id=2)
>>> post.publish()
>>> Post.objects.filter(published_date__isnull=False)
[<Post: Sample 02>]

这时候,我们就通过django shell用CLI的方式创建了三篇文章并发布了其中一篇。

后台管理Django Admin

Django框架提供了一个简单的后台管理界面Django Admin。我们先创建一个管理员账号admin:

python manage.py createsuperuser

创建完成后,我们就可以用这个账号登陆Django后台。

http://localhost:8080/admin

2

接下来,我们把我们创建的Post这个Model注册到Django Admin中:

修改hzblog/admin.py

from django.contrib import admin
from .models import Post

admin.site.register(Post)

下面,我们登陆到Django后台,现在已经可以看到我们刚才通过shell创建的几篇文章了。

3

Django后台界面

4

文章列表页

5

文章详情页

Django博客系统开发01

环境搭建

开发环境

这里使用的是Ubuntu 16.04 LTS Server版本的系统,所以系统自带了Python3.5版本。但是系统默认使用的是Python2.7, 需要使用Python3时使用Python3命令。为了让开发环境相互隔离,我使用virtualenv创建独立的虚拟环境。

首先安装pip3

apt update
apt upgrade
apt install python3-pip

这里还需要安装一些依赖库以用于之后数据库的连接

apt install python-dev
apt install libmysqlclient-dev

(CentOS对应为python34-devel、mysql-devel)

然后安装虚拟环境virtualenv

pip install virtualenv

现在,我们到/var/www/目录下创建一个虚拟环境,并将虚拟环境所在目录命名为venv

cd /var/www/
virtualenv venv -p /usr/bin/python3 --no-site-packages

然后,激活这个虚拟环境

root@ubuntu:var/www# . venv/bin/activate
(venv) root@ubuntu:/var/www#

然后,安装django和mysqlclient用于连接mysql数据库(当然也可以使用pymysql这样的工具)

pip install django
pip install mysqlclient

现在,我们就有了开发所需要的软件环境,接下来开始构建项目。

创建项目

在/var/www/目录下执行一下命令创建我们的工程(hzsite)

django-admin startproject hzsite

创建后,工程的结构如下:

hzsite
    ├───manage.py
    └───hzsite
         settings.py
         urls.py
         wsgi.py
         __init__.py

数据库

博客的数据使用MySQL数据库存储,所以我们需要先新建一个数据库

mysql -u root -p
> create database hzsite;

配置项目

修改hzsite/settings.py文件中的以下配置

修改ALLOW_HOSTS

ALLOWED_HOSTS = ['*']

修改TIME_ZONE

TIME_ZONE = 'Asia/Shanghai'

修改数据库连接配置

# Database
# https://docs.djangoproject.com/en/1.10/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'hzsite',
        'USER': 'root',
        'PASSWORD': 'password',
        'HOST': '127.0.0.1',
        'PORT': '3306',
    }
}

完成后,执行migrate命令生成数据库结构

python manage.py migrate

显示如下则成功

Operations to perform:
 Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
 Applying contenttypes.0001_initial... OK
 Applying auth.0001_initial... OK
 Applying admin.0001_initial... OK
 Applying admin.0002_logentry_remove_auto_add... OK
 Applying contenttypes.0002_remove_content_type_name... OK
 Applying auth.0002_alter_permission_name_max_length... OK
 Applying auth.0003_alter_user_email_max_length... OK
 Applying auth.0004_alter_user_username_opts... OK
 Applying auth.0005_alter_user_last_login_null... OK
 Applying auth.0006_require_contenttypes_0002... OK
 Applying auth.0007_alter_validators_add_error_messages... OK
 Applying auth.0008_alter_user_username_max_length... OK
 Applying sessions.0001_initial... OK

完成后,使用以下命令在本机8080端口启动服务器

python manage.py runserver 0.0.0.0:8080

使用浏览器访问,出现It Works提示页面则配置成功

1

创建新应用

一个Django Project中可以包含多个Application。这里我们创建一个hzblog应用作为博客系统的主要App。

python manage.py startapp hzblog

创建完成后在hzsite/settings.py中注册这个app

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'hzblog',
]

至此,基本的环境和博客系统的目录结构就有了。

Django博客系统开发

一直想用Python实现一个博客系统来替换掉现在臃肿的WordPress。之前尝试过使用Flask框架来实现,但是由于功力不足,Flask这种小型框架做起来还是困难比较大的,所以决定还是从Django入手吧。在这之后应该会有一系列的文章来完成一个这个博客系统的实现,虽然离WordPress应该差距不小,但是至少应该能够实现一个博客系统需要的基本功能。

目录

源码

https://github.com/cnzh/hzsite

目标

实现一个基于Django框架的简单博客,第一阶段应该至少实现以下功能:

  1. 增加、修改、删除文章
  2. 用户登录、登出
  3. 草稿系统,草稿发布逻辑
  4. 基本的前端界面

之后会对这些功能迭代,Todo:

  1. 页面导航
  2. 文章搜索
  3. Redis缓存
  4. MarkDown集成
  5. 富文本编辑

环境

  1. Ubuntu 16.04 LTS
  2. Django 1.10
  3. MySQL 5.7
  4. Python 3.5

参考

代码结构很大程度上参考了Django Girlstutorial以及tutorial-extensions系列教程,这里进行说明。

Django Model一对多、多对多关系

在Django的Model中,可以定义多种关系:一对一,多对一/一对多,多对多。

分别为:

  • 一对一:OneToOneField
  • 多对一:ForeignKey
  • 多对多:ManyToManyField

可以更加natural的表述为:

  • 多个属于一个,即 belong to : ForeignKey,多个属于一个
  • 一个有一个,即 only has one: OneToOneField
  • 一个有很多个,即 has many: lots of A belong to B 与 B has many A,在建立 ForeignKey 时,另一个表会自动建立对应的关系
  • 一个既有很多个,又属于很多个,即 has many and belong to : ManyToManyField,同样只能在一个model类中说明,关联表会自动建立。

在官方的tutorial中,有这样一个例子:

import datetime

from django.db import models
from django.utils import timezone

class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

    def __str__(self):
        return self.question_text

    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)


class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

    def __str__(self):
        return self.choice_text

在Model定义中表现了如下一对多关系:

               |---- Choice 1
               |
Question 1 ----|---- Choice 2
               |
               |---- Choice 3

我们可以看到,在“多”的一方(Choice)中定义了“一”的一方(Question)的外键。

当从“多”的一方展开查询时,只需要指明属性名即可

>>> c = Choice.objects.get(id=1)
>>> c.question

当从“一”的一方展开查询时,则需创建一个foo_set集合:

>>> q = Question.objects.get(id=1)
>>> q.choice_set.all()

对于多对多关系,其实和一对多非常的像,定义ManyToManyField的Model访问和它关联的Model时,直接访问该Model的名字就可以了,反过来,就需要加上“_set”了。

参考:http://logic0.blog.163.com/blog/static/18892814620137343447299/

http://blog.csdn.net/hackerain/article/details/39838559