Django教程:http://www.liujiangblog.com/course/django/2 第一个Django应用 该应用包括以下两个部分: 一个可以让公众用户进行投票和查看投票结果的站点 一个让可以进行增删改查的后台admin管理界面 Part 1:请求与响应 一、 新建项目 进入你指定的项目保存目录,然后运行下面的命令:$ django-admin startproject mysite 二、 启动开发服务器 进入mystie项目的根目录,输入下面的命令:$ python manage.py runserver 注意: Django的开发服务器具有自动重载功能,当你的代码有修改,每隔一段时间服务器将自动更新。 三、 创建投票应用(app) 进入mysite项目根目录,确保与manage.py文件处于同一级,输入下述命令:$ python manage.py startapp polls 四、编写第一个视图 在polls/views.py文件中,编写代码: from django.http import HttpResponse def index(request): return HttpResponse("Hello, world. You're at the polls index.") 现在,在polls目录中新建一个文件,名字为urls.py,在其中输入代码如下: from django.conf.urls import url from . import views urlpatterns = [ url(r'^$', views.index, name='index'), ] 打开mysite/urls.py文件,代码如下: from django.conf.urls import include, url from django.contrib import admin urlpatterns = [ url(r'^polls/', include('polls.urls')), url(r'^admin/', admin.site.urls), ] 好了,路由设置成功后,启动服务器,然后在浏览器中访问地址http://localhost:8000/polls/。 Part 2:模型与管理后台 一、数据库安装 $ python manage.py migrate 二、创建模型 # polls/models.py from django.db import models class Question(models.Model): question_text = models.CharField(max_length=200) pub_date = models.DateTimeField('date published') class Choice(models.Model): question = models.ForeignKey(Question, on_delete=models.CASCADE) choice_text = models.CharField(max_length=200) votes = models.IntegerField(default=0) 三、启用模型 上面的代码看着有点少,其实包含了大量的信息,据此,Django会做下面两件事: 创建该app对应的数据库表结构 为Question和Choice对象创建基于Python的数据库访问API 要将应用添加到项目中,需要在INSTALLED_APPS设置中增加指向该应用的配置文件的链接。 我们需要再运行下一个命令:$ python manage.py makemigrations polls 有一个叫做sqlmigrate的命令可以展示SQL语句,例如:$ python manage.py sqlmigrate polls 0001 如果你感兴趣,也可以运行python manage.py check命令,它将检查项目中的错误,并不实际进行迁移或者链接数据库的操作。 四、使用模型的API 要进入Python的shell,请输入命令:$ python manage.py shell 当你进入shell后,尝试一下下面的API吧: >>> from polls.models import Question, Choice # 导入我们写的模型类 # 现在系统内还没有questions对象 >>> Question.objects.all() <QuerySet []> # 创建一个新的question对象 # Django推荐使用timezone.now()代替python内置的datetime.datetime.now() # 这个timezone就来自于Django唯一的依赖库pytz from django.utils import timezone >>> q = Question(question_text="What's new?", pub_date=timezone.now()) # 你必须显式的调用save()方法,才能将对象保存到数据库内 >>> q.save() # 默认情况,你会自动获得一个自增的名为id的主键 >>> q.id 1 # 通过python的属性调用方式,访问模型字段的值 >>> q.question_text "What's new?" >>> q.pub_date datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>) # 通过修改属性来修改字段的值,然后显式的调用save方法进行保存。 >>> q.question_text = "What's up?" >>> q.save() # objects.all() 用于查询数据库内的所有questions >>> Question.objects.all() <QuerySet [<Question: Question object>]> 返回polls/models.py文件,修改一下question和Choice这两个类,代码如下: from django.db import models from django.utils.encoding import python_2_unicode_compatible class Question(models.Model): # ... def __str__(self): return self.question_text class Choice(models.Model): # ... def __str__(self): return self.choice_text 另外,这里我们自定义一个模型的方法,用于判断问卷是否最近时间段内发布度的: import datetime from django.db import models from django.utils import timezone class Question(models.Model): # ... def was_published_recently(self): return self.pub_date >= timezone.now() - datetime.timedelta(days=1) 保存修改后,我们重新启动一个新的python shell,再来看看其他的API: >>> from polls.models import Question, Choice # 先看看__str__()的效果,直观多了吧? >>> Question.objects.all() <QuerySet [<Question: What's up?>]> # Django提供了大量的关键字参数查询API >>> Question.objects.filter(id=1) <QuerySet [<Question: What's up?>]> >>> Question.objects.filter(question_text__startswith='What') <QuerySet [<Question: What's up?>]> # 获取今年发布的问卷 >>> from django.utils import timezone >>> current_year = timezone.now().year >>> Question.objects.get(pub_date__year=current_year) <Question: What's up?> # 查询一个不存在的ID,会弹出异常 >>> Question.objects.get(id=2) Traceback (most recent call last): ... DoesNotExist: Question matching query does not exist. # Django为主键查询提供了一个缩写:pk。下面的语句和Question.objects.get(id=1)效果一样. >>> Question.objects.get(pk=1) <Question: What's up?> # 看看我们自定义的方法用起来怎么样 >>> q = Question.objects.get(pk=1) >>> q.was_published_recently() True # 让我们试试主键查询 >>> q = Question.objects.get(pk=1) # 显示所有与q对象有关系的choice集合,目前是空的,还没有任何关联对象。 >>> q.choice_set.all() <QuerySet []> # 创建3个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对象可通过API访问和他们关联的Question对象 >>> c.question <Question: What's up?> # 同样的,Question对象也可通过API访问关联的Choice对象 >>> q.choice_set.all() <QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]> >>> q.choice_set.count() 3 # API会自动进行连表操作,通过双下划线分割关系对象。连表操作可以无限多级,一层一层的连接。 # 下面是查询所有的Choices,它所对应的Question的发布日期是今年。(重用了上面的current_year结果) >>> Choice.objects.filter(question__pub_date__year=current_year) <QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]> # 使用delete方法删除对象 >>> c = q.choice_set.filter(choice_text__startswith='Just hacking') >>> c.delete() 五、admin后台管理站点 首先,我们需要通过下面的命令,创建一个可以登录admin站点的用户:$ python manage.py createsuperuser 输入用户名:Username: admin 输入邮箱地址:Email address: [email protected] 输入密码: Password: larken0627 Password (again): larken0627 Superuser created successfully. 2. 启动开发服务器 服务器启动后,在浏览器访问http://127.0.0.1:8000/admin/。你就能看到admin的登陆界面了: 3. 进入admin站点 当前只有两个可编辑的内容:groups和users。它们是django.contrib.auth模块提供的身份认证框架。 4. 在admin中注册投票应用 现在还无法看到投票应用,必须先在admin中进行注册,告诉admin站点,请将polls的模型加入站点内,接受站点的管理。 打开polls/admin.py文件,加入下面的内容: from django.contrib import admin from .models import Question admin.site.register(Question) 4. admin站点的主要功能 注册question模型后,刷新admin页面就能看到Question栏目了。 Part 3:视图和模板 一、概述 二、编写视图 下面,打开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文件中加入下面的url模式,将其映射到我们上面新增的视图。 from django.conf.urls import url from . import views urlpatterns = [ url(r'^$', views.index, name='index'), url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'), url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'), url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'), ] 三、编写能实际干点活的视图 下面是一个新的index()视图,用于替代先前无用的index,它会根据发布日期显示最近的5个投票问卷。 from django.http import HttpResponse from .models import Question def index(request): latest_question_list = Question.objects.order_by('-pub_date')[:5] output = ', '.join([q.question_text for q in latest_question_list]) return HttpResponse(output) 现在,将下列代码写入文件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 %} 同时,修改视图文件polls/views.py,让新的index.html文件生效: from django.http import HttpResponse from django.template import loader from .models import Question def index(request): latest_question_list = Question.objects.order_by('-pub_date')[:5] template = loader.get_template('polls/index.html') context = { 'latest_question_list': latest_question_list, } return HttpResponse(template.render(context, request)) 快捷方式:render() 在实际运用中,加载模板、传递参数,返回HttpResponse对象是一整套再常用不过的操作了,为了节省力气,Django提供了一个快捷方式:render函数,一步到位!看如下代码: polls/views.py from django.shortcuts import render from .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) render()函数的第一个位置参数是请求对象(就是view函数的第一个参数),第二个位置参数是模板。还可以有一个可选的第三参数,一个字典,包含需要传递给模板的数据。最后render函数返回一个经过字典数据渲染过的模板封装而成的HttpResponse对象。 四、返回404错误 现在让我们来编写返回具体问卷文本内容的视图polls/views.py: from django.http import Http404 from django.shortcuts import render from .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}) 快捷方式:get_object_or_404() 就像render函数一样,Django同样为你提供了一个偷懒的方式,替代上面的多行代码,那就是get_object_or_404()方法,参考下面的代码:polls/views.py from django.shortcuts import get_object_or_404, render from .models import Question # ... def detail(request, question_id): question = get_object_or_404(Question, pk=question_id) return render(request, 'polls/detail.html', {'question': question}) 五、 使用模板系统 detail()视图会将上下文变量question传递给对应的polls/templates/polls/detail.html模板,修改该模板的内容,如下所示: <h1>{{ question.question_text }}</h1> <ul> {% for choice in question.choice_set.all %} <li>{{ choice.choice_text }}</li> {% endfor %} </ul> 六、删除模板中硬编码的URLs 七、URL names的命名空间 Part 4:表单和类视图 一、表单form 为了接收用户的投票选择,我们需要在前端页面显示一个投票界面。让我们重写先前的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> 现在,让我们创建一个处理提交过来的数据的视图。前面我们已经写了一个“占坑”的vote视图的url(polls/urls.py): url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'), 以及“占坑”的vote视图函数(polls/views.py),我们把坑填起来: from django.shortcuts import get_object_or_404, render from django.http import HttpResponseRedirect, HttpResponse from django.urls import reverse from .models import Choice, Question # ... def vote(request, question_id): question = get_object_or_404(Question, pk=question_id) try: selected_choice = question.choice_set.get(pk=request.POST['choice']) except (KeyError, Choice.DoesNotExist): # 发生choice未找到异常时,重新返回表单页面,并给出提示信息 return render(request, 'polls/detail.html', { 'question': question, 'error_message': "You didn't select a choice.", }) else: selected_choice.votes += 1 selected_choice.save() # 成功处理数据后,自动跳转到结果页面,防止用户连续多次提交。 return HttpResponseRedirect(reverse('polls:results', args=(question.id,))) 当有人对某个问题投票后,vote()视图重定向到了问卷的结果显示页面。下面我们来写这个处理结果页面的视图(polls/views.py): from django.shortcuts import get_object_or_404, render def results(request, question_id): question = get_object_or_404(Question, pk=question_id) return render(request, 'polls/results.html', {'question': question}) 同样,还需要写个模板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> 如果你在前面漏掉了一部分操作没做,比如没有创建choice选项对象,那么可以按下面的操作,补充一下: F:\Django_course\mysite>python manage.py shell Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) >>> from polls.models import Question >>> q = Question.objects.get(pk=1) >>> q.choice_set.create(choice_text='Not much', votes=0) <Choice: Choice object> >>> q.choice_set.create(choice_text='The sky', votes=0) <Choice: Choice object> >>> q.choice_set.create(choice_text='Just hacking again', votes=0) <Choice: Choice object> 二、 使用类视图:减少重复代码 1.改良URLconf 打开polls/urls.py文件,将其修改成下面的样子: from django.conf.urls import url from . import views app_name = 'polls' urlpatterns = [ url(r'^$', views.IndexView.as_view(), name='index'), url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='detail'), url(r'^(?P<pk>[0-9]+)/results/$', views.ResultsView.as_view(), name='results'), url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'), ] 2.修改视图 接下来,打开polls/views.py文件,删掉index、detail和results视图,替换成Django的类视图,如下所示: from django.shortcuts import get_object_or_404, render from django.http import HttpResponseRedirect from django.urls import reverse from django.views import generic from .models import Choice, Question class IndexView(generic.ListView): template_name = 'polls/index.html' context_object_name = 'latest_question_list' def get_queryset(self): """返回最近发布的5个问卷.""" 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): ... # 这个视图未改变!!! Part 5:测试 Part 6:静态文件 一、使用静态文件 首先在你的polls目录中创建一个static目录。Django将在那里查找静态文件,这与Django在polls/templates/中寻找对应的模板文件的方式是一致的。 将下面的代码写入样式文件polls/static/polls/style.css: li a { color: green; } 接下来在模板文件polls/templates/polls/index.html的头部加入下面的代码: {% load static %} <link rel="stylesheet" type="text/css" href="{% static 'polls/style.css' %}" /> 二、添加背景图片 下面,我们在polls/static/polls/目录下创建一个用于存放图片的images子目录,在这个子目录里放入`background.gif文件。换句话说,这个文件的路径是polls/static/polls/images/background.gif。 在css样式文件polls/static/polls/style.css中添加下面的代码: body { background: white url("images/background.gif") no-repeat right bottom; } 三、直接访问静态文件 实际上不管是在Django开发服务器上,还是在nginx+uwsgi+django部署的服务器上,都可以直接通过url访问静态文件,不需要在Django中专门为每个静态文件编写url路由和视图。 Part 7:自定义admin站点 一、定制模型表单 下面是一个修改admin表单默认排序方式的例子。修改polls/admin.py的代码:: from django.contrib import admin from .models import Question class QuestionAdmin(admin.ModelAdmin): fields = ['pub_date', 'question_text'] admin.site.register(Question, QuestionAdmin) 还有,当表单含有大量字段的时候,你也许想将表单划分为一些字段的集合。再次修改polls/admin.py: from django.contrib import admin from .models import Question class QuestionAdmin(admin.ModelAdmin): fieldsets = [ (None, {'fields': ['question_text']}), ('Date information', {'fields': ['pub_date']}), ] admin.site.register(Question, QuestionAdmin) 二、添加关联对象 三、定制实例列表页面 四、定制admin整体界面 很明显,在每一个项目的admin页面顶端都显示Django administration是很可笑的,它仅仅是个占位文本。利用Django的模板系统,我们可以快速修改它。 1.定制项目模板 在manage.py文件同级下创建一个templates目录。然后,打开设置文件mysite/settings.py,在TEMPLATES条目中添加一个DIRS选项: 五、定制admin首页 六、源码对照
第一个Django应用
猜你喜欢
转载自www.cnblogs.com/larken/p/9627040.html
今日推荐
周排行