天天看点

Django快速开发Web 应用程序Django模型层(models)为你的网络应用提供数据的结构化处理和操作处理

Django模型层(models)为你的网络应用提供数据的结构化处理和操作处理

###Django最重要的内容:模型(Model)

Django模型类似于传统的数据库对象关系映射器,但它使用起来要比ORM简单快捷很多倍,能够节省大量的工作。

模型是你的数据的唯一的、权威的信息源。它包含你所储存数据的必要字段和行为。通常,每个模型对应数据库中唯一的一张表。

  • 每个模型都是django.db.models.Model 的一个Python 子类。
  • 模型的每个属性都表示为数据库中的一个字段。
  • Django 提供一套自动生成的用于数据库访问的API;

例如:在models.py中新建两个实体类:reporter、Artical,这两个类对应两个表,并且类的属性字段与表的字段一一对应。

from django.db import models

class Reporter(models.Model):
    full_name = models.CharField(max_length=70)

	#如果你用的是python3 用__str__即可,该方法是该类的实例化对象默认返回方法
    def __str__(self):              
        return self.full_name
    # 如果用的是python2,用__unicode__
    def __unicode__ (self):              
     return self.full_name

class Article(models.Model):
    pub_date = models.DateField()
    headline = models.CharField(max_length=200)
    content = models.TextField()
    reporter = models.ForeignKey(Reporter)

    def __str__(self):              # __unicode__ on Python 2
        return self.headline
           
  • 安装模块–生成数据库表

运行Django命令行工具来自动创建数据库表

$ python manage.py migrate        
           

使用模型的一些注意事项:

这个表的名称appName_Reporter,是根据模型中的元数据自动生成的,也可以重写为别的名称,。

id 字段是自动添加的,但这个行为可以被重写。详见自增主键字段。

这个例子中的CREATE TABLE SQL 语句使用PostgreSQL 语法格式,要注意的是Django 会根据设置文件 中指定的数据库类型来使用相应的SQL 语句。

  • 模型中大量方便的API

接着,你就可以使用一个便捷且功能丰富的Python API来访问你的数据。这些API是即时创建的,不需要代码生成:

# Import the models we created from our "news" app
>>> from news.models import Reporter, Article

# Python程序中直接使用改模型对象查询数据
>>> Reporter.objects.all()
[]

# 新建该类的对象到数据库
>>> r = Reporter(full_name='John Smith')
# Save the object into the database. You have to call save() explicitly.
>>> r.save()
# Now it has an ID.
>>> r.id   #查询新建reportor的ID(django自动生成的数据库主键id)
1

# 现在再查reportor这张表
>>> Reporter.objects.all()
[<Reporter: John Smith>]   #返回显示的信息是实体类中__str__方法的返回值。
>>> r.full_name
'John Smith'
# 查询id是1的reportor
>>> Reporter.objects.get(id=1)
<Reporter: John Smith>
#模糊查询
>>> Reporter.objects.get(full_name__startswith='John')
<Reporter: John Smith>
>>> Reporter.objects.get(full_name__contains='mith')
<Reporter: John Smith>
#查询不存在的id
>>> Reporter.objects.get(id=2)
Traceback (most recent call last):
    ...
DoesNotExist: Reporter matching query does not exist.
#报错对象找不到

           

生成动态的管理界面:它不只是一个脚手架 ,而是一所完整的房子

一旦你的模型定义完毕之后,Django能自动创建一个专业的、可以用于生产环境的 管理界面 – 可以让认证的用户添加、修改和删除对象的一个站点。只需简单地在admin site中注册你的模型即可:

#mysite/news/models.py

from django.db import models

class Article(models.Model):
    pub_date = models.DateField()
    headline = models.CharField(max_length=200)
    content = models.TextField()
    reporter = models.ForeignKey(Reporter)
mysite/news/admin.py
from django.contrib import admin

from . import models

admin.site.register(models.Article)
           

这里的原则是,你的网站是由工作人员或客户,或者也许只是你编辑 - 并且你不想仅仅为了管理内容而创建后端接口。

创建Django应用的一个典型工作流程是创建模型然后尽快地让admin sites启动和运行起来, 这样您的员工(或客户)能够开始录入数据。 然后,开发向公众展现数据的方式。

设计你的URLs

对于高质量的Web 应用来说,使用简洁、优雅的URL 模式是一个非常值得重视的细节。Django鼓励使用漂亮的URL设计且不会像.php或.asp一样把乱七八糟的东西放到URLs里面,.

为了给一个应用设计URLs,你需要创建一个叫做URLconf的Python模块。这其实是你应用的目录,它包含URL模式与Python回调函数间的一个简单映射。 URLconfs 还用作从Python代码中解耦URLs。

下面是针对上面Reporter/Article例子URLconf 可能的样子:

# mysite/news/urls.py
from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^articles/([0-9]{4})/$', views.year_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]
           

上面的代码将URLs映射作为简单的正则表达式映射到Python的回调函数(视图)。正则表达式通过圆括号来“捕获”URLs中的值。 当一个用户请求一个页面时,Django将按照顺序去匹配每一个模式,并停在第一个匹配请求的URL上。 (如果没有匹配到, Django将调用一个特殊的404视图。)整个过程是极快的,因为正则表达式在加载时就已经编译好了。

一旦有一个正则表达式匹配上了,Django 将导入和调用对应的视图,它其实就是一个简单的Python函数。 每个视图将得到一个request对象 —— 它包含了request 的metadata(元数据) —— 和正则表达式所捕获到的值。

例如,如果一个用户请求了URL “/articles/2005/05/39323/”,Django将调用函数news.views.article_detail(request, ‘2005’, ‘05’, ‘39323’)。

编写视图

每个视图只负责两件事中的一件:返回一个包含请求的页面内容的 HttpResponse对象, 或抛出一个异常如Http404。 剩下的就看你了。

通常,一个视图会根据参数来检索数据、加载一个模板然后使用检索出来的数据渲染模板。下面是上文year_archive的一个视图例子:

# mysite/news/views.py
from django.shortcuts import render

from .models import Article

def year_archive(request, year):
    a_list = Article.objects.filter(pub_date__year=year)
    context = {'year': year, 'article_list': a_list}
    return render(request, 'news/year_archive.html', context)
           

这个例子使用了Django的模板系统,它具有几个强大的功能,但是仍然努力做到了即使对于非编程人员也能保持足够的简单。

###设计模板

上面的代码加载news/year_archive.html模板。

Django有一个模板搜索路径,它允许您最大限度地减少模板之间的冗余。在你的Django设置中,你可以通过DIRS指定一个查找模板的目录列表。如果这个模板没有在第一个目录中,那么它会去查找第二个,以此类推。

让我们假设news/year_archive.html模板已经找到。它看起来可能是下面这个样子:

# mysite/news/templates/news/year_archive.html
{% extends "base.html" %}

{% block title %}Articles for {{ year }}{% endblock %}

{% block content %}
<h1>Articles for {{ year }}</h1>

{% for article in article_list %}
    <p>{{ article.headline }}</p>
    <p>By {{ article.reporter.full_name }}</p>
    <p>Published {{ article.pub_date|date:"F j, Y" }}</p>
{% endfor %}
{% endblock %}
           

变量使用两对大括号包围。 {{ article.headline }}表示“输出 article的headline属性”。但是点符号不仅用于属性查找。它们还用于字典的键值查找、索引查找和函数调用。

注意{{ article.pub_date|date:“F j, Y” }}使用Unix风格的“管道”(“|”字符)。这叫做模板过滤器,它是过滤变量值的一种方式。 在本例中,date过滤器格式化Python的datetime对象成给定的格式(正如在PHP中日期函数)。

你可以无限制地串联使用多个过滤器。 你可以编写自定义的目标过滤器。你可以编写自定义的模板标签,在幕后运行自定义的Python代码。

最后,Django使用“模板继承”的概念。这就是{% extends “base.html” %}所做的事。它表示“首先载入‘base’ 模板,该模板中定义了一系列block,然后使用接下来的(存在于继承模板)blocks填充这些blocks”。简而言之,模板继承让你大大减少模板间的冗余内容:每个模板只需要定义它独特的部分。

下面是“base.html”模板可能的样子,它使用了静态文件:

mysite/templates/base.html

{% load staticfiles %}
<html>
<head>
    <title>{% block title %}{% endblock %}</title>
</head>
<body>
    <img src="{% static "images/sitelogo.png" %}" alt="Logo" />
    {% block content %}{% endblock %}
</body>
</html>
           

简单地说,它定义网站的外观(使用网站的logo ),并提供“空洞”让子模板填充。这使站点的重构变得非常容易,只需改变一个文件 —— base模板。

它还可以让你利用不同的基础模板并重用子模板创建一个网站的多个版本。Django 的创建者已经利用这一技术来创造了显著不同的手机版本的网站 —— 只需创建一个新的基础模板。

请注意,如果你喜欢其它模板系统,你可以不使用Django的模板系统。 虽然Django的模板系统与Django的模型层集成得特别好,但并没有强制你使用它。同理,你也可以不使用Django的数据库API。 你可以使用任何你想要的方法去操作数据,包括其它数据库抽象层,读取 XML 文件或者直接从磁盘中读取文件。Django的每个组成部分 —— 模型、视图和模板都可以解耦。

PS:以上内容取自python官方文档,后期会结合实际使用情况加以补充。