使用Django和Heroku快速迭代

开展在线业务可能会非常复杂。 尽管从表面上看,创建在线业务比实体交易要容易得多,但企业家可能会迷失在众多选择中。 在线企业家陷入的一些最常见陷阱包括:

  • 太过早地进行构建 :浪费时间并浪费金钱来构建复杂的产品。 在此过程中要充满动力,对产品失去信心,并放弃项目。
  • 对这个想法抱有太多的信念 :即使客户没有出现,不付款或不满意,也要坚持最初的想法,不要反复进行。
  • 未能开始 :当某人开始构建Web项目时,他/她可能会被看似无限的决定和选择所淹没。 使用什么托管? 什么平台? 什么是WordPress主题? 如何建立高转换目标网页? 什么编程语言和什么数据库? 您应该使用网络框架吗? 前端使用Vanilla JavaScript还是jQuery? 也许是因为项目一旦成熟就需要一个更复杂的前端框架?
  • 无法启动 :在构建Web项目时,即使您决定使用技术堆栈,也会因收到的反馈而感到不知所措。 违反直觉,听太多反馈被认为是错误的。 可能是反正不会使用您的产品的人的反馈。 人们往往对所有事情都有自己的见解,即使他们并不完全了解该领域。

鉴于人们在前进道路上可能会失败的多种方式,以下几点非常重要:

  • 尽可能少地,尽快地构建,并向您认为是潜在客户的人展示 :最小化成本和精力。
  • 尽快将其投入在线 :获得人们对产品的反馈,而不是您的抽象想法的反馈。
  • 快速做出改变 :了解客户的需求时,敏捷并为您的第一批付费客户提供良好的服务至关重要。

这就是原型制作的地方。 企业家应该精益求精,而不是浪费时间和资源。 在开始时尽可能少地构建可以证明是一种美德。

关于什么是原型以及应如何创建原型,存在许多思想流派。 有人说它应该只是一个登陆页面,而有些人则说它应该是最终产品的精简版。 我更喜欢第二种。 仅使用目标网页可能会感到骗子。 另外,您无法获得有关如何解决问题的反馈,而只能获得有关问题是否值得解决的反馈。

这是一个聪明的原型在线企业家的工具带:

  • 前端框架 :Bootstrap,Foundation,jQuery,Vue等。使用前端框架将使您的应用程序以适当的设计在不同的屏幕尺寸和不同的浏览器上运行。
  • 后端框架 :Django,Ruby on Rails,Laravel。 使用后端框架将帮助您轻松处理HTML模板,HTTP表单,数据库访问,URL架构等。
  • 平台即服务 :Heroku,Google App Engine,AWS Elastic Beanstalk。 选择PaaS可以使您摆脱管理服务器,日志聚合,正常运行时间监控,部署基础架构等方面的痛苦。

在本教程中,我们将本着快速原型的精神构建一个简单的应用程序。 我们将使用Django,Bootstrap CSS和Heroku。 重点将放在后端而不是前端。

我们将利用Heroku平台尽早使某些内容联机并快速部署新功能。 我们将使用Django构建复杂的数据库模型和功能。 Bootstrap CSS将为我们的页面提供合理的默认样式。 聊够了,走吧。

我们正在建设什么

确保您正在为此而坐。 这个主意将使您脱颖而出。 推销方法如下:您是否不只是讨厌如何获得所有这些折扣代码,但忘记使用它们,它们就会过期?

将代码存储在可以搜索它们的地方,并在它们即将到期时得到通知会不会很酷? 我知道,好主意,对不对? 好吧,放下您的信用卡,您将不会在此投资。 您将要构建它。

入门

在本教程中,我将使用Python3。如果您使用的是Python 2.7,则更改应该相当容易。 我还将假设您熟悉setuptools ,Python virtualenvs和Git。 继续之前的另一件事:确保您具有GitHub和Heroku帐户。 要使用Heroku,还需要安装Heroku CLI

让我们从创建一个virtualenv开始:

$ mkvirtualenv coupy

您可能已经知道,我们的应用程序名称是Coupy 。 让我们切换到新的virtualenv $ workon coupy并安装Django:

$ pip install Django

进入您的GitHub帐户并创建一个新项目。 接下来,让我们克隆该项目:

$ git clone https://github.com/<GITHUB_USERNAME>/<GITHUB_PROJECT_NAME>.git
$ cd <GITHUB_PROJECT_NAME>

下一步逻辑是创建一个Django项目。 要将Django项目部署到Heroku,我们需要遵循一些准则。 幸运的是,我们可以为此使用项目模板。 这样做的方法如下:

$ django-admin.py startproject --template=https://github.com/heroku/heroku-django-template/archive/master.zip --name=Procfile coupy

您可能需要在某些文件夹中移动。 确保您的存储库根文件夹如下所示:

.
├── Procfile
├── README.md
├── coupy
│   ├── __init__.py
│   ├── settings.py
│   ├── static
│   │   └── humans.txt
│   ├── urls.py
│   └── wsgi.py
├── manage.py
├── requirements.txt
└── runtime.txt

现在,让我们安装模板提供的要求:

$ pip install -r requirements.txt

现在,我们要将新创建的文件推送到GitHub:

$ git add .
$ git commit -m"Init Django project"
$ git push origin master

让我们看看到目前为止我们所做的工作是否可行:

$ python manage.py runserver

现在打开浏览器窗口,然后转到http:// localhost:8000 。 如果一切顺利,您应该会看到经典的Django Welcome页面。 为了确保从Heroku的角度来看一切都很好,我们还可以这样运行应用程序:

$ heroku local web

为了证明我们上线的速度,让我们首先部署到Heroku:

$ heroku login
$ heroku create

现在,我们已经创建了一个Heroku应用程序,但尚未将任何代码发送到Heroku。 请注意,Heroku创建了一个用户友好的应用程序ID。 这是您应该获得的输出:

Creating app... done, ⬢ <HEROKU_APP_ID>
https://<HEROKU_APP_ID>.herokuapp.com/ | https://git.heroku.com/<HEROKU_APP_ID>.git

现在,我们需要将我们的仓库与新创建的Heroku应用程序关联:

$ heroku git:remote -a <HEROKU_APP_ID>
$ git push heroku master
$ heroku open

太棒了,您刚刚将应用程序部署到了Heroku。 它并没有做太多,但是您在创纪录的时间内将某些东西放到了网上。 做得好。

设置数据库

如果没有数据库,您可能永远不会构建一个平凡的Web应用程序。 数据库是Web应用程序的数据存储部分。 Web应用程序在这里保持其状态(至少是大多数状态)。 这是我们保留用户帐户和登录详细信息的地方,还有更多。 Heroku提供托管的PostgreSQL服务。

这就是我们要使用的。 确保您已在计算机上安装了Postgres,并创建了要在我们的应用程序中使用的数据库实例。 Heroku需要设置一个环境变量才能连接到数据库服务。 我们需要设置的变量是DATABASE_URL

$ export DATABASE_URL="postgres://<USERNAME>:<PASSWORD>@localhost:5432/<DATABASE_NAME>"

现在让我们告诉Django应用迁移并创建必要的表:

$ ./manage.py migrate

让我们创建一个超级用户并登录到http:// localhost:8000 / admin的管理界面:

$ ./manage.py createsuperuser
$ ./manage.py runserver

我们可以看到表确实已经创建。 默认情况下,Heroku已经将数据库实例与您的应用程序相关联。 您可以通过在Heroku在线控制台中检入Heroku HEROKU_APP_ID > Settings > Config Variables来确保确实如此。 您应该在此处看到DATABASE_URL设置为Heroku生成的数据库地址。

现在,我们必须运行迁移并在线创建超级用户命令。 让我们看看它们是否都能按预期工作:

$ heroku run python manage.py migrate
$ heroku run python manage.py createsuperuser

如果一切顺利,如果我们访问https://<HEROKU_APP_ID>.herokuapp.com/admin/ ,我们应该能够使用刚刚提供的凭据登录。

用户认证

在本节中,我们将初始化Django应用程序,并使用Django预定义组件在我们的应用程序中创建用户身份验证功能。

$ ./manage.py startapp main

在新应用程序内部,我们将创建一个urls.py文件:

from django.conf.urls import url
from django.contrib.auth import views as auth_views
from django.views.generic.base import RedirectView


urlpatterns = [
    url('^$', RedirectView.as_view(url='login'), name='index'),
    url(r'^login$', auth_views.LoginView.as_view(), name='login'),
    url(r'^logout$', auth_views.LogoutView.as_view(), name='logout'),
]

在这里,我们使用三个通用的Django视图:

  • RedirectView :由于应用程序的基本URL不会执行任何操作,因此我们将重定向到登录页面。
  • LoginView :Django预定义视图,用于创建登录表单并实现用户身份验证例程。
  • LogoutView :Django预定义视图,用于注销用户并重定向到特定页面。

main应用程序添加到INSTALLED_APPS列表中:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    # Disable Django's own staticfiles handling in favour of WhiteNoise, for
    # greater consistency between gunicorn and `./manage.py runserver`. See:
    # http://whitenoise.evans.io/en/stable/django.html#using-whitenoise-in-development
    'whitenoise.runserver_nostatic',
    'django.contrib.staticfiles',

    'main',
]

main.urls连接到根URL架构:

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

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

为了正确显示表单,包括样式和类以及所有内容,我们需要安装django-widget-tweaks

$ pip install django-widget-tweaks
$ pip freeze > requirements.txt

django-widget-tweaks添加到INSTALLED_APPS

INSTALLED_APPS = [
    # ...
    'main',
    'widget_tweaks',
]

现在,我们将这两个配置添加到settings.py

  • LOGIN_REDIRECT_URL :告诉Django成功通过身份验证后将用户重定向到何处。
  • LOGOUT_REDIRECT_URL :告诉Django用户注销后将其重定向到何处。
# settings.py

LOGIN_REDIRECT_URL = 'dashboard'
LOGOUT_REDIRECT_URL = 'login'

让我们编写一个简单的主模板base.html和一个扩展它的dashboard.html模板。 我们稍后再回到仪表板。

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />

    <title>{% block title %}{% endblock %}</title>
</head>
<body>
    <div class="container">
    {% block content %}{% endblock %}
    </div><!-- /container-->
</body>
</html>
{% extends 'base.html' %}

{% block title %}Dashboard{% endblock %}

{% block content %}
<h1>Dashboard</h1>
{% endblock %}

编写呈现dashboard.html模板的视图:

from django.shortcuts import render
from django.core.urlresolvers import reverse_lazy


@login_required(login_url=reverse_lazy('login'))
def dashboard(request):
    return render(request, 'dashboard.html')

我们都准备好了。 转到http://localhost:8000/login/并测试身份验证是否有效。 接下来,保存您的进度:

$ git add .
$ git commit -m"Login/Logout/Dashboard views"

创建优惠券模型

现在,我们来设计应用程序中最重要的部分,设计Coupon模型。 我们将安装django-model-utilsdjango-model-utils添加一些额外的属性。

$ pip install django-model-utils
$ pip freeze > requirements.txt

编写Coupon模型:

from model_utils.models import TimeStampedModel, TimeFramedModel
from django.db import models
from django.contrib.auth.models import User


class Coupon(TimeStampedModel, TimeFramedModel):
    owner = models.ForeignKey(User)
    discount_code = models.CharField("Discount Code", max_length=100)
    website = models.URLField("Website")
    description = models.TextField("Coupon Description")

我们扩展的django-model-utils模型使我们能够:

  • TimeStampedModel通过created字段帮助我们跟踪何时将模型放置在数据库中。
  • TimeFramedModelstart字段和end字段添加到我们的模型中。 我们正在使用这些字段来跟踪优惠券的可用性。

将模型挂接到管理员:

from django.contrib import admin
from .models import Coupon


@admin.register(Coupon)
class CouponAdmin(admin.ModelAdmin):
    pass

创建并应用迁移:

$ ./manage.py makemigrations
$ ./manage.py migrate

保存进度:

$ git add .
$ git commit -m"Create Coupon model"

优惠券创建的ModelForm

Django的很酷的功能之一就是能够从模型类创建表单。 我们将创建一个使用户能够创建优惠券的表格。 让我们在main应用程序中创建一个forms.py文件:

from django.forms import ModelForm
from .models import Coupon


class CouponForm(ModelForm):
    class Meta:
        model = Coupon
        exclude = ('owner', ) # We're setting this field ourselves

让我们将此表单添加到仪表板。 我们需要更改视图和模板:

# views.py

from django.shortcuts import render, redirect
from django.core.urlresolvers import reverse_lazy
from .forms import CouponForm


@login_required(login_url=reverse_lazy('login'))
def dashboard(request):
    if request.method == 'POST':
        form = CouponForm(request.POST)
        if form.is_valid():
            coupon = form.save(commit=False)
            coupon.owner = request.user
            coupon.save()
            return redirect('dashboard')
    else:
        form = CouponForm()

    return render(request, 'dashboard.html', context={'create_form': form})
{% extends 'base.html' %}

{% load widget_tweaks %}

{% block title %}Dashboard{% endblock %}

{% block content %}
<h1>Dashboard</h1>

<form method="post">
    {% csrf_token %}
    <div class="form-group">
        <label for="discount_code">Discount Code</label>
        {% render_field create_form.discount_code class="form-control" placeholder="Discount Code" %}
    </div>

    <div class="form-group">
        <label for="website">Website</label>
        {% render_field create_form.website class="form-control" placeholder="Website" %}
    </div>

    <div class="form-group">
        <label for="description">Description</label>
        {% render_field create_form.description class="form-control" placeholder="Description" %}
    </div>

    <div class="form-group">
        <label for="start">Available From</label>
        {% render_field create_form.start class="form-control" placeholder="Available From (MM/DD/YYYY)" %}
    </div>

    <div class="form-group">
        <label for="end">Expires on</label>
        {% render_field create_form.end class="form-control" placeholder="Expires On (MM/DD/YYYY)" %}
    </div>

    <button type="submit" class="btn btn-primary">Save</button>
</form>


{% endblock %}

现在,我们有了从仪表盘创建优惠券的方法。 去试试看。 我们无法在信息中心中查看优惠券,但可以在管理面板中查看。 让我们保存进度:

$ git add .
$ git commit -m"Coupon creation form in dashboard"

即将过期的优惠券

我们希望在仪表板上显示另一件事:即将过期的优惠券,例如本周过期的优惠券。

django.contrib.humanize添加到INSTALLED_APPS以人性化的方式在模板中显示日期。

让我们增强视图,以便它获取即将到期的优惠券并将其传递给模板上下文:

from datetime import timedelta

from django.contrib.auth.decorators import login_required
from django.shortcuts import render, redirect
from django.core.urlresolvers import reverse_lazy
from django.utils import timezone

from .forms import CouponForm
from .models import Coupon


@login_required(login_url=reverse_lazy('login'))
def dashboard(request):
    expiring_coupons = Coupon.objects.filter(
        end__gte=timezone.now(),
        end__lte=timezone.now() + timedelta(days=7))

    if request.method == 'POST':
        form = CouponForm(request.POST)
        if form.is_valid():
            coupon = form.save(commit=False)
            coupon.owner = request.user
            coupon.save()
            return redirect('dashboard')
    else:
        form = CouponForm()

    return render(request, 'dashboard.html', context={
        'create_form': form,
        'expiring_coupons': expiring_coupons})

让我们更新模板,以使其以表格形式显示到期的息票。 我们还将使用Bootstrap的网格系统将创建表单和表格放在两个单独的列中:

{% extends 'base.html' %}

{% load widget_tweaks %}
{% load humanize %}

{% block title %}Dashboard{% endblock %}

{% block content %}
<h1>Dashboard</h1>
<div class="row">
    <div class="col-md-6">
        [The form code]
    </div>
    <div class="col-md-6">
        {% if expiring_coupons %}
            <table class="table">
                <thead>
                    <tr>
                        <th>Discount Code</th>
                        <th>Website</th>
                        <th>Expire Date</th>
                    </tr>
                </thead>
            {% for coupon in expiring_coupons %}
                <tr>
                    <td>{{coupon.discount_code}}</td>
                    <td>{{coupon.website}}</td>
                    <td>{{coupon.end|naturalday }}</td>
                </tr>
            {% endfor %}
            </table>
        {% else %}
            <div class="alert alert-success" role="alert">No coupons expiring soon</div>
        {% endif %}

        {% endblock %}
    </div>
</div>

看起来不错。 保存进度:

$ git add .
$ git commit -m"Implementing the expiring coupon list"

目录视图

现在让我们学习其他一些Django快捷方式,以创建一个视图,显示我们可用的优惠券列表。 我们正在谈论通用视图。 这是快速创建ListView

# views.py

# ...
from django.views.generic.list import ListView
from django.db.models import Q


class CouponListView(ListView):
    model = Coupon

    def get_queryset(self):
        return Coupon.objects.filter(Q(end__gte=timezone.now()) | Q(end__isnull=True)).order_by('-end')

现在,将视图绑定到您的URL模式中:

# main/urls.py

from django.conf.urls import url
from django.contrib.auth import views as auth_views
from django.views.generic.base import RedirectView
from .views import dashboard, CouponListView


urlpatterns = [
    url('^$', RedirectView.as_view(url='login'), name='index'),
    url(r'^login/$', auth_views.LoginView.as_view(), name='login'),
    url(r'^logout/$', auth_views.LogoutView.as_view(), name='logout'),
    url(r'^dashboard/$', dashboard, name='dashboard'),
    url(r'^catalogue/$', CouponListView.as_view(template_name='catalogue.html'), name='catalogue'),

]

创建模板catalogue.html

{% extends 'base.html' %}

{% load humanize %}

{% block title %}Catalogue{% endblock %}

{% block content %}
<h1>Catalogue</h1>
<div class="row">

    <div class="col-md-12">
        {% if object_list %}
            <table class="table">
                <thead>
                    <tr>
                        <th>Discount Code</th>
                        <th>Website</th>
                        <th>Expire Date</th>
                    </tr>
                </thead>
            {% for coupon in object_list %}
                <tr>
                    <td>{{coupon.discount_code}}</td>
                    <td>{{coupon.website}}</td>
                    <td>{{coupon.end|naturalday }}</td>
                </tr>
            {% endfor %}
            </table>
        {% else %}
            <div class="alert alert-success" role="alert">
                No coupons yet. Create your first one <a href="{% url 'dashboard' %}">here</a>.
            </div>
        {% endif %}

        {% endblock %}
    </div>
</div>

由于我们已经完成了所有工作,因此请转到http://localhost:8000/catalogue/查看您的优惠券目录。

保存进度:

$ git add .
$ git commit -m"Creating the catalogue view"

这非常接近MVP。 我鼓励您进行一些微调,例如创建导航栏,登录/注销/注册按钮等。重要的是,您应该了解原型制作过程以及将产品送到那里以便人们看到的过程。 说到这一点,我们的产品尚未在线。 我们没有将最新版本推送到Heroku。 让我们这样做,然后拿起电话,打电话给投资者。

结论

我们创建了一个简单但实​​用的应用程序。 我们快速创建了功能,并将其在线部署,以便我们的潜在客户可以使用它们并提供反馈。 最好向人们展示,而不是仅仅谈论一个想法。

我们可以得出一些结论:

翻译自: https://code.tutsplus.com/tutorials/iterating-fast-with-django-heroku--cms-28997

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值