【Django】Web应用开发经由

【Django开发经由】

  本来以为看完网上的入门教程之后就可以看书详细学习一下,没想到手头上的这本书也讲得不是太详细。。无奈,不过好在这本书从无到有建立一个网站的流程还算可以,就以这个角度简单记录一下,顺便也对之前发现但是还没来得及记录的一些东西进行一些总结。

■  建立项目

  首先是建立项目,我没用django-admin的命令行,而是直接用了Pycharm的建立新项目。建立完成之后就有了项目结构,关于自动创建的几个文件分别是哪些作用。可以特别提一下的是urls.py文件在理想情况下应该是到各个模块的路由(也就是说除了默认的^admin/之外尽量不直接路由到一个界面而是一个Django下的App,让App进一步规定url到响应函数的映射)。另外wsgi.py这个文件一般不用动。

  因为djangosite/urls.py中的路由只是路由到模块这一层,所以我们肯定要startapp几个App来充实内容。比如我们创建一个test。此时会提示创建失败,因为在创建App目录的时候里面有一个test.py的文件,如果App也叫test的话就会引起模块名的混乱了。所有App名字就改成mytest吧。

■  基础路由与视图设置

  基础的路由设置就不多说了,这里讲一下之前没有提到过的几个路由设置的技巧:

  ●  多层URI的路由

  之前说到过的所有路由设置全部都是基于一个不变的如url(r'^test/'),但是作为一个正则表达式很明显有更加灵活的用法。比如下面这样的用法:

###djangosite/urls.py###
urlpatterns = [
  url(r'^test/', include('mytest.urls')),  #新增这行
]

###mytest/urls.py###
from django.conf.urls import url
import views

urlpatterns = [
    url(r'^add/(d+)/(d+)/', views.add)
]

###mytest/views.py###
from django.http import HttpResponse
def add(request,a,b):
    a = int(a)
    b = int(b)
    return HttpResponse('<p>%s</p>' % (a + b) )

  如此,在访问如test/add/3/4的时候就可以看到返回的是7了。其要点在于,把路由表示的正则表达式中的子模式自动提取出来并作为参数传递给响应函数。需要注意参数个数应该和子模式个数一致。

  ●  静态文件

  一个网站的javascript,css,图片等这些内容一般都作为静态文件放在服务器上。

  相比于flask默认把项目根目录的一个static子目录作为静态文件的存放位置,并且把URI/static/直接和其相关起来相比,Django在默认情况下是没有配置静态文件的目录的。如果需要在项目根目录中像flask一样有个静态文件存放的地方的话那么可以这么干:

  首先当然是在根目录下面创建static文件夹,里面可以放上一些文件。

###djangosite/settings.py###
STATIC_URL = '/static/'    #这条是默认有的,但是光有这条是不行的
STATICFILES_DIRS = (BASE_DIR,'static')    #新加,注意没有os.path.join

  设置完静态文件的存放之后还可以通过如下的方式进行和前端的互动,也就是说前端可以直接引用一些静态文件,这正是我们的目的:

{% load staticfiles %}
<script type="text/javascript" src="{% static 'path/to/file' %}">

■  关联数据库

  之前的文章中提到过关联数据库的几个步骤。首先是修改settings.py中的DATABASES配置项,然后在相关的App下的models.py文件,修改之创建模型。看到书上之后知道了,python manage.py makemigrations的时候可以在后面加上一个App名,表示只固化这个App相关的模型的变动。

  但是直接python manage.py mytest的话会报错说没有安装APP,确实我们还需要到settings.py里面去设置一下INSTALLED_APPS这个配置。之前在文章中说的是直接以App的名字去INSTALL,不过这里介绍一种看起来更加时髦的办法,在每个新建的APP下面会自动有一个apps.py的文件,里面默认生成了一个XxxxConfig的类,继承自django.apps.AppConfig类。可以把这个类给写到INSTALLED_APPS里面去,目前来看效果是一样的。这是因为这个AppConfig类中有类似name,module,path,label等和一个App(老打App好麻烦,之后我们都称App为模块好了)相关的信息。所以直接在INSTALLED_APPS里面写模块名和写这个类效果一样,我怀疑即使是写模块名可能也是根据这个模块名来找这个类然后加载。

  然后就是熟悉的python manage.py makemigrations mytest,然后再python manage.py migrate。这里还注意到了一点,在第一次初始化数据库时,进行makemigrations之后,数据库中首先生成了一张django_migrations的表,然后migrate之后才有了其他乱七八糟的那些表的。

