【Django】Django入门

Published April 20, 2020, 3:32 a.m. by admin

pip安装Django

安装

pip install Django==2.2

查看版本

>>> import django
>>> django.get_version()
'2.2'

第一个项目

$ django-admin startproject Zsite

目录结构

$ tree
.
├── manage.py
└── Zsite
    ├── __init__.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

数据库迁移:

$ python manage.py migrate

运行服务

$ python manage.py runserver 172.30.200.252:8001

错误报警:

Invalid HTTP_HOST header: '172.30.200.252:8001'. You may need to add '172.30.200.252' to ALLOWED_HOSTS.

设置允许的主机:

ALLOWED_HOSTS = ['172.30.200.252', 'localhost', '127.0.0.1']

页面效果图:

创建一个Zblog博客程序

我们需要在我们刚刚创建的Zsite站点上面,创建我们的第一个应用程序Zblog,如下:

$ python manage.py startapp Zblog

目录结构:

├── Zblog
│   ├── admin.py
│   ├── apps.py
│   ├── __init__.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py

定义一个Post模块,models.py文件

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


class PublishedManager(models.Manager): 
    def get_queryset(self): 
        return super(PublishedManager, self).get_queryset().filter(status='published')


class Post(models.Model): 
    STATUS_CHOICES = ( 
        ('draft', 'Draft'), 
        ('published', 'Published'), 
    ) 
#标题charField代表数据库的varchar字段
    title = models.CharField(max_length=250) 
#slug是一个URL的简短标记
    slug = models.SlugField(max_length=250,  
                            unique_for_date='publish') 
#作者,有一个外键,代表一对多。一个作者可以写多篇
    author = models.ForeignKey(User, 
                               on_delete=models.CASCADE,
                               related_name='blog_posts') 
#内容,Text字段
    body = models.TextField()
#各种日期,DateTime字段
    publish = models.DateTimeField(default=timezone.now) 
    created = models.DateTimeField(auto_now_add=True) 
    updated = models.DateTimeField(auto_now=True) 
#status,char字段,
    status = models.CharField(max_length=10,  
                              choices=STATUS_CHOICES, 
                              default='draft') 

#    objects = models.Manager() # The default manager. 
#    published = PublishedManager() # Our custom manager.

    class Meta: 
        ordering = ('-publish',) 

    def __str__(self): 
        return self.title

    def get_absolute_url(self):
        return reverse('blog:post_detail',
                       args=[self.publish.year,
                             self.publish.month,
                             self.publish.day,
                             self.slug])

在settings.py,加载我们刚刚那个模型,用于激活。

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'Zblog.apps.ZblogConfig'
]

生成Post模型SQL脚本:

(ZDjango) zsd@zsd-virtual-machine:~/ZDjango/Zsite$ python manage.py makemigrations Zblog
Migrations for 'Zblog':
  Zblog/migrations/0001_initial.py
    - Create model Post

查看迁移目录中的SQL生成脚本:

$ python manage.py sqlmigrate Zblog 0001
BEGIN;
--
-- Create model Post
--
CREATE TABLE "Zblog_post" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "title" varchar(250) NOT NULL, "slug" varchar(250) NOT NULL, "body" text NOT NULL, "publish" datetime NOT NULL, "created" datetime NOT NULL, "updated" datetime NOT NULL, "status" varchar(10) NOT NULL, "author_id" integer NOT NULL REFERENCES "auth_user" ("id") DEFERRABLE INITIALLY DEFERRED);
CREATE INDEX "Zblog_post_slug_67c50a85" ON "Zblog_post" ("slug");
CREATE INDEX "Zblog_post_author_id_61676bb3" ON "Zblog_post" ("author_id");
COMMIT;

同步上述SQL语句至数据库中

$ python manage.py migrate
Operations to perform:
  Apply all migrations: Zblog, admin, auth, contenttypes, sessions
Running migrations:
  Applying Zblog.0001_initial... OK

创建超级用户

(ZDjango) zsd@zsd-virtual-machine:~/ZDjango/Zsite$ python manage.py createsuperuser
Username (leave blank to use 'zsd'): admin
Error: Enter a valid email address.
Email address: zhangshengdongly@hotmail.com
Password: 
Password (again): 

进入Django管理站点

$ python manage.py runserver 172.30.200.252:8001

输入刚刚创建的用户名/密码,如下:

在admin.py,动态注册加载post模型。如下:

(ZDjango) zsd@zsd-virtual-machine:~/ZDjango/Zsite/Zblog$ vim admin.py 
from django.contrib import admin

