如何创建一个Django网站

本文参考官方文档演示如何创建一个简单的 django 网站,使用的 django 版本为1.7。

1. 创建项目

运行下面命令就可以创建一个 django 项目,项目名称叫 mysite :

$ django-admin.py startproject mysite

创建后的项目目录如下:

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

1 directory, 5 files

说明:

  • __init__.py :让 Python 把该目录当成一个开发包 (即一组模块)所需的文件。 这是一个空文件,一般你不需要修改它。
  • manage.py :一种命令行工具,允许你以多种方式与该 Django 项目进行交互。 键入python manage.py help,看一下它能做什么。 你应当不需要编辑这个文件;在这个目录下生成它纯是为了方便。
  • settings.py :该 Django 项目的设置或配置。
  • urls.py:Django项目的URL路由设置。目前,它是空的。
  • wsgi.py:WSGI web 应用服务器的配置文件。更多细节,查看 How to deploy with WSGI

接下来,你可以修改 settings.py 文件,例如:修改 LANGUAGE_CODE、设置时区 TIME_ZONE

SITE_ID = 1

LANGUAGE_CODE = 'zh_CN'

TIME_ZONE = 'Asia/Shanghai'

USE_TZ = True

上面开启了 Time zone 特性,需要安装 pytz:

$ sudo pip install pytz

2. 运行项目

在运行项目之前,我们需要创建数据库和表结构,这里我使用的默认数据库:

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

然后启动服务:

$ python manage.py runserver

你会看到下面的输出:

Performing system checks...

System check identified no issues (0 silenced).
January 28, 2015 - 02:08:33
Django version 1.7.1, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

这将会在端口8000启动一个本地服务器, 并且只能从你的这台电脑连接和访问。 既然服务器已经运行起来了,现在用网页浏览器访问 http://127.0.0.1:8000/。你应该可以看到一个令人赏心悦目的淡蓝色 Django 欢迎页面它开始工作了。

你也可以指定启动端口:

$ python manage.py runserver 8080

以及指定 ip:

$ python manage.py runserver 0.0.0.0:8000

3. 创建 app

前面创建了一个项目并且成功运行,现在来创建一个 app,一个 app 相当于项目的一个子模块。

在项目目录下创建一个 app:

$ python manage.py startapp polls

如果操作成功,你会在 mysite 文件夹下看到已经多了一个叫 polls 的文件夹,目录结构如下:

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

1 directory, 6 files

4. 创建模型

  • 每一个 Django Model 都继承自 django.db.models.Model
  • 在 Model 当中每一个属性 attribute 都代表一个 database field
  • 通过 Django Model API 可以执行数据库的增删改查, 而不需要写一些数据库的查询语句

打开 polls 文件夹下的 models.py 文件。创建两个模型:

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 was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

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

然后在 mysite/settings.py 中修改 ` INSTALLED_APPS` 添加 polls:

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'polls',
)

在添加了新的 app 之后,我们需要运行下面命令告诉 Django 你的模型做了改变,需要迁移数据库:

$ python manage.py makemigrations polls

你会看到下面的输出日志:

Migrations for 'polls':
  0001_initial.py:
    - Create model Choice
    - Create model Question
    - Add field question to choice

你可以从 polls/migrations/0001_initial.py 查看迁移语句。

运行下面语句,你可以查看迁移的 sql 语句:

$ python manage.py sqlmigrate polls 0001

输出结果:

BEGIN;
CREATE TABLE "polls_choice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "choice_text" varchar(200) NOT NULL, "votes" integer NOT NULL);
CREATE TABLE "polls_question" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "question_text" varchar(200) NOT NULL, "pub_date" datetime NOT NULL);
CREATE TABLE "polls_choice__new" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "choice_text" varchar(200) NOT NULL, "votes" integer NOT NULL, "question_id" integer NOT NULL REFERENCES "polls_question" ("id"));
INSERT INTO "polls_choice__new" ("choice_text", "votes", "id") SELECT "choice_text", "votes", "id" FROM "polls_choice";
DROP TABLE "polls_choice";
ALTER TABLE "polls_choice__new" RENAME TO "polls_choice";
CREATE INDEX polls_choice_7aa0f6ee ON "polls_choice" ("question_id");