■  表单视图

  下面明确一下如何方便地把一个数据库模型类变成一个表单类:

###mytest/models.py###
from django.db import models

class Moment(models.Model):
    content = models.Charfield(max_length=200)
    user_name = models.Charfield(max_length=20)
    kind = models.Charfield(max_length=20)
    def __unicode__(self):
        return self.user_name,self.content

###mytest/views.py###
from django.forms import ModelForm
from mytest.models import Moment

class MomentForm(Form):
    class Meta:    #采用了子类的方式进行类的转换
        model = Moment
        fields = '__all__'    #__all__是指把模型类中的所有字段都导入表单类中

  fields也可以写类似('content','user_name','kind')这样的。

  ●  更高级一点的模型类

  插入在这里有些唐突,不过我们可以这样改造一下models.py中的类以使表结构(不涉及表之间的结构)更加复杂。

KIND_CHOICES = (
    ('Python技术','Python技术'),
    ('数据库技术','数据库技术'),
    ('经济学','经济学'),
    ('文体咨询','文体咨询'),
    ('个人心情','个人心情'),
    ('其他','其他')
)

class Moment(models.Model):
    content = models.Charfield(max_length=200)
    user_name = models.Charfield(max_length=20,default='无名氏')
    kind = models.Charfield(max_length=20,choices=KIND_CHOICES,default=KIND_CHOICES[0])

  这个类的kind字段已经有了一些合法的值的选项,实际上这个kind字段在表单中就会成为一个SelectField了,虽然在数据库中还是varchar类型的。

  然后就是编写模板:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>消息录入页面</title>
</head>
<body>
    <form action="?" method="post">
        <fieldset>
            <legend>请输入并提交</legend>
                {{ form.as_p }}
                <input type="submit" value="submit" />
        </fieldset>
    </form>
</body>
</html>

  再编写views中的响应函数:

from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
from django.shortcuts import render
from mytest.forms import MomentForm

def moments_input(request):
    if request.method == 'POST':
        form = MomentForm(request.POST)
        if form.is_valid():
            moment = form.save()
            moment.save()
            return HttpResponseRedirect(reverse('static_test_name'))
    else:
        form = MomentForm()

    return render(request,'moments_input.html',{'form':form})

  这段代码又有点新鲜的东西,HttpResponseRedirect顾名思义和django.shortcuts.redirect是差不多的,起到一个重定向的作用。reverse函数就像flask里的url_for,可以把一个endpoint形式的响应函数转化成相应的url,和url_for一样reverse也有一个args参数(或kwargs参数),可以给生成出来的GET请求的url自动加上参数。

  嗯。。书上的是endpoint形式的,可是我自己试了下发现并不行只有像上面代码写得那样才能成功得到url并进行重定向。那么static_test_name是什么?其实是在mytest/urls.py中设置url路由的时候,原先是url(r'^statictest',views.static_test)改成了url(r'^statictest',views.static_test,name='static_test_name')。只有设置了name参数,然后在reverse中参数写成这个name才可以顺利得到url。

  save什么的就是存进数据库,其实据我估计这边两个save是多余的,只要form.save()即可。我把下面的注释掉也能把数据顺利存进数据库。

  嗯。。管理界面上篇文章讲的挺详细了,就不多说了。

原文地址:https://www.cnblogs.com/franknihao/p/7773361.html