zoukankan      html  css  js  c++  java
  • django_book学习笔记4模型

    本质上,每个产品页面都是数据库中数据以 HTML格式进行的展现
    Django数据库层。
    一、MTV开发模式
    Django数据驱动Web应用的总体设计。
    把数据存取逻辑、业务逻辑和表现逻辑组合在一起的概念有时被称为软件架构的 Model-View-Controller (MVC)模式。
    在这个模式中, Model 代表数据存取层,View 代表的是系统中选择显示什么和怎么显示的部分,Controller 指的是系统中根据用户输入并视需要访问模型,以决定使用哪个视图的那部分。

    Django 紧紧地遵循这种MVC模式,可以称得上是一种MVC框架。 以下是Django中M、V 和 C 各自的含义:
    M ,数据存取部分,由django数据库层处理。
    V ,选择显示哪些数据要显示以及怎样显示的部分,由视图和模板处理。
    C ,根据用户输入委派视图的部分,由Django框架根据 URLconf 设置,对给定URL调用适当的 Python 函数。
    由于C由框架自行处理,而Django里更关注的是模型(Model)、模板(Template)和视图(Views),Django 也被称为 MTV 框架 。在 MTV 开发模式中:
    M 代表模型(Model),即数据存取层。 该层处理与数据相关的所有事务: 如何存取、如何验证有效性、包含哪些行为以及数据之间的关系等。
    T 代表模板(Template),即表现层。 该层处理与表现相关的决定: 如何在页面或其他类型文档中进行显示。
    V 代表视图(View),即业务逻辑层。 该层包含存取模型及调取恰当模板的相关逻辑。 你可以把它看作模型与模板之间的桥梁。

    二、数据库配置
    django1.4
    1、设置
    # vim mysite/mysite/settings.py
    DATABASES = {
    'default': {
    'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
    'NAME': 'django', # Or path to database file if using sqlite3.
    'USER': 'jin', # Not used with sqlite3.
    'PASSWORD': '123.com', # Not used with sqlite3.
    'HOST': 'localhost', # Set to empty string for localhost. Not used with sqlite3.
    'PORT': '', # Set to empty string for default. Not used with sqlite3.
    }
    }
    如果使用 SQLite,请对数据库文件指定完整的文件系统路径。 例如:
    DATABASE_NAME = '/home/django/mydata.db'
    输入下面这些命令来测试你的数据库配置:
    2、测试配置
    [root@pxe-svr mysite]# ./manage.py shell
    >>> from django.db import connection
    >>> cursor = connection.cursor()

    三、创建应用程序并激活
    1、要使用Django的数据库层(模型),必须创建一个Django app
    project 和 app 之间到底有什么不同呢?它们的区别就是一个是配置另一个是代码.
    一个project包含很多个Django app以及对它们的配置。
    技术上,project的作用是提供配置文件,比方说哪里定义数据库连接信息, 安装的app列表, TEMPLATE_DIRS ,等等。
    一个app是一套Django功能的集合,通常包括模型和视图。
    Django本身内建有一些app,例如注释系统和自动管理界面。 app的一个关键点是它们是很容易移植到其他project和被多个project复用。

    可以不用创建app,这一点应经被我们之前编写的视图函数的例子证明了。 在那些例子中,我们只是简单的创建了一个称为views.py的文件,编写了一些函数并在URLconf中设置了各个函数的映射。
    这些情况都不需要使用apps。但是,系统对app有一个约定: 如果你使用了Django的数据库层(模型),你必须创建一个Django app。
    模型必须存放在apps中。 因此,为了开始建造我们的模型,我们必须创建一个新的app。

    2、创建app
    ./manage.py startapp books
    #这样创建貌似在创建url的时候不能工作,因为django1.4版本
    [root@pxe-svr mysite]# tree
    .
    ├── books
    │?? ├── __init__.py
    │?? ├── models.py
    │?? ├── tests.py
    │?? └── views.py
    ├── manage.py
    └── mysite
    ├── __init__.py
    ├── __init__.pyc
    ├── settings.py
    ├── settings.py~
    ├── settings.pyc
    ├── urls.py
    └── wsgi.py
    3、激活app
    [root@pxe-svr mysite]# vim mysite/settings.py
    INSTALLED_APPS = (
    # 'django.contrib.auth',
    # 'django.contrib.contenttypes',
    # 'django.contrib.sessions',
    # 'django.contrib.sites',
    'mysite.books',
    )
    如果web在运行,包下面错误就挂了
    [root@pxe-svr mysite]# Error: No module named books
    #1.4版本需要替换为books或者创建app时到mysite/mysite下面创建
    #先使用books

    四、开始创建模型
    1、第一个模型
    [root@pxe-svr mysite]# vim books/models.py
    class Publisher(models.Model):
    name = models.CharField(max_length=30)
    address = models.CharField(max_length=50)
    city = models.CharField(max_length=60)
    state_province = models.CharField(max_length=30)
    country = models.CharField(max_length=50)
    website = models.URLField()

    class Author(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=40)
    email = models.EmailField()

    class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField(Author)
    publisher = models.ForeignKey(Publisher)
    publication_date = models.DateField()

    每个模型(class)相当于单个数据库表,每个属性也是这个表中的一个字段。 属性名就是字段名,它的类型(例如 CharField )相当于数据库的字段类型 (例如 varchar )。
    例如, Publisher模块(class)等同于下面这张表(用PostgreSQL的 CREATE TABLE 语法描述):
    CREATE TABLE "books_publisher" (
    "id" serial NOT NULL PRIMARY KEY,
    "name" varchar(30) NOT NULL,
    "address" varchar(50) NOT NULL,
    "city" varchar(60) NOT NULL,
    "state_province" varchar(30) NOT NULL,
    "country" varchar(50) NOT NULL,
    "website" varchar(200) NOT NULL
    );

    2、测试模型
    1)check
    validate 命令检查你的模型的语法和逻辑是否正确。
    如果一切正常,你会看到 0 errors found 消息。如果出错,请检查你输入的模型代码。 错误输出会给出非常有用的错误信息来帮助你修正你的模型
    [root@pxe-svr mysite]# ./manage.py validate
    0 errors found
    2)模型确认没问题了,运行下面的命令来生成 CREATE TABLE 语句
    sqlall 命令并没有在数据库中真正创建数据表,只是把SQL语句段打印出来,这样你可以看到Django究竟会做些什么
    [root@pxe-svr mysite]# ./manage.py sqlall books
    BEGIN;
    CREATE TABLE `books_publisher` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `name` varchar(30) NOT NULL,
    `address` varchar(50) NOT NULL,
    `city` varchar(60) NOT NULL,
    `state_province` varchar(30) NOT NULL,
    `country` varchar(50) NOT NULL,
    `website` varchar(200) NOT NULL
    )
    ;
    CREATE TABLE `books_author` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `first_name` varchar(30) NOT NULL,
    `last_name` varchar(40) NOT NULL,
    `email` varchar(75) NOT NULL
    )
    ;
    CREATE TABLE `books_book_authors` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `book_id` integer NOT NULL,
    `author_id` integer NOT NULL,
    UNIQUE (`book_id`, `author_id`)
    )
    ;
    ALTER TABLE `books_book_authors` ADD CONSTRAINT `author_id_refs_id_9e7e386` FOREIGN KEY (`author_id`) REFERENCES `books_author` (`id`);
    CREATE TABLE `books_book` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `title` varchar(100) NOT NULL,
    `publisher_id` integer NOT NULL,
    `publication_date` date NOT NULL
    )
    ;
    ALTER TABLE `books_book` ADD CONSTRAINT `publisher_id_refs_id_3a4d8b45` FOREIGN KEY (`publisher_id`) REFERENCES `books_publisher` (`id`);
    ALTER TABLE `books_book_authors` ADD CONSTRAINT `book_id_refs_id_30430d9e` FOREIGN KEY (`book_id`) REFERENCES `books_book` (`id`);
    CREATE INDEX `books_book_22dd9c39` ON `books_book` (`publisher_id`);
    COMMIT;
    自动生成的表名是app名称( books )和模型的小写名称 ( publisher , book , author )的组合
    3、创建表-提交SQL语句至数据库
    [root@pxe-svr mysite]# ./manage.py syncdb
    Creating tables ...
    Creating table auth_permission
    Creating table auth_group_permissions
    Creating table auth_group
    Creating table auth_user_user_permissions
    Creating table auth_user_groups
    Creating table auth_user
    Creating table django_content_type
    Creating table django_session
    Creating table django_site
    Creating table books_publisher
    Creating table books_author
    Creating table books_book_authors
    Creating table books_book

    You just installed Django's auth system, which means you don't have any superusers defined.
    Would you like to create one now? (yes/no):
    这里要设置一个管理员账号
    Password:
    Password (again):
    Superuser created successfully.
    Installing custom SQL ...
    Installing indexes ...
    Installed 0 object(s) from 0 fixture(s)

    五、数据库访问
    1、基本数据访问
    [root@pxe-svr mysite]# ./manage.py shell
    >>> from books.models import Publisher
    #导入Publisher模型类
    >>> p1 = Publisher(name='Apress', address='2855 Telegraph Avenue', city='Berkeley', state_province='CA', country='U.S.A.',website='http://www.apress.com/')
    #创建Publisher类的实例p1
    >>> p1.save()
    #调用实例p1的save()方法将数据存入数据库,Django 会在后台执行一条 INSERT 语句。
    如果需要一步完成对象的创建与存储至数据库,就使用`` objects.create()`` 方法.
    >>> p1 = Publisher.objects.create(name='Apress', address='2855 Telegraph Avenue', city='Berkeley', state_province='CA', country='U.S.A.',website='http://www.apress.com/')
    获取
    >>> publisher_list = Publisher.objects.all()
    >>> publisher_list
    [<Publisher: Publisher object>]
    2、添加模块的字符串表现
    当我们打印整个publisher列表时,我们没有得到想要的有用信息,无法把````对象区分开来:
    [root@pxe-svr mysite]# vim books/models.py
    from django.db import models

    # Create your models here.
    class Publisher(models.Model):
    name = models.CharField(max_length=30)
    address = models.CharField(max_length=50)
    city = models.CharField(max_length=60)
    state_province = models.CharField(max_length=30)
    country = models.CharField(max_length=50)
    website = models.URLField()

    def __unicode__(self):
    return self.name


    class Author(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=40)
    email = models.EmailField()

    def __unicode__(self):
    return u'%s %s' % (self.first_name, self.last_name)

    class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField(Author)
    publisher = models.ForeignKey(Publisher)
    publication_date = models.DateField()

    def __unicode__(self):
    return self.title
    __unicode__() 方法可以进行任何处理来返回对一个对象的字符串表示。 Publisher和Book对象的__unicode__()方法简单地返回各自的名称和标题,
    Author对象的__unicode__()方法则稍微复杂一些,它将first_name和last_name字段值以空格连接后再返回。
    对__unicode__()的唯一要求就是它要返回一个unicode对象 如果`` __unicode__()`` 方法未返回一个Unicode对象,而返回比如说一个整型数字,
    那么Python将抛出一个`` TypeError`` 错误,并提示:”coercing to Unicode: need string or buffer, int found” 。
    unicode对象就是一个Python字符串.
    Unicode对象并没有编码。它们使用Unicode,一个一致的,通用的字符编码集。 当你在Python中处理Unicode对象的时候,你可以直接将它们混合使用和互相匹配而不必去考虑编码细节。
    Django 在其内部的各个方面都使用到了 Unicode 对象。 模型 对象中,检索匹配方面的操作使用的是 Unicode 对象,视图 函数之间的交互使用的是 Unicode 对象,
    模板的渲染也是用的 Unicode 对象。通常,我们不必担心编码是否正确,后台会处理的很好。
    为了让我们的修改生效,先退出Python Shell,然后再次运行 python manage.py shell 进入。(这是保证代码修改生效的最简单方法。)
    >>> publisher_list = Publisher.objects.all()
    >>> publisher_list
    [<Publisher: Apress>

    3、插入和更新数据
    1)插入
    >>> from books.models import Publisher
    >>> p = Publisher(name='Apress', address='2855 Telegraph Avenue', city='Berkeley', state_province='CA', country='U.S.A.',website='http://www.apress.com/')
    >>> p.save()
    >>> p.id
    4L
    #因为 Publisher 模型有一个自动增加的主键 id ,所以第一次调用 save() 还多做了一件事: 计算这个主键的值并把它赋值给这个对象实例:

    >>> p = Publisher.objects.create(name='Apress', address='2855 Telegraph Avenue', city='Berkeley', state_province='CA', country='U.S.A.',website='http://www.apress.com/')
    >>> p.id
    5L
    这个方法也会有实例属性id
    2)更新
    >>>p = Publisher.objects.get(name='Apress')
    >>> p.name='jin'
    >>> p.save
    这里不爽的是需要原来创建的那个实例
    执行的 save() 相当于下面的SQL语句:
    UPDATE books_publisher SET
    name = 'jin',
    address = '2855 Telegraph Ave.',
    city = 'Berkeley',
    state_province = 'CA',
    country = 'U.S.A.',
    website = 'http://www.apress.com'
    WHERE id = 5;
    注意,并不是只更新修改过的那个字段,所有的字段都会被更新。 这个操作有可能引起竞态条件,这取决于你的应用程序。

    3)更新多个对象
    Django 模型的save()方法更新了不仅仅是name列的值,还有更新了所有的列。 若name以外的列有可能会被其他的进程所改动的情况下,只更改name列显然是更加明智的。
    更改某一指定的列,我们可以调用结果集(QuerySet)对象的update()方法:
    >>> Publisher.objects.filter(id=7).update(country='USA')
    1L
    等同
    UPDATE books_publisher
    SET country='USA'
    WHERE id = 52;
    update()方法会返回一个整型数值,表示受影响的记录条数。 在上面的例子中,这个值是2。
    update()方法对于任何结果集(QuerySet)均有效,这意味着你可以同时更新多条记录

    4、选择对象 查询
    1)基本查询数据 Publisher.objects.all()
    >>>Publisher.objects.all()
    [<Publisher: Apress>, <Publisher: O'Reilly>]
    QuerySet 对象,仿真列表
    这相当于这个SQL语句:
    SELECT id, name, address, city, state_province, country, website
    FROM books_publisher;
    注意到Django在选择所有数据时并没有使用 SELECT* ,而是显式列出了所有字段。
    设计的时候就是这样: SELECT* 会更慢,而且最重要的是列出所有字段遵循了Python 界的一个信条: 明言胜于暗示。
    Publisher.objects.all() 这行的每个部分:
    首先,已定义的模型 Publisher
    然后,是objects属性。 它被称为管理器
    所有的模型都自动拥有一个 objects 管理器;你可以在想要查找数据时使用它。
    最后,还有 all() 方法。这个方法返回返回数据库中所有的记录。 尽管这个对象 看起来 象一个列表(list),它实际是一个 QuerySet 对象, 这个对象是数据库中一些记录的集合。
    所有的数据库查找都遵循这个通用模式:
    2)数据过滤 Publisher.objects.filter()
    >>> Publisher.objects.filter(name='jin')
    [<Publisher: jin>]
    filter() 根据关键字参数来转换成 WHERE SQL语句。
    SELECT id, name, address, city, state_province, country, website
    FROM books_publisher
    WHERE name = 'jin';
    传递多个参数到 filter() 来缩小选取范围:
    >>> Publisher.objects.filter(country="U.S.A.", state_province="CA")
    [<Publisher: jin>, <Publisher: Apress>]
    多个参数会被转换成 AND SQL从句,
    SELECT id, name, address, city, state_province, country, website
    FROM books_publisher
    WHERE country = 'U.S.A.'
    AND state_province = 'CA';
    注意,SQL缺省的 = 操作符是精确匹配的
    LIKE方式匹配
    >>> Publisher.objects.filter(name__contains="press")
    [<Publisher: Apress>]
    在 name 和 contains 之间有双下划线。和Python一样,Django也使用双下划线来表明会进行一些魔术般的操作。这里,contains部分会被Django翻译成LIKE语句:
    3)、获取单个对象。Publisher.objects.get()
    上面的例子中`` filter()`` 函数返回一个记录集,这个记录集是一个列表。 相对列表来说,有些时候我们更需要获取单个的对象, `` get()`` 方法就是在此时使用的:
    >>> Publisher.objects.get(name="Apress")
    这样,就返回了单个对象,而不是列表(更准确的说,QuerySet)。 所以,如果结果是多个对象,会导致抛出异常:
    <Publisher: Apress>
    Publisher.objects.get(country="U.S.A.")
    如果查询没有返回结果也会抛出异常:
    DoesNotExist 异常 是 Publisher 这个 model 类的一个属性,即 Publisher.DoesNotExist。在你的应用中,你可以捕获并处理这个异常,像这样:
    try:
    p = Publisher.objects.get(name='Apress')
    except Publisher.DoesNotExist:
    print "Apress isn't in the database yet."
    else:
    print "Apress is in the database."
    4)数据排序 Publisher.objects.order_by()
    在你的 Django 应用中,你或许希望根据某字段的值对检索结果排序,比如说,按字母顺序。
    >>> Publisher.objects.all()
    [<Publisher: jin>, <Publisher: Apress>]
    >>> Publisher.objects.order_by("name")
    [<Publisher: Apress>, <Publisher: jin>]
    SQL语句里多了指定排序的部分:
    SELECT id, name, address, city, state_province, country, website
    FROM books_publisher
    ORDER BY name;
    对多个字段进行排序
    Publisher.objects.order_by("state_province", "address")
    还可以指定逆向排序,在前面加一个减号 - 前缀:
    类似SQL :ORDER BY name DESC;
    >>> Publisher.objects.order_by("-name")
    [<Publisher: jin>, <Publisher: Apress>]

    5)在模型的缺省排序方式
    尽管很灵活,但是每次都要用 order_by() 显得有点啰嗦。 大多数时间你通常只会对某些 字段进行排序。 在这种情况下,Django让你可以指定模型的缺省排序方式:
    class Publisher(models.Model):
    name = models.CharField(max_length=30)
    address = models.CharField(max_length=50)
    city = models.CharField(max_length=60)
    state_province = models.CharField(max_length=30)
    country = models.CharField(max_length=50)
    website = models.URLField()

    def __unicode__(self):
    return self.name

    class Meta:
    rdering = ['name']
    新的概念。 class Meta,内嵌于 Publisher 这个类的定义中(如果 class Publisher 是顶格的,那么 class Meta 在它之下要缩进4个空格--按 Python 的传统 )。
    你可以在任意一个模型类中使用 Meta 类,来设置一些与特定模型相关的选项。
    如果你设置了这个选项,那么除非你检索时特意额外地使用了 order_by(),否则,当你使用 Django 的数据库 API 去检索时,Publisher对象的相关返回值默认地都会按 name 字段排序。
    >>> from books.models import Publisher
    >>> Publisher.objects.all()
    [<Publisher: Apress>, <Publisher: jin>]

    6)连锁查询Publisher.objects.filter().order_by() #过滤后再排序
    我们已经知道如何对数据进行过滤和排序。 当然,通常我们需要同时进行过滤和排序查询的操作。 因此,你可以简单地写成这种“链式”的形式:
    >>> Publisher.objects.filter(country="U.S.A.").order_by("-name")
    [<Publisher: jin>, <Publisher: Apress>]
    转换成SQL查询就是 WHERE 和 ORDER BY 的组合:
    SELECT id, name, address, city, state_province, country, website
    FROM books_publisher
    WHERE country = 'U.S.A'
    ORDER BY name DESC;
    7)限制返回的数据
    另一个常用的需求就是取出固定数目的记录。可以使用标准的Python列表裁剪语句:
    Publisher.objects.order_by('name')[0]
    这相当于:
    SELECT id, name, address, city, state_province, country, website
    FROM books_publisher
    ORDER BY name
    LIMIT 1;
    类似的,可以用Python的range-slicing语法来取出数据的特定子集:
    Publisher.objects.order_by('name')[0:2]
    超出边界 不会报错
    注意,不支持Python的负索引(negative slicing):
    虽然不支持负索引,但是我们可以使用其他的方法。 比如,稍微修改 order_by() 语句来实现:
    >>> Publisher.objects.order_by('-name')[0]

    5、删除对象
    删除数据库中的对象只需调用该对象的delete()方法即可:
    >>> p = Publisher.objects.get(name="jin")
    >>> p.delete()
    >>> Publisher.objects.all()
    [<Publisher: Apress>]
    同样我们可以在结果集上调用delete()方法同时删除多条记录。这一点与我们上一小节提到的update()方法相似:
    >>> Publisher.objects.filter(country='USA').delete() #有条件删除
    >>> Publisher.objects.all().delete() #删除所有数据
    >>> Publisher.objects.all()
    []

  • 相关阅读:
    ab并发负载压力测试
    在vmware里运行qcow2镜像
    nginx root alias
    速成制作rpm包
    oracle分区表按时间自动创建
    Some network Tools
    python中defaultdict用法详解
    CENTOS7 安装telnet
    H3C 交换机配置
    H3C
  • 原文地址:https://www.cnblogs.com/diege/p/2715784.html
Copyright © 2011-2022 走看看