COMMIT;

你可以运行下面命令,来检查数据库是否有问题:

$ python manage.py check

再次运行下面的命令,来创建新添加的模型:

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

总结一下,当修改一个模型时,需要做以下几个步骤:

  • 修改 models.py 文件
  • 运行 python manage.py makemigrations 创建迁移语句
  • 运行 python manage.py migrate,将模型的改变迁移到数据库中

你可以阅读 django-admin.py documentation,查看更多 manage.py 的用法。

创建了模型之后,我们可以通过 Django 提供的 API 来做测试。运行下面命令可以进入到 python shell 的交互模式:

$ python manage.py shell

下面是一些测试:

>>> from polls.models import Question, Choice   # Import the model classes we just wrote.

# No questions are in the system yet.
>>> Question.objects.all()
[]

# Create a new Question.
# Support for time zones is enabled in the default settings file, so
# Django expects a datetime with tzinfo for pub_date. Use timezone.now()
# instead of datetime.datetime.now() and it will do the right thing.
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())

# Save the object into the database. You have to call save() explicitly.
>>> q.save()

# Now it has an ID. Note that this might say "1L" instead of "1", depending
# on which database you're using. That's no biggie; it just means your
# database backend prefers to return integers as Python long integer
# objects.
>>> q.id
1

# Access model field values via Python attributes.
>>> q.question_text
"What's new?"
>>> q.pub_date
datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>)

# Change values by changing the attributes, then calling save().
>>> q.question_text = "What's up?"
>>> q.save()

# objects.all() displays all the questions in the database.
>>> Question.objects.all()
[<Question: Question object>]

打印所有的 Question 时,输出的结果是 [<Question: Question object>],我们可以修改模型类,使其输出更为易懂的描述。修改模型类:

from django.db import models

class Question(models.Model):
    # ...
    def __str__(self):              # __unicode__ on Python 2
        return self.question_text

class Choice(models.Model):
    # ...
    def __str__(self):              # __unicode__ on Python 2
        return self.choice_text

接下来继续测试:

>>> from polls.models import Question, Choice

# Make sure our __str__() addition worked.
>>> Question.objects.all()
[<Question: What's up?>]

# Django provides a rich database lookup API that's entirely driven by
# keyword arguments.
>>> Question.objects.filter(id=1)
[<Question: What's up?>]
>>> Question.objects.filter(question_text__startswith='What')
[<Question: What's up?>]

# Get the question that was published this year.
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: What's up?>

# Request an ID that doesn't exist, this will raise an exception.
>>> Question.objects.get(id=2)
Traceback (most recent call last):
    ...
DoesNotExist: Question matching query does not exist.

# Lookup by a primary key is the most common case, so Django provides a
# shortcut for primary-key exact lookups.
# The following is identical to Question.objects.get(id=1).
>>> Question.objects.get(pk=1)
<Question: What's up?>

# Make sure our custom method worked.
>>> q = Question.objects.get(pk=1)

# Give the Question a couple of Choices. The create call constructs a new
# Choice object, does the INSERT statement, adds the choice to the set
# of available choices and returns the new Choice object. Django creates
# a set to hold the "other side" of a ForeignKey relation
# (e.g. a question's choice) which can be accessed via the API.
>>> q = Question.objects.get(pk=1)

# Display any choices from the related object set -- none so far.
>>> q.choice_set.all()
[]

# Create three choices.
>>> q.choice_set.create(choice_text='Not much', votes=0)
<Choice: Not much>
>>> q.choice_set.create(choice_text='The sky', votes=0)
<Choice: The sky>
>>> c = q.choice_set.create(choice_text='Just hacking again', votes=0)

# Choice objects have API access to their related Question objects.
>>> c.question
<Question: What's up?>

# And vice versa: Question objects get access to Choice objects.
>>> q.choice_set.all()
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
>>> q.choice_set.count()
3

# The API automatically follows relationships as far as you need.
# Use double underscores to separate relationships.
# This works as many levels deep as you want; there's no limit.
# Find all Choices for any question whose pub_date is in this year
# (reusing the 'current_year' variable we created above).
>>> Choice.objects.filter(question__pub_date__year=current_year)
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]

# Let's delete one of the choices. Use delete() for that.
>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delete()
>>>

上面这部分测试,涉及到 django orm 相关的知识,详细说明可以参考 Django中的ORM

5. 管理 admin

Django有一个优秀的特性, 内置了Django admin后台管理界面, 方便管理者进行添加和删除网站的内容.

新建的项目系统已经为我们设置好了后台管理功能,见 mysite/settings.py:

INSTALLED_APPS = (
    'django.contrib.admin', #默认添加后台管理功能
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'polls',
)

同时也已经添加了进入后台管理的 url, 可以在 mysite/urls.py 中查看:

url(r'^admin/', include(admin.site.urls)), #可以使用设置好的url进入网站后台

接下来我们需要创建一个管理用户来登录 admin 后台管理界面:

$ python manage.py createsuperuser
Username (leave blank to use 'june'): admin
Email address:
Password:
Password (again):
Superuser created successfully.

上面创建了一个 admin 的超级用户,密码也为 admin。

再次运行项目:

$ python manage.py runserver

然后,访问web 页面 http://127.0.0.1:8000/admin/,你将会看到:

输入用户名和密码,你可以看到:

这时候你可以看到,你可以修改 groups 和 users 两个对象,但是你不能修改你添加的模型。下面来使你添加的模型也能修改,修改 polls/admin.py:

from django.contrib import admin
from polls.models import Choice, Question

class ChoiceInline(admin.StackedInline):
    model = Choice
    extra = 3

class QuestionAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,               {'fields': ['question_text']}),
        ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
    ]
    inlines = [ChoiceInline]
    list_filter = ['pub_date']
    list_display = ('question_text', 'pub_date', 'was_published_recently')