# Register your models here.

from .models import Post
admin.site.register(Post)

直接刷新页面,我们的Zblog。如下效果.:

这里面,Django自带的表格页面,可以让我们提交我们的第一篇BLog。页面如下:

保存之后,我们的效果如下:

定制展示的页面

在admin.py中,添加如下代码:

@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
    list_display = ('title', 'slug', 'author', 'publish','status')
    list_filter = ('status', 'created', 'publish', 'author')
    search_fields = ('title', 'body')
    prepopulated_fields = {'slug': ('title',)}
    raw_id_fields = ('author',)
    date_hierarchy = 'publish'
    ordering = ('status', 'publish')

相当于重构了默认页面,添加了查询框,展示多列,多了不同的过滤条件。增加了默认排列。运用的是QuerySet

上面是网页端的增删改查,Django自己有抽象的API接口。可以调用。来控制Post模型的增删改查。操作如下:

1)创建对象

(ZDjango) zsd@zsd-virtual-machine:~/ZDjango/Zsite$ python manage.py shell
Python 3.6.9 (default, Nov  7 2019, 10:44:02) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from django.contrib.auth.models import User
>>> from Zblog.models import Post
>>> user = User.objects.get(username='admin')
>>> post = Post(title='测试博客文章',slug='test-post',body='我叫盛东',author=user)
>>> post.save()

如上代码的意思:获取用户,插入一篇测试博客文章。最后保存。展现效果如下:

2)获取对象

全部获取,和添加过滤条件的方式如下:

>>> post = Post(title='测试博客文章',slug='test-post',body='我叫盛东',author=user)
>>> post.save()
>>> all_posts = Post.objects.all()
>>> Post.objects.all()
<QuerySet [<Post: 测试博客文章>, <Post: LInux下部署python2.7>, <Post: Django内置模型>]>
>>> Post.objects.filter(publish__year=2020)
<QuerySet [<Post: 测试博客文章>, <Post: LInux下部署python2.7>, <Post: Django内置模型>]>
>>> Post.objects.filter(publish__year=2019)
<QuerySet []>
>>> Post.objects.filter(publish__year=2020,author__username='admin')
<QuerySet [<Post: 测试博客文章>, <Post: LInux下部署python2.7>, <Post: Django内置模型>]>
>>> Post.objects.filter(publish__year=2020,author__username='zsd')  
<QuerySet []>
>>> Post.objects.filter(publish__year=2020)\
... .filter(author__username='admin')
<QuerySet [<Post: 测试博客文章>, <Post: LInux下部署python2.7>, <Post: Django内置模型>]>

2)删除对象

删除【测试博客文章】的这篇文章。

>>> Post.objects.get(id=4)
<Post: 测试博客文章>
>>> post = Post.objects.get(id=4)
>>> post.delete()
(1, {'Zblog.Post': 1})

创建自己定制的模型管理器

通过复写,定义一个Post.published.all()来查看状态为已经发布的文章。

如下:在model.py里,定义如下代码:

class PublishedManager(models.Manager):
    def get_queryset(self): 
        return super(PublishedManager, self).get_queryset().filter(status='published')
class Post(models.Model):
#  ...
    objects = models.Manager() # The default manager. 
    published = PublishedManager() # Our custom manager.

可以看到,添加了我们定制的PublishedManager(),然后复写了方法,可以直接filter状态为published的文章。

演示效果如下(我们把【Django内置模型】改成已发布的文章):

>>> from Zblog.models import Post
>>> Post.published.filter(title__startswith='Django')
<QuerySet [<Post: Django内置模型>]>

视图展现

前面都是如何增删改查Post,现在我们在视图中进行展现。我们要把post中内容,渲染到视图中。并且制定到特定的URL中、如下:

1.生成视图和列表

创建显示post的视图,在views.py中。添加如下代码:

from django.shortcuts import render, get_object_or_404
from .models import Post
# Create your views here.

def post_list(request):
    posts = Post.published.all()
    return render(request,'Zblog/post/list.html',{'posts': posts})

def post_detail(request, year, month, day, post):
    post = get_object_or_404(Post, slug=post,
                                   status='published',
                                   publish__year=year,
                                   publish__month=month,
                                   publish__day=day)
    return render(request,
                  'Zblog/post/detail.html',
                  {'post': post})

定义了两个函数,一个是获取所有文章,一个是获取文章明细内容。一个定位到Zblog/post/list.html,一个定位到`Zblog/post/detail.html

2.为视图添加URL路径

在Zblog的应用中,添加代码到urls.py中。

from django.urls import path
from . import views 


app_name = 'Zblog'
urlpatterns = [
    # post views
    path('', views.post_list, name='post_list'),
    #path('', views.PostListView.as_view(), name='post_list'),
    path('<int:year>/<int:month>/<int:day>/<slug:post>/',
         views.post_detail,
         name='post_detail'),
] 

其中代表中一种匹配。

在Zsite的目录下,urls.py也需要添加zblog的路径如下:

from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('Zblog/', include('Zblog.urls', namespace='blog')),
]

模型models.py需要根据传递参数,构建特定的文章内容。代码如下:

from django.urls import reverse

    def get_absolute_url(self):
        return reverse('Zblog:post_detail',
                       args=[self.publish.year,
                             self.publish.month,
                             self.publish.day,
                             self.slug])

3.创建视图的HTML模板

写好了view,需要渲染具体的内容到html中。 html的模板目录结构如下:

└── Zblog
    ├── base.html
    └── post
        ├── detail.html
        └── list.html

base.html划分了主内容区域和侧栏。内容如下:

{% load static %}
<!DOCTYPE html>
<html>
<head>
  <title>{% block title %}{% endblock %}</title>
  <link href="{% static "css/blog.css" %}" rel="stylesheet">
</head>
<body>
  <div id="content">
    {% block content %}
    {% endblock %}
  </div>
  <div id="sidebar">
    <h2>东晔博客</h2>
      <p>宠辱不惊,闲看庭前花开花落</p>
  </div>
</body>
</html>

post/list.hmtl展现所有的博客文章,内容如下:

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

{% block title %}My Blog{% endblock %}

{% block content %}
  <h1>东晔博客</h1>
  {% for post in posts %}
    <h2>
      <a href="{{ post.get_absolute_url }}">
        {{ post.title }}
      </a>
    </h2>
    <p class="date">
      Published {{ post.publish }} by {{ post.author }}
    </p>
    {{ post.body|truncatewords:30|linebreaks }}
  {% endfor %}
{% endblock %}

里面一个for循环,把所有的文章都发布出来。效果如下:

增加一个看博客文章明细html页面。

post/detail.html文件,查看如下:

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

{% block title %}{{ post.title }}{% endblock %} 

{% block content %} 
  <h1>{{ post.title }}</h1> 
  <p class="date"> 
    Published {{ post.publish }} by {{ post.author }} 
  </p> 
  {{ post.body|linebreaks }} 
{% endblock %}

效果如下:

4.页面的分页机制

导入Django的分页器并且修正post_list视图。views.py修改如下:

from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

def post_list(request):
    object_list = Post.published.all()
    paginator = Paginator(object_list, 3) # 每一页有三篇文章
    page = request.GET.get('page')
    try:
        posts = paginator.page(page)
    except PageNotAnInteger:
        # If page is not an integer deliver the first page
        posts = paginator.page(1)
    except EmptyPage:
        # If page is out of range deliver last page of results
        posts = paginator.page(paginator.num_pages)
    return render(request,
                  'Zblog/post/list.html',
                  {'page': page,
                   'posts': posts})

创建一个html分页模板templates/pagination.html

<div class="pagination">
  <span class="step-links">
    {% if page.has_previous %}
      <a href="?page={{ page.previous_page_number }}">前一页</a>
    {% endif %}
    <span class="current">
      Page {{ page.number }} of {{ page.paginator.num_pages }}.
    </span>
      {% if page.has_next %}
      <a href="?page={{ page.next_page_number }}">后一页</a>
      {% endif %}
  </span>
</div>

在list.html加入分页的扩展:

{% block content %}
...
    {% include "pagination.html" with page=posts %}
{% endblock %}

效果如下:

分页另一个方法:基于View

在Zblog应用中添加PostListView。效果和上述效果一样。在views.py中,添加如下代码:

from django.views.generic import ListView

class PostListView(ListView):
    queryset = Post.published.all()
    context_object_name = 'posts'
    paginate_by = 3
    template_name = 'Zblog/post/list.html'

在urls.py文件中,修改url路径:

    path('', views.PostListView.as_view(), name='post_list'),

最后html模板post/list.html,添加:

  {% include "pagination.html" with page=page_obj %}

同类文章

【Django】Django 数据导入和导出

【Django】创建Zstockweb

【Django】Site matching query does not exist

【Django】haystack+whoosh+jieba实现中文全文搜索

0 次评论

没有任何评论

添加一条评论