学习使用Django和Bulma的Todo应用程序

413 阅读13分钟

Django是一项神奇的技术,它已被证明是一个坚实可靠的Python网络开发框架。Bulma是一个新的、非常酷的CSS框架,可以使你的前端看起来尽可能的好。在本教程中,我们将在后端使用Django,在前端使用Bulma CSS来构建一个小型的Todo应用程序。我们将看到如何将项目添加到列表中,对它们进行相应的样式设计,将项目标记为完整或不完整,以及其他一些技巧。让我们现在就开始使用Django和Bulma的Todo应用程序。


入门

本教程假定你已经安装并运行了Python和Django,准备开始构建你的应用程序。如果你在这些方面需要帮助,[Django For Beginners]可能是一个不错的初读。


启动一个新的Django项目

我们可以先用以下命令启动一个新的[Django项目]django-admin.py startproject todo.

(vdjango) vdjango $ django-admin.py startproject todo

然后,我们将快速启动Django服务器,使用 python manage.py runserver来确认一切都在运行,事情看起来很好!

(vdjango) todo $python manage.py runserver
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).

You have 17 unapplied migration(s). Your project may not work properly until you
apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
May 18, 2020 - 09:49:58
Django version 3.0.6, using settings 'todo.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.

django installed successfully

随着Django项目的建立,我们可以进入项目目录,并使用以下命令运行内置的迁移功能 python manage.py migrate.

(vdjango) vdjango $cd todo
(vdjango) todo $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 admin.0003_logentry_add_action_flag_choices... 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 auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying sessions.0001_initial... OK
(vdjango) todo $

访问管理仪表板

Django有一个很棒的管理仪表盘,你可以免费获得。我们可以在你选择的网络浏览器中访[问http://127.0.0.1:8000/admin,来查看它。

django built in admin login

现在要使用这个管理区,我们需要一个超级用户来完成。我们可以用 python manage.py createsuperuser命令创建一个超级用户。

(vdjango) todo $python manage.py createsuperuser
Username (leave blank to use 'compname'): admin
Email address: admin@example.com
Password:
Password (again):
Superuser created successfully.
(vdjango) todo $

django superuser admin login

使用你在创建超级用户时提供的凭证,登录到管理区,看一看。

django admin logged in


启动你的应用程序

Django的设计是为了让你能够创建可重复使用的应用程序。有许多伟大的Django包可以使用,你可以直接插入到你的Django项目中。一个Django项目只是一个或多个应用程序的集合。现在让我们用以下命令创建一个新的应用程序 python manage.py startapp todoapp.

(vdjango) todo $python manage.py startapp todoapp

一旦该命令运行,你会在你的Django项目中看到一个新的目录,该目录包含了[应用程序]\所需的所有文件。

django startapp files


注册你的应用

当你在Django项目中添加一个新的应用时,你需要让Django知道它。这可以在settings.py文件中完成,就像我们在这里看到的。我们可以像这样添加todoapp。


todotodosettings.py

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

为你的应用程序添加一个urls.py文件

每个应用程序都需要一个urls.py文件,以便在你的Django项目中正确路由HTTP流量。我们现在可以手动添加该文件。

django add urlspy to app

要开始创建URL映射,请从django.urls.com导入路径模块。


todotodoappurls.py

from django.urls import path

urlpatterns = [
    path(),
]

使用urls的include()

在项目级目录中(而不是我们的新应用!),我们要把事情设置好,当用户访问根URL时,我们的Django项目将把这个请求指向我们刚刚创建的新应用。下面的代码主要是接收所有传入的请求,并将它们转发到位于todoapp目录下的[urls.py]\文件。


todotodourls.py

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('todoapp.urls'))
]

添加模板

为了向用户显示一个网页,Django使用了[模板]\。让我们在应用程序中添加一个主页模板。惯例是创建一个模板目录,然后在该目录下用应用程序的名称创建另一个目录。

django templates in app

我们将只放一个HTML片段,像这样。


todotodoapptemplatestodoapphome.html

<h1>Hello from home.html</h1>

在urls.py中使用视图函数

在应用程序的 urls.py 文件中,我们要导入视图模块,并在有人请求主页时调用一个函数。在这段代码中,views.py文件的home()函数将被调用,它是home的一个命名路由。在Django中,你总是希望命名你的路由,这样你就可以设置动态链接。


todotodoappurls.py

from django.urls import path
from . import views

urlpatterns = [
    path('', views.home, name='home'),
]

现在我们可以在views.py文件中添加需要的代码来处理请求。


todotodoappviews.py

from django.shortcuts import render


def home(request):
    return render(request, 'todoapp/home.html', {})

如果一切按计划进行,当你访问网站时,你应该看到一个像这样的简单的HTML页面。

first web page django


在Base模板中添加Bulma CSS

现在我们要完成两个目标。一个是使我们的小项目看起来很时尚,另一个是减少代码的重复性。我们可以通过创建一个基础模板来扩展,同时在基础模板中加入Bulma CSS库来实现这个目标。

django base_html file


todotodoapptemplatestodoappbase.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Django And Bulma!</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.8.2/css/bulma.min.css">
    <script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
</head>
<body>
{% block content %}

{% endblock content %}
</body>
</html>

从基础扩展

我们可以更新home.html模板,从我们刚刚创建的base.html文件进行扩展。


todotodoapptemplatestodoapphome.html

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

{% block content %}
    <section class="section">
        <div class="container">
            <h1 class="title">
                Hello from home.html
            </h1>
        </div>
    </section>
{% endblock %}

马上,我们就可以看到字体已经更新了,而且看起来更好了

base template extends django


添加一个导航条

Bulma有一个漂亮的导航条,你可以很容易地实现。我们可以把导航条的标记放在base.html文件中。这样一来,任何从基地延伸出来的模板文件都会自动包含导航条。


todotodoapptemplatestodoappbase.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Django And Bulma!</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.8.2/css/bulma.min.css">
    <script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
</head>
<body>
<nav class="navbar is-light" role="navigation" aria-label="main navigation">
    <div class="navbar-brand">
        <a class="navbar-item" href="https://bulma.io">
            <img src="https://bulma.io/images/bulma-logo.png" width="112" height="28">
        </a>
    </div>

    <div class="navbar-menu">
        <div class="navbar-start">
            <a class="navbar-item">
                Home
            </a>
        </div>

        <div class="navbar-end">
            <div class="navbar-item">
                <form>
                    <div class="field has-addons">
                        <div class="control">
                            <input class="input" type="text" placeholder="Add Todo">
                        </div>
                        <div class="control">
                            <button type="submit" class="button is-link">Submit</button>
                        </div>
                    </div>
                </form>
            </div>
        </div>
    </div>
</nav>
{% block content %}

{% endblock content %}
</body>
</html>

我们走吧!即使在开始阶段,导航条也看起来不错。

bulma in django base template


使用Django模型的动态数据

当我们在Django中使用[Models]时,会有更多的乐趣。模型保存了应用程序的所有数据。我们可以从我们的应用程序中打开models.py文件,并添加这里的代码。


todotodoappmodels.py

from django.db import models


class Todo(models.Model):
    task = models.CharField(max_length=200)
    completed = models.BooleanField(default=False)

    def __str__(self):
        return self.task

任何时候你在Django中创建一个新的Model或者编辑一个现有的Model,你都必须*创建一个新的迁移。通过运行 python manage.py makemigrations,Django将扫描这些models.py文件,并自动为你建立迁移文件。这些迁移文件是用来修改数据库,使其容纳符合应用程序要求的数据。

(vdjango) todo $python manage.py makemigrations
Migrations for 'todoapp':
  todoappmigrations001_initial.py
    - Create model Todo
(vdjango) todo $

例如,下面的迁移就是在这种情况下创建的。

python managepy makemigrations

from django.db import migrations, models


class Migration(migrations.Migration):

    initial = True

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='Todo',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('task', models.CharField(max_length=200)),
                ('completed', models.BooleanField(default=False)),
            ],
        ),
    ]

迁移数据库

为了让这些迁移文件发挥作用,你需要迁移数据库。这可以通过运行 python manage.py migrate.

(vdjango) todo $python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions, todoapp
Running migrations:
  Applying todoapp.0001_initial... OK
(vdjango) todo $

所以,我们的启示是,在使用Models的时候,你要始终。

  • 1.创建模型(或编辑)。
  • 2.2.创建迁移
  • 3.运行迁移

将你的模型添加到管理员中

Django不仅为你创建了Model和Migrations,而且还为你提供了一种在管理面板上注册Model的方法。一旦它被注册到管理面板上,你就可以在管理区自动获得完整的CRUD(创建、读取、更新、删除)能力。


todotodoappadmin.py

from django.contrib import admin
from .models import Todo

# Register your models here.

admin.site.register(Todo)

就这样,Todoapp和Todo模型在管理仪表板上是可见的。

register model in django admin

让我们使用这个模型向数据库添加一条新记录。

add items to django admin

很好!它被添加了一个漂亮的成功信息。

view new items in django admin

继续添加一些项目,这样我们就有一些数据可以在下一节中使用。


使用基于函数的视图

Django有一些被称为基于类的视图,但在这个例子中,我们将使用更容易理解的基于函数的视图。在下面的代码中,我们需要做的第一件事是导入我们之前创建的Todo模型。有了它,我们定义一个主函数,使用Django ORM从数据库中获取所有todos。一旦我们有了它们,我们就渲染主页模板,同时使用上下文字典将数据传递给该模板。


todotodoappviews.py

from django.shortcuts import render
from .models import Todo


def home(request):
    todos = Todo.objects.all()
    return render(request, 'todoapp/home.html', {'todos': todos})

循环浏览模板中的项目

这让我们可以访问所有我们刚刚从数据库中获取的todos。我们可以在它们上面循环,并输出每个todo的信息,像这样。


todotodoapptemplatestodoapphome.html

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

{% block content %}
    <section class="section">
        <div class="container">
            {% for todo in todos %}
                <h1 class="title">
                    {{ todo.task }}
                </h1>
            {% endfor %}
        </div>
    </section>
{% endblock %}

事情正在形成!我们现在看到数据库中的所有记录都被输出到主页上。

updated django home page


在Bulma中使用一个表

为了让事情变得更漂亮,我们将使用一个漂亮的表格布局,用Bulma CSS样式的HTML表格来显示待办事项。我们可以为每一列添加标题,这样就可以更清楚地了解数据的内容。我们有要完成的任务,是否已经完成,以及删除待办事项的链接的雏形。


todotodoapptemplatestodoapphome.html

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

{% block content %}
    <section class="section">
        <table class="table is-hoverable is-fullwidth">
            <thead>
            <tr>
                <th>Task</th>
                <th>Completed</th>
                <th>Delete</th>
            </tr>
            </thead>
            {% for todo in todos %}
                <tr>
                    <td>
                        {{ todo.task }}
                    </td>
                    <td>
                        {{ todo.completed }}
                    </td>
                    <td>
                        Remove Task
                    </td>
                </tr>
            {% endfor %}
        </table>
    </section>
{% endblock %}

bulma css table

模板中的条件逻辑

我们可以根据我们正在循环的数据,在模板中采取各种行动。下面的代码增加了在已完成的项目上显示穿线和检查标记的能力。对于不完整的项目,我们显示正常的文本和一个空的圆圈。这些图标是通过Font Awesome提供的。Bulma和Font Awesome就像面包和黄油一样工作。


todotodoapptemplatestodoapphome.html

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

{% block content %}
    <section class="section">
        <table class="table is-hoverable is-fullwidth">
            <thead>
            <tr>
                <th>Task</th>
                <th>Completed</th>
                <th>Delete</th>
            </tr>
            </thead>
            {% for todo in todos %}
                <tr>
                    <td>
                        {% if todo.completed == True %}
                            <span style="text-decoration: line-through">{{ todo.task }}</span>
                        {% else %}
                            {{ todo.task }}
                        {% endif %}
                    </td>
                    <td>
                        {% if todo.completed == True %}
                            <i class="far fa-check-circle"></i> {{ todo.completed }}
                        {% else %}
                            <i class="far fa-circle"></i> {{ todo.completed }}
                        {% endif %}
                    </td>
                    <td>
                        Remove Task
                    </td>
                </tr>
            {% endfor %}
        </table>
    </section>
{% endblock %}

这提供了一个相当酷的效果!

bulma font awesome checkmark


使用Django表单

让我们在这个Django应用程序中让我们的表单正常工作。要做到这一点,我们需要在应用程序目录中添加一个 forms.py 文件。

add formspy to django app

这里的例子使用了Django模型表单。这些东西是不可思议的,一旦你让它们工作起来,感觉就像魔法一样:-)。


todotodoappforms.py

from django import forms
from .models import Todo


class TodoForm(forms.ModelForm):
    class Meta:
        model = Todo
        fields = ['task', 'completed']

这个新的模型表单现在可以被导入我们的views.py文件。新的TodoForm类使用一个对象实例来保存从HTML表单发送的任何数据。要在代码中填充表单,你所需要做的就是使用form = TodoForm(request.POST or None)。通过阅读其他代码,你可以看到如何验证表单,并将其保存到数据库中。注意,在Django中,一个特定的视图函数可以处理GET或POST请求。你有责任检查请求类型是什么,然后采取适当的行动。


todotodoappviews.py

from django.shortcuts import render
from .models import Todo
from .forms import TodoForm


def home(request):
    if request.method == 'POST':
        form = TodoForm(request.POST or None)

        if form.is_valid():
            form.save()
            todos = Todo.objects.all()
            return render(request, 'todoapp/home.html', {'todos': todos})
    else:
        todos = Todo.objects.all()
        return render(request, 'todoapp/home.html', {'todos': todos})

存在于base.html文件中的表单需要被更新,以便与我们的模型一起工作。下面的片段显示了我们如何设置方法为POST,添加csrf标记,并确保输入标签的属性是正确的。


todotodoapptemplatestodoappbase.html

<form method="POST">
    {% csrf_token %}
    <div class="field has-addons">
        <div class="control">
            <input name="task" class="input" type="text" placeholder="Add Todo">
        </div>
        <div class="control">
            <button type="submit" class="button is-link">Submit</button>
        </div>
    </div>
</form>

测试表单

我们准备在表单中输入一个新的todo项目,然后点击提交。这应该会添加该待办事项并将其保存到数据库中。

django form submit

点击提交后,页面重新加载,新的todo项目被添加到表格中。表单开始工作了!

the django form submit worked

添加Flash消息

Django有一个很好的消息模块,可以很容易地在你的应用程序中添加Flash消息。首先,我们可以更新视图文件中的代码,以利用消息模块。


todotodoappviews.py

from django.shortcuts import render, redirect
from .models import Todo
from .forms import TodoForm
from django.contrib import messages


def home(request):
    if request.method == 'POST':
        form = TodoForm(request.POST or None)

        if form.is_valid():
            form.save()
            todos = Todo.objects.all()
            messages.success(request, ('Task has been added!'))
            return render(request, 'todoapp/home.html', {'todos': todos})
    else:
        todos = Todo.objects.all()
        return render(request, 'todoapp/home.html', {'todos': todos})

在模板中,我们可以检查是否有flash消息,如果有,就使用Bulma CSS样式输出消息,以达到良好的效果。


todotodoapptemplatestodoapphome.html

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

{% block content %}
    <section class="section">
        {% if messages %}
            {% for message in messages %}
                <article class="message is-success">
                    <div class="message-header">
                        <p>Nice!</p>
                    </div>
                    <div class="message-body">
                        {{ message }}
                    </div>
                </article>
            {% endfor %}
        {% endif %}
        <table class="table is-hoverable is-fullwidth">
            <thead>
            <tr>
                <th>Task</th>
                <th>Completed</th>
                <th>Delete</th>
            </tr>
            </thead>
            {% for todo in todos %}
                <tr>
                    <td>
                        {% if todo.completed == True %}
                            <span style="text-decoration: line-through">{{ todo.task }}</span>
                        {% else %}
                            {{ todo.task }}
                        {% endif %}
                    </td>
                    <td>
                        {% if todo.completed == True %}
                            <i class="far fa-check-circle"></i> {{ todo.completed }}
                        {% else %}
                            <i class="far fa-circle"></i> {{ todo.completed }}
                        {% endif %}
                    </td>
                    <td>
                        Remove Task
                    </td>
                </tr>
            {% endfor %}
        </table>
    </section>
{% endblock %}

让我们在我们的todos列表中增加一个任务。

add another todo django

赢了!现在该任务被添加了,但我们也得到了一个漂亮的消息,表明它被成功添加了。

django success flash message


按ID删除一个项目

在这一部分,我们可以在模板文件中设置路由、视图和链接,以允许删除一个特定的todo任务。


todotodoappurls.py

from django.urls import path
from . import views

urlpatterns = [
    path('', views.home, name='home'),
    path('delete/<int:todo_id>', views.delete, name='delete'),
]

todotodoappviews.py

from django.shortcuts import render, redirect
from .models import Todo
from .forms import TodoForm
from django.contrib import messages


def home(request):
    if request.method == 'POST':
        form = TodoForm(request.POST or None)

        if form.is_valid():
            form.save()
            todos = Todo.objects.all()
            messages.success(request, ('Task has been added!'))
            return render(request, 'todoapp/home.html', {'todos': todos})
    else:
        todos = Todo.objects.all()
        return render(request, 'todoapp/home.html', {'todos': todos})


def delete(request, todo_id):
    todo = Todo.objects.get(id=todo_id)
    todo.delete()
    messages.success(request, ('Task has been Deleted!'))
    return redirect('home')

todotodoapptemplatestodoapphome.html

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

{% block content %}
    <section class="section">
        {% if messages %}
            {% for message in messages %}
                <article class="message is-success">
                    <div class="message-header">
                        <p>Nice!</p>
                    </div>
                    <div class="message-body">
                        {{ message }}
                    </div>
                </article>
            {% endfor %}
        {% endif %}
        <table class="table is-hoverable is-fullwidth">
            <thead>
            <tr>
                <th>Task</th>
                <th>Completed</th>
                <th>Delete</th>
            </tr>
            </thead>
            {% for todo in todos %}
                <tr>
                    <td>
                        {% if todo.completed == True %}
                            <span style="text-decoration: line-through">{{ todo.task }}</span>
                        {% else %}
                            {{ todo.task }}
                        {% endif %}
                    </td>
                    <td>
                        {% if todo.completed == True %}
                            <i class="far fa-check-circle"></i> {{ todo.completed }}
                        {% else %}
                            <i class="far fa-circle"></i> {{ todo.completed }}
                        {% endif %}
                    </td>
                    <td>
                        <a href="{% url 'delete' todo.id %}">Remove Task</a>
                    </td>
                </tr>
            {% endfor %}
        </table>
    </section>
{% endblock %}

现在我们点击一个特定任务的链接,在这个例子中,我们点击 "洗生菜 "的链接来删除这个todo。

add link for delete django item

就这样,那个特定的任务被删除了。

django delete by id


标记一项任务为完成或不完成

我们还希望能够将一项任务标记为完成或不完成。也许我们不想完全删除该任务,但有一个运行列表,你可以划掉已完成的项目。我们现在就可以设置了。


todotodoappurls.py

from django.urls import path
from . import views

urlpatterns = [
    path('', views.home, name='home'),
    path('delete/<int:todo_id>', views.delete, name='delete'),
    path('mark_complete/<int:todo_id>', views.mark_complete, name="mark_complete"),
    path('mark_incomplete/<int:todo_id>', views.mark_incomplete, name="mark_incomplete"),
]

todotodoappviews.py

from django.shortcuts import render, redirect
from .models import Todo
from .forms import TodoForm
from django.contrib import messages


def home(request):
    if request.method == 'POST':
        form = TodoForm(request.POST or None)

        if form.is_valid():
            form.save()
            todos = Todo.objects.all()
            messages.success(request, ('Task has been added!'))
            return render(request, 'todoapp/home.html', {'todos': todos})
    else:
        todos = Todo.objects.all()
        return render(request, 'todoapp/home.html', {'todos': todos})


def delete(request, todo_id):
    todo = Todo.objects.get(id=todo_id)
    todo.delete()
    messages.success(request, ('Task has been Deleted!'))
    return redirect('home')


def mark_complete(request, todo_id):
    todo = Todo.objects.get(id=todo_id)
    todo.completed = True
    todo.save()
    return redirect('home')


def mark_incomplete(request, todo_id):
    todo = Todo.objects.get(id=todo_id)
    todo.completed = False
    todo.save()
    return redirect('home')

todotodoapptemplatestodoapphome.html

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

{% block content %}
    <section class="section">
        {% if messages %}
            {% for message in messages %}
                <article class="message is-success">
                    <div class="message-header">
                        <p>Nice!</p>
                    </div>
                    <div class="message-body">
                        {{ message }}
                    </div>
                </article>
            {% endfor %}
        {% endif %}
        <table class="table is-hoverable is-fullwidth">
            <thead>
            <tr>
                <th>Task</th>
                <th>Completed</th>
                <th>Delete</th>
            </tr>
            </thead>
            {% for todo in todos %}
                <tr>
                    <td>
                        {% if todo.completed == True %}
                            <span style="text-decoration: line-through">{{ todo.task }}</span>
                        {% else %}
                            {{ todo.task }}
                        {% endif %}
                    </td>
                    <td>
                        {% if todo.completed == True %}
                            <i class="far fa-check-circle"></i>
                            <a href="{% url 'mark_incomplete' todo.id %}">Mark Incomplete</a>
                        {% else %}
                            <i class="far fa-circle"></i>
                            <a href="{% url 'mark_complete' todo.id %}">Mark Complete</a>
                        {% endif %}
                    </td>
                    <td>
                        <a href="{% url 'delete' todo.id %}">Remove Task</a>
                    </td>
                </tr>
            {% endfor %}
        </table>
    </section>
{% endblock %}

看看下面的视频短片,看看现在的操作。


编辑一个任务

我们可以添加的最后一项功能是编辑一个todo项目的能力。我们的目标是为每个任务描述提供一个链接,然后启动一个预先填充数据的表格来进行编辑。然后,用户可以进行任何他们喜欢的编辑,点击表格上的提交按钮,任务就会被更新。下面是对URL、视图和模板的编辑,以便将其连接起来。


todotodoappurls.py

from django.urls import path
from . import views

urlpatterns = [
    path('', views.home, name='home'),
    path('delete/<int:todo_id>', views.delete, name='delete'),
    path('mark_complete/<int:todo_id>', views.mark_complete, name="mark_complete"),
    path('mark_incomplete/<int:todo_id>', views.mark_incomplete, name="mark_incomplete"),
    path('edit/<int:todo_id>', views.edit, name="edit"),
]

todotodoappviews.py

from django.shortcuts import render, redirect
from .models import Todo
from .forms import TodoForm
from django.contrib import messages


def home(request):
    if request.method == 'POST':
        form = TodoForm(request.POST or None)

        if form.is_valid():
            form.save()
            todos = Todo.objects.all()
            messages.success(request, ('Task has been added!'))
            return render(request, 'todoapp/home.html', {'todos': todos})
    else:
        todos = Todo.objects.all()
        return render(request, 'todoapp/home.html', {'todos': todos})


def delete(request, todo_id):
    todo = Todo.objects.get(id=todo_id)
    todo.delete()
    messages.success(request, ('Task has been Deleted!'))
    return redirect('home')


def mark_complete(request, todo_id):
    todo = Todo.objects.get(id=todo_id)
    todo.completed = True
    todo.save()
    return redirect('home')


def mark_incomplete(request, todo_id):
    todo = Todo.objects.get(id=todo_id)
    todo.completed = False
    todo.save()
    return redirect('home')


def edit(request, todo_id):
    if request.method == 'POST':
        todo = Todo.objects.get(id=todo_id)
        form = TodoForm(request.POST or None, instance=todo)

        if form.is_valid():
            form.save()
            messages.success(request, ('Task has been edited!'))
            return redirect('home')
    else:
        todo = Todo.objects.get(id=todo_id)
        return render(request, 'todoapp/edit.html', {'todo': todo})

todotodoapptemplatestodoappedit.html

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

{% block content %}
    <section class="section">
        <form method="POST">
            {% csrf_token %}
            <div class="field has-addons">
                <div class="control">
                    <input name="task" class="input" type="text" placeholder="{{ todo.task }}" value="{{ todo.task }}">
                    <input name="completed" type="hidden" value="{{ todo.completed }}">
                </div>
                <div class="control">
                    <button type="submit" class="button is-link">Edit Todo</button>
                </div>
            </div>
        </form>
    </section>
{% endblock %}

现在,我们通过点击 "采摘西红柿 "项目的 "编辑任务 "链接来进行测试。它加载了一个带有该文本的新表单,我们把它改为 "摘这么多番茄!!"。一旦按钮被点击,编辑就完成了,页面就会重定向,并有一个漂亮的Flash信息,让我们知道编辑成功了。

使用Django和Bulma的Todo应用程序总结

谢谢你阅读这个有趣的小教程,关于使用Django和Bulma一起建立一个基本的todo应用程序。我们看到了如何在Django中进行所有的CRUD操作,同时还学习了一些关于很酷的新CSS框架Bulma的知识。