admin.site.register(Choice)
admin.site.register(Question, QuestionAdmin)

你单击表头时,会发现 was_published_recently 这一列无法排序,我们可以修改 polls/models.py 中的 Question 模型,额外添加一些属性:

class Question(models.Model):
    # ...
    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
    was_published_recently.admin_order_field = 'pub_date'
    was_published_recently.boolean = True
    was_published_recently.short_description = 'Published recently?'

定制外观

在项目根路径创建一个 templates 目录,并修改 mysite/settings.py 文件,添加下面设置:

TEMPLATE_DIRS = [os.path.join(BASE_DIR, 'templates')]

在 templates 下面创建一个 admin 目录,并从 Django admin 模板路径下拷贝 admin/base_site.html 文件到 admin 目录下,修改该文件:

{% block branding %}
<h1 id="site-name"><a href="{% url 'admin:index' %}">Polls Administration</a></h1>
{% endblock %}

同样,你可以参考上面定制 admin/index.html 内容。

使用第三方插件

Django现在已经相对成熟,已经有许多不错的可以使用的第三方插件可以使用,这些插件各种各样,现在我们使用一个第三方插件使后台管理界面更加美观,目前大部分第三方插件可以在 Django Packages 中查看,尝试使用 django-admin-bootstrap 美化后台管理界面。

安装:

$ pip install bootstrap-admin

然后在 mysite/settings.py 中修改 INSTALLED_APPS:

INSTALLED_APPS = (
    'bootstrap_admin',  #一定要放在`django.contrib.admin`前面
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'polls',
)

from django.conf import global_settings
TEMPLATE_CONTEXT_PROCESSORS = global_settings.TEMPLATE_CONTEXT_PROCESSORS + (
    'django.core.context_processors.request',
)
BOOTSTRAP_ADMIN_SIDEBAR_MENU = True

保存后,再次刷新页面,访问 http://127.0.0.1:8000/admin

6. 视图和URL配置

Django 中 views 里面的代码就是一个一个函数逻辑,处理客户端(浏览器)发送的 HTTPRequest,然后返回 HTTPResponse。

第一个视图

创建 polls/views.py 文件并添加如下内容:

from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello, world. You're at the polls index.")

在 polls/urls.py 中添加一个 url 映射:

from django.conf.urls import patterns, url
from polls import views

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

这时候 polls 目录结构如下:

polls
├── __init__.py
├── admin.py
├── migrations
│   ├── 0001_initial.py
│   ├── __init__.py
├── models.py
├── tests.py
├── urls.py
└── views.py

在上面视图文件中,我们只是告诉 Django,所有指向 URL /index/ 的请求都应由 index 这个视图函数来处理。

Django 在检查 URL 模式前,移除每一个申请的URL开头的斜杠。 这意味着我们为 /index/ 写URL模式不用包含斜杠。

模式包含了一个尖号(^)和一个美元符号($)。这些都是正则表达式符号,并且有特定的含义: ^要求表达式对字符串的头部进行匹配,$符号则要求表达式对字符串的尾部进行匹配。

如果你访问 /index,默认会重定向到末尾带有反斜杠的请求上去,这是受配置文件setting中 APPEND_SLASH 项控制的。

如果你是喜欢所有URL都以 / 结尾的人(Django开发者的偏爱),那么你只需要在每个 URL 后添加斜杠,并且设置 APPEND_SLASH 为 “True”。如果不喜欢URL以斜杠结尾或者根据每个 URL 来决定,那么需要设置 APPEND_SLASH 为 “False”,并且根据你自己的意愿来添加结尾斜杠/在URL模式后。

接下来配置项目根路径的 URL 映射,修改 mysite/urls.py 如下:

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

urlpatterns = patterns('',
    url(r'^polls/', include('polls.urls')),
    url(r'^admin/', include(admin.site.urls)),
)

打开浏览器,访问 http://localhost:8000/polls/,你将会看到 Hello, world. You’re at the polls index.

编写更多视图

修改 polls/views.py 文件,添加:

def detail(request, question_id):
    return HttpResponse("You're looking at question %s." % question_id)

def results(request, question_id):
    response = "You're looking at the results of question %s."
    return HttpResponse(response % question_id)

def vote(request, question_id):
    return HttpResponse("You're voting on question %s." % question_id)

然后,修改 polls/urls.py 添加映射:

from django.conf.urls import patterns, url

from polls import views

urlpatterns = patterns('',
    # ex: /polls/
    url(r'^$', views.index, name='index'),
    # ex: /polls/5/
    url(r'^(?P<question_id>\d+)/$', views.detail, name='detail'),
    # ex: /polls/5/results/
    url(r'^(?P<question_id>\d+)/results/$', views.results, name='results'),
    # ex: /polls/5/vote/
    url(r'^(?P<question_id>\d+)/vote/$', views.vote, name='vote'),
)

正则表达式

正则表达式是通用的文本模式匹配的方法。 Django URLconfs 允许你使用任意的正则表达式来做强有力的 URL 映射,不过通常你实际上可能只需要使用很少的一部分功能。这里是一些基本的语法。

符号 匹配
. 任意单一字符
\d 任意一位数字
[A-Z] A 到 Z中任意一个字符(大写)
[a-z] a 到 z中任意一个字符(小写)
[A-Za-z] a 到 z中任意一个字符(不区分大小写)
+ 匹配一个或更多 (例如, \d+ 匹配一个或 多个数字字符)
[^/]+ 一个或多个不为‘/’的字符
* 零个或一个之前的表达式(例如:\d? 匹配零个或一个数字)
* 匹配0个或更多 (例如, \d* 匹配0个 或更多数字字符)
{1,3} 介于一个和三个(包含)之前的表达式(例如,\d{1,3}匹配一个或两个或三个数字)

有关正则表达式的更多内容,请访问http://www.djangoproject.com/r/python/re-module/

动态内容

接下来使视图返回动态内容,修改 mysite/views.py 内容如下:

from django.http import HttpResponse

from polls.models import Question

def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    output = ', '.join([p.question_text for p in latest_question_list])
    return HttpResponse(output)

# Leave the rest of the views (detail, results, vote) unchanged

这时候访问 http://127.0.0.1:8000/polls/ 可以看到输出内容为所有的问题通过逗号连接。

使用模板

接下来在视图中使用模板,在 settings.py 中有一个 TEMPLATE_LOADERS 属性,并且有一个默认值 django.template.loaders.app_directories.Loader,该值定义了从每一个安装的 app 的 templates 目录下寻找模板,故我们可以在 polls 目录下创建 templates 目录以及其子目录 polls。

现在创建一个首页页面 polls/templates/polls/index.html:

{% if latest_question_list %}
    <ul>
    {% for question in latest_question_list %}
        <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
    {% endfor %}
    </ul>
{% else %}
    <p>No polls are available.</p>
{% endif %}

注意: 页面中的 latest_question_list 变量来自视图返回的上下文,见下面 context 变量

然后更新 polls/views.py 视图,来使用模板:

from django.http import HttpResponse
from django.template import RequestContext, loader

from polls.models import Question

def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    template = loader.get_template('polls/index.html')
    context = RequestContext(request, {
        'latest_question_list': latest_question_list,
    })
    return HttpResponse(template.render(context))

代码说明:

  • 通过 loader 来加载模板页面,如前面提到的,这里是相对 polls/templates 目录
  • 创建上下文,将需要传递到页面的变量放入上下文变量 context
  • 使用 template 通过上下文来渲染页面

上面代码,可以使用 render() 来简化:

from django.shortcuts import render
from polls.models import Question

def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    context = {'latest_question_list': latest_question_list}
    return render(request, 'polls/index.html', context)

当查询数据返回错误时,可以抛出异常,让页面重定向到 404 页面:

from django.http import Http404
from django.shortcuts import render

from polls.models import Question
# ...
def detail(request, question_id):
    try:
        question = Question.objects.get(pk=question_id)
    except Question.DoesNotExist:
        raise Http404("Question does not exist")
    return render(request, 'polls/detail.html', {'question': question})

现在,我们可以回过头来修改 polls/index.html 页面中下面代码:

<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>

上面代码中的 url 为硬编码的,我们可以将其修改为:

<li><a href="{ % url  'detail' question.id  %}">{{ question.question_text }}</a></li>

为了避免多个视图的名称,例如 detail 视图,的冲突,我们可以给 URL 添加命名空间,修改 mysite/urls.py:

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

urlpatterns = patterns('',
    url(r'^polls/', include('polls.urls', namespace="polls")),
    url(r'^admin/', include(admin.site.urls)),
)

然后,修改 polls/templates/polls/index.html 为:

<li><a href="{ % url 'polls:detail' question.id % }">{{ question.question_text }}</a></li>

接下来创建明细页面 polls/templates/polls/detail.html:

<h1>{{ question.question_text }}</h1>

{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}

<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
    <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
    <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br />
{% endfor %}
<input type="submit" value="Vote" />
</form>

创建一个显示投票结果页面 polls/templates/polls/results.html :

<h1>{{ question.question_text }}</h1>

<ul>
{% for choice in question.choice_set.all %}
    <li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
{% endfor %}
</ul>

<a href="{% url 'polls:detail' question.id %}">Vote again?</a>

接下来修改 polls/views.py 添加 detail 、 vote 和 results 三个函数:

from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect, HttpResponse
from django.core.urlresolvers import reverse

from polls.models import Question,Choice

# ...
def detail(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, 'polls/detail.html', {'question': question})

def vote(request, question_id):
    p = get_object_or_404(Question, pk=question_id)
    try:
        selected_choice = p.choice_set.get(pk=request.POST['choice'])
    except (KeyError, Choice.DoesNotExist):
        # Redisplay the question voting form.
        return render(request, 'polls/detail.html', {
            'question': p,
            'error_message': "You didn't select a choice.",
        })
    else:
        selected_choice.votes += 1
        selected_choice.save()
        # Always return an HttpResponseRedirect after successfully dealing
        # with POST data. This prevents data from being posted twice if a
        # user hits the Back button.
        return HttpResponseRedirect(reverse('polls:results', args=(p.id,)))    

def results(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, 'polls/results.html', {'question': question})

重启服务进行测试,检查是否有错误。

简化代码

如果我们要针对很多模型编写视图,则有很多代码都是重复的,我们可以使用 Django 中的通用视图来简化代码。首先,我们将 polls/urls.py 改成如下:

from django.conf.urls import patterns, url

from polls import views

urlpatterns = patterns('',
    url(r'^$', views.IndexView.as_view(), name='index'),
    url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail'),
    url(r'^(?P<pk>\d+)/results/$', views.ResultsView.as_view(), name='results'),
    url(r'^(?P<question_id>\d+)/vote/$', views.vote, name='vote'),
)

然后,我们删除 polls/views.py 中的 index、detail 和 results 三个函数,vote 函数和之前保持一致,最后改为如下:

from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.views import generic

from polls.models import Choice, Question

class IndexView(generic.ListView):
    template_name = 'polls/index.html'
    context_object_name = 'latest_question_list'

    def get_queryset(self):
        """Return the last five published questions."""
        return Question.objects.order_by('-pub_date')[:5]

class DetailView(generic.DetailView):
    model = Question
    template_name = 'polls/detail.html'

class ResultsView(generic.DetailView):
    model = Question
    template_name = 'polls/results.html'

def vote(request, question_id):
    ... # same as above

代码说明:

  • 这里我们使用了两个通用视图 : ListView 和 DetailView,来和模型相关联。
  • DetailView 视图需要传递一个名称为 pk 表示模型主键的参数,所以我们需要把 URL 映射中的 question_id 改为 pk。
  • 默认情况下, DetailView使用 <app name>/<model name>_detail.html 模板,我们可以使用 template_name 变量重新定义模板路径;类似的, ListView 默认使用<app name>/<model name>_list.html 模板。
  • DetailView 视图中的上下文默认就包含了对模型的引用,如 question 变量;对于 ListView 视图,为 question_list 变量,如果我们想修改该变量名称,可以通过context_object_name 变量覆盖默认的名称,如使用 latest_question_list 代替 question_list。

更多的文档,请参考 generic views documentation

7. 总结

最后,来看项目目录结构:

mysite
├── db.sqlite3
├── manage.py
├── mysite
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   ├── wsgi.py
├── polls
│   ├── __init__.py
│   ├── admin.py
│   ├── migrations
│   │   ├── 0001_initial.py
│   │   ├── __init__.py
│   ├── models.py
│   ├── templates
│   │   └── polls
│   │       ├── detail.html
│   │       ├── index.html
│   │       └── results.html
│   ├── tests.py
│   ├── urls.py
│   ├── views.py
└── templates
    └── admin
        └── base_site.htm

通过上面的介绍,对 django 的安装、运行以及如何创建视图和模型有了一个清晰的认识,接下来就可以深入的学习 django 的自动化测试、持久化、中间件、国际化等知识。

时间: 2024-11-08 21:25:05

如何创建一个Django网站的相关文章

PS网页设计教程V——如何在Photoshop中创建一个商业网站布局

作为编码者,美工基础是偏弱的.我们可以参考一些成熟的网页PS教程,提高自身的设计能力.套用一句话,"熟读唐诗三百首,不会作诗也会吟". 本系列的教程来源于网上的PS教程,都是国外的,全英文的.本人尝试翻译这些优秀的教程.因为翻译能力有限,翻译的细节上还有待推敲,希望广大网友不吝赐教. 约定: 1.本文的软件是Photoshop CS5版本 2.原教程的截图是英文的,本人在重新制作的基础上,重新截了中文版的图 3.原文中有些操作没有给出参数.本人在反复测试的情况下测定了一些参数,以红色的

创建一个营销网站的5个有效步骤

中介交易 SEO诊断 淘宝客 云主机 技术大厅 建立一个营销型网站,是建立一体化网络营销自动化赚钱系统的基础;同时让你的网站被认为是"权威的",需要一定的时间积累. 但也有一些方法,如果正确实施的话,会帮助您节省很多的时间. 这5个步骤和方法与建立一个常规网站基本相同,但是一些关键思路是不同的. 现在,让我们来看看建立一个权威营销型网站的五个步骤和方法. 步骤1.网站创建和品牌塑造 如果你还没有决定将如何建立自己的网站,你需要选择一个网站生成器. WordPress是创建一个网站的简单

创建一个典型的企业网站项目

简介:这是一个真实的故事.故事中,我作为一个项目的负责人,因为初期过于迎合客户,而放弃了对一些基本原则的坚持,最终导致项目进行中被迫进行大改动.而改动过程中,通过引入敏捷开发而将损失降到了最低. 项目背景 2006年年初,一位客户联系我的公司,希望能够为其企业创建一个企业网站项目.根据客户的简单描述,这个项目本质上就是一个内容管理系统,并集成了论坛.FTP和电子邮件等功能,因此不算复杂.按照以往的经验估计,最多一个月就可以完成这个简单的项目. 需求分析 大体而言,该项目的主要功能包括新闻和文章发

使用MySQL数据库创建Windows Azure网站

不用担心,在此http://www.aliyun.com/zixun/aggregation/39815.html">博客文章中,我将详细介绍使用 Virtualenv 和适用于 Visual Studio 的Python 工具为您的应用程序创建 Python 环境的步骤.与此同时,我还将介绍如何将基于 Django 的站点发布到 Windows Azure 网站上. 使用 MySQL 数据库创建 Windows Azure 网站 现在,登录 Azure 管理门户,使用 Custom cr

《精通 ASP.NET MVC 4》----2.4 创建一个简单的数据录入应用程序

2.4 创建一个简单的数据录入应用程序 精通 ASP.NET MVC 4 本章的其余部分将通过建立一个简单的数据录入应用程序,来考察MVC的更多基本特性.本节将分步进行,目的是演示MVC的运转,因此会跳过对幕后工作原理的一些解释.不用担心--在后面的章节中还会重新深入地讨论这些论题. 2.4.1 设置场景 设想一个朋友要主办一个"新年除夕晚会",需要创建一个Web网站,以便让被邀请人进行RSVP(电子回复).这个网站需要以下四个关键特性: 一个显示此晚会信息的主页: 一个可以用来进行R

你有一个移动网站,是用户友好的?

如果上面的答案是否定的,那么你的企业可能会失去潜在客户来源,每隔一小时.随着移动通信的增长需要移动友好的网站是至关重要的. 如果您是第一次创建一个移动网站和不确定的整个概念移动和云营销不要惊慌.它是好的,新的移动网站是有点紧张,因为他们不一样的传统网站.它始终是最好,以保持自己更新有关移动网站的存在.小脑袋一键竞价软件小编分析怎样优化一个网站的手机.&http://www.aliyun.com/zixun/aggregation/37954.html">nbsp;方法1:简化的网站

编写第一个Django app,第二部分——创建模型和使用模型

创建模型 现在你的运行环境--"project"--已经建好了,现在准备让它开始工作了 . 你在Django中写的每一个应用程序都是由Python包组成,它们都在Python的 路径下,遵循一定的约定. Django自带有一个实用的工具,自动生成app的基本目录结构,因些,你可以 把更多的精力放在代码的编写上而不是创建目录上. Projects vs. apps(项目与应用程序) project和app之间有什么不同之处呢?一个app是实现某种功能的Web应用程 序--例如,一个网络博

编写第一个Django app,第一部分——创建项目

编写第一个Django app,第一部分--创建项目 让我们通过例子来学习. 通过这个指导教程,我们将一步步地教你创建一个简单的投票系统. 这个系统分为两部分: 1.一个公共的页面让人们投票和查看投票结果. 2.一个管理员页面让你添加,修改和删除投票. 我们假定你已经安装了Django.你可以运行Python编译器并输入import django来测试Django是否已经安装.如果命令运行成功,没有错误,说明Django 已经安装了. 新建项目 如果你是第一次使用Django,你必须确保一些初始

Web设计主题:教你创建一个古典风格的网站

如何进行古典风格的设计?主要针对酒店行业和联邦政府进行Web开发的Ryan Boudreaux针对该话题发表了文章<Web design themes: Create a vintage look and feel>.CSDN对该文进行了编译,内容如下: 你有被要求创建一个具有古典风格的商业网站吗?在我们的小城镇,有一些卖古典商品的小商家,你所在城市或许也有吧.古典在很多商业和组织中是一个很热门的主题.该类型的商业包括二手衣服商店.寄售商店.特色食品商店.工艺精品店.家具城.廉价市场.摄影店等