美文网首页
Django快速入门4博客实例&静态文件

Django快速入门4博客实例&静态文件

作者: python测试开发 | 来源:发表于2021-07-18 10:41 被阅读0次

    本章我们将建立允许用户创建、编辑和删除文章的博客应用程序。主页将列出所有的博客文章,每个博客文章将有详细页面。我们还将介绍CSS的样式,并学习Django如何与静态文件一起工作。

    建立博客应用

    $ mkdir blog
    $ cd blog
    $ django-admin startproject config .
    $ python manage.py startapp blog
    $ python manage.py migrate
    $ python manage.py runserver
    $ vi config/settings.py
    # config/settings.py
    INSTALLED_APPS =
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'blog', # new
    ]
    

    数据库模型

    我们保持简单,假设每篇文章有一个标题、作者和正文。我们可以通过打开blog/models.py文件并输入下面的代码将其转化为一个数据库模型。

    # blog/models.py
    from django.db import models
    
    
    class Post(models.Model):
        title = models.CharField(max_length=200)
        author = models.ForeignKey(
            'auth.User',
            on_delete=models.CASCADE,
        )
        body = models.TextField()
    
        def __str__(self):
            return self.title
    

    数据迁移

    $ python manage.py makemigrations blog
    $ python manage.py migrate blog
    $ python manage.py createsuperuser
    

    更新blog/admin.py,所以现在让我们来做这个。

    代码blog/admin.py

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

    添加两个博客帖子,这样我们就有样本数据可以使用。点击Post旁边的+Add按钮,创建一个新条目。确保为每个帖子也添加一个 "作者",因为在默认情况下,所有的模型字段都是必需的。

    URL

    blog/urls.py

    # blog/urls.py
    from django.urls import path
    from .views import BlogListView
    
    urlpatterns = [
        path('', BlogListView.as_view(), name='home'),
    ]
    

    更新我们的 config/urls.py 文件

    # config/urls.py
    from django.contrib import admin
    from django.urls import path, include # new
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('', include('blog.urls')), # new
    ]
    

    我们在第二行添加了 include 和使用空字符串正则表达式 '' 的 URLpattern,指示 URL 请求应按原样重定向到博客的 URL 以获取进一步说明。

    视图

    我们将使用基于类的视图,但如果您想看到基于函数的方式来构建博客应用程序,强烈推荐Django Girls Tutorial

    blog/views.py

    from django.views.generic import ListView
    from .models import Post
    
    
    class BlogListView(ListView):
        model = Post
        template_name = 'home.html'
    

    模板

    $ mkdir templates
    $ touch templates/base.html
    $ touch templates/home.html
    $ vi templates/base.html
    <!-- templates/base.html -->
    <html>
      <head>
        <title>Django blog</title>
      </head>
      <body>
        <header>
          <h1><a href="{% url 'home' %}">Django blog</a></h1>
        </header>
        <div>
          {% block content %}
          {% endblock content %}
        </div>
      </body>
    </html>
    $vi templates/home.html
    <!-- templates/home.html -->
    {% extends 'base.html' %}
    
    {% block content %}
      {% for post in object_list %}
        <div class="post-entry">
          <h2><a href="">{{ post.title }}</a></h2>
          <p>{{ post.body }}</p>
        </div>
      {% endfor %}
    {% endblock content %}
    

    静态文件

    CSS、JavaScript 和图像是任何现代 Web 应用程序的核心部分,在 Django 世界中被称为“静态文件”。 Django 在如何使用这些文件方面提供了极大的灵活性,但这可能会给新手带来很多困惑。

    默认情况下,Django 将在每个应用程序中查找名为 static 的文件夹。

    不过我们准备将静态文件存储在单个项目级目录中。


    $ mkdir static
    $ vi config/settings.py
    STATIC_URL = '/static/'
    STATICFILES_DIRS = [str(BASE_DIR.joinpath('static'))] 
    $ mkdir static/css
    $ vi static/css/base.css
    /* static/css/base.css */
    header h1 a {
      color: red;
    }
    $ vi templates/base.html 
    <!-- templates/base.html -->
    {% load static %}
    <html>
      <head>
        <title>Django blog</title>
        <link rel="stylesheet" href="{% static 'css/base.css' %}">
      </head>
      ...
    
    

    再次使用 python manage.py runserver 启动服务器并查看我们更新的主页 http://127.0.0.1:8000/。

    不过我们可以做得更好一点。如果我们添加自定义字体和更多 CSS 怎么样?由于本书不是 CSS 教程,因此只需在 <head></head> 标签之间插入以下内容即可添加 Source Sans Pro,这是一种来自 Google 的免费字体。

    $ vi templates/base.html 
    <!-- templates/base.html -->
    {% load static %}
    <html>
      <head>
        <title>Django blog</title>
       <link href="https://fonts.font.im/css?family=Source+Sans+Pro:400" rel="stylesheet">   
        <link rel="stylesheet" href="{% static 'css/base.css' %}">
      </head>
    
    $ vi static/css/base.css 
    /* static/css/base.css */
    body {
      font-family: 'Source Sans Pro', sans-serif;
      font-size: 18px;
    }
    
    header {
      border-bottom: 1px solid #999;
      margin-bottom: 2rem;
      display: flex;
    }
    
    header h1 a {
      color: red;
      text-decoration: none;
    }
    
    .nav-left {
      margin-right: auto;
    }
    
    .nav-right {
      display: flex;
      padding-top: 2rem;
    }
    
    .post-entry {
      margin-bottom: 2rem;
    }
    
    .post-entry h2 {
      margin: 0.5rem 0;
    }
    
    .post-entry h2 a,
    .post-entry h2 a:visited {
      color: blue;
      text-decoration: none;
    }
    
    .post-entry p {
      margin: 0;
      font-weight: 400;
    }
    
    .post-entry h2 a:hover {
      color: red;
    }
    
    

    在 http://127.0.0.1:8000/ 刷新主页,您应该看到以下内容。

    博客页面

    我们可以使用通用的基于类的 DetailView 来简化事情。在文件的顶部,将 DetailView 添加到导入列表中,然后创建名为 BlogDetailView 的新视图。

    blog/views.py

    # blog/views.py
    from django.views.generic import ListView, DetailView # new
    from .models import Post
    
    
    class BlogListView(ListView):
        model = Post
        template_name = 'home.html'
    
    
    class BlogDetailView(DetailView): # new
        model = Post
        template_name = 'post_detail.html'
    

    模板

    $ vi templates/home.html 
    <!-- templates/home.html -->
    {% extends 'base.html' %}
    
    {% block content %}
      {% for post in object_list %}
      <div class="post-entry">
        <h2><a href="{% url 'post_detail' post.pk %}">{{ post.title }}</a></h2>
        <p>{{ post.body }}</p>
      </div>
      {% endfor %}
    {% endblock content %}
    
    $ vi templates/post_detail.html
    <!-- templates/post_detail.html -->
    {% extends 'base.html' %}
    
    {% block content %}
      <div class="post-entry">
        <h2>{{ post.title }}</h2>
        <p>{{ post.body }}</p>
      </div>
    
    {% endblock content %}
    # 甚至下面这样也可以的
    <!-- templates/post_detail.html -->
    {% extends 'base.html' %}
    
    {% block content %}
      <div class="post-entry">
        <h2>{{ object.title }}</h2>
        <p>{{ object.body }}</p>
      </div>
    
    {% endblock content %}
    
    

    如果您发现使用 post 或 object 令人困惑,可以使用 context_object_name显式命名上下文对象。

    添加新的 URLConf :

    # blog/urls.py
    from django.urls import path
    from .views import BlogListView, BlogDetailView # new
    
    urlpatterns = [
        path('post/<int:pk>/', BlogDetailView.as_view(),
          name='post_detail'), # new
        path('', BlogListView.as_view(), name='home'),
    ]
    

    所有博客文章条目都将以 post/ 开头。接下来是我们的帖子条目的主键,它将表示为一个整数 <int:pk>。您可能会问的主键是什么? Django 会自动为我们的数据库模型添加自动递增的主键。因此,虽然我们只在 Post 模型中声明了字段 title、author 和 body,但 Django 在底层还添加了另一个名为 id 的字段,它是我们的主键。我们可以以 id 或 pk 的形式访问它。

    测试

    blog/tests.py

    # blog/tests.py
    from django.contrib.auth import get_user_model
    from django.test import TestCase
    from django.urls import reverse
    
    from .models import Post
    
    
    class BlogTests(TestCase):
    
        def setUp(self):
            self.user = get_user_model().objects.create_user(
                username='testuser',
                email='test@email.com',
                password='secret'
            )
    
            self.post = Post.objects.create(
                title='A good title',
                body='Nice body content',
                author=self.user,
            )
    
        def test_string_representation(self):
            post = Post(title='A sample title')
            self.assertEqual(str(post), post.title)
    
        def test_post_content(self):
            self.assertEqual(f'{self.post.title}', 'A good title')
            self.assertEqual(f'{self.post.author}', 'testuser')
            self.assertEqual(f'{self.post.body}', 'Nice body content')
    
        def test_post_list_view(self):
            response = self.client.get(reverse('home'))
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, 'Nice body content')
            self.assertTemplateUsed(response, 'home.html')
    
        def test_post_detail_view(self):
            response = self.client.get('/post/1/')
            no_response = self.client.get('/post/100000/')
            self.assertEqual(response.status_code, 200)
            self.assertEqual(no_response.status_code, 404)
            self.assertContains(response, 'A good title')
            self.assertTemplateUsed(response, 'post_detail.html')
    

    相关文章

      网友评论

          本文标题:Django快速入门4博客实例&静态文件

          本文链接:https://www.haomeiwen.com/subject/acsopltx.html