zoukankan      html  css  js  c++  java
  • django模型

    用django时,只要用到数据库就得用到模型。

    一、数据库的MTV开发模式

    从MVC到MTV

    所谓软件架构的MVC模式将数据的存取逻辑(Module),表现逻辑(View)和业务逻辑(Controller)分开,降低耦合。

    Module代表数据库的存取,View代表系统中选择显示什么和怎样显示,Controller指系统根据用户输入访问模型以决定使用哪个视图。

    django设计同样鼓励松耦合。

    django中的MTV模式也是一种MVC框架。

    M:django中模型,负责数据存取。

    V:由django视图模板控制那些数据要显示已经怎样显示。

    C:由django框架根据URLconf控制URL调用python函数,由框架自行处理

    所以对开发人员来说更关注模型,模板和视图,就演变成了M(Model)T(Template) V(Views)。

    二、数据库连接

    首先在settings.py文件进行数据库的配置。

    DATABASES = {
        'default': {
            'ENGINE': 'mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.                                                     
            'NAME': 'dbname',                      # Or path to database file if using sqlite3.
            'USER': 'stack',                      # Not used with sqlite3.
            'PASSWORD': 'password',                  # Not used with sqlite3.
            'HOST': 'x.x.x.x',                      # Set to empty string for localhost. Not used with sqlite3.
            'PORT': '3306',                      # Set to empty string for default. Not used with sqlite3.
            'OPTIONS': {
                        'charset': 'utf8',
                        'use_unicode': True, },
        }
    }

     配置好数据库,可以使用python manage.py shell进行测试,不报错说明配置可用。

    >>> from django.db import connection
    >>> cursor=connection.cursor()
    >>> 

    三、创建数据库模型APP

    django中一个项目可以包含多个app,项目中对这些app进行配置,配置数据库连接,app列表,模板路径等。

    一个app包括独立的功能,可复用,它包括独立的模型,视图。

    现在在mysite这个项目里创建一个books模型。

    liuxiaoyan@development:~/mysite$ python manage.py startapp books
    liuxiaoyan@development:~/mysite$ ls
    books  __init__.py  __init__.pyc  manage.py  settings.py  settings.pyc  urls.py  urls.pyc  views.py  views.pyc

    Django有专用的字段类型来描述Email地址、URL。好处就是高级的数据类型带来更高的效率和更好的代码复用。

    Django有工具从现有数据库表自动生成模型。

    先提醒一点,要非常注意模型和数据库的同步问题。修改了一个Django模型,要手动修改数据库来保证和模型同步。

    四、从模型生成数据库

    接下来使用django的模型。从一个例子开始,例子如下:

    • 一个作者有姓、名和Email地址。
    • 出版商有名称、地址,所在城市、省,国家,网站
    • 书籍有书名和出版日期。书和作者是多对多的关联关系[many-to-many],出版商和书是一对多的关联关系[one-to-many],也被称作外键[foreign key]

    1、建好模型

    liuxiaoyan@development:~/mysite/books$ cat 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()
    
    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()
    View Code

    解释:每个数据模型都是django.db.models.Model的子类。它的父类Model包含了所有必要的和数据库交互的方法,并提供了一个简洁的定义数据库字段的语法。

    *python在类名后用一对圆括号表示继承关系, 括号中的类表示父类 

    模型和表一一对应,属性和表的字段一一对应。属性名就是字段名,类型是数据库的字段类型。

    2、模型安装

    第一步,在settings.py文件的INSTALLED_APPS加入该APP。

    MIDDLEWARE_CLASSES中的中间件依赖于INSTALLED_APPS的条目。

    在INSTALLED_APPS中增加'mysite.books'元组。

    INSTALLED_APPS = (
        # 'django.contrib.auth',
        # 'django.contrib.contenttypes',
        # 'django.contrib.sessions',
        # 'django.contrib.sites',
        'books', #注意加上引号和这个逗号
    )
    View Code

    第二步,创建数据库表

    首先检测模型有效性

    liuxiaoyan@development:~/mysite$ python manage.py validate
    0 errors found

    打印创建数据库表的语句

    liuxiaoyan@development:~/mysite$ python 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_c5b274bb` FOREIGN KEY (`publisher_id`) REFERENCES `books_publisher` (`id`);
    ALTER TABLE `books_book_authors` ADD CONSTRAINT `book_id_refs_id_cfbcf262` FOREIGN KEY (`book_id`) REFERENCES `books_book` (`id`);
    CREATE INDEX `books_book_22dd9c39` ON `books_book` (`publisher_id`);
    COMMIT;
    View Code

    sqlall只是打印出SQL语句,没有在数据库创建表。

    创建表

    liuxiaoyan@development:~/mysite$ python manage.py syncdb
    Creating tables ...
    Creating table books_publisher
    Creating table books_author
    Creating table books_book_authors
    Creating table books_book
    Installing custom SQL ...
    Installing indexes ...
    No fixtures found.
    View Code

    syncdb同步INSTALLED_APPS的模型到数据库,这个同步是指检查表是否存在,不存在就创建,但是不能将模型的修改或删除同步到数据库。

    所以再次提醒修改了一个Django模型,要手动修改数据库来保证和模型同步。

    五、基本数据访问

    1、增

    liuxiaoyan@development:~/mysite$ python manage.py shell
    Python 2.7.3 (default, Feb 27 2014, 19:58:35) 
    [GCC 4.6.3] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    (InteractiveConsole)
    >>> from books.models import Publisher
    >>> p1 = Publisher(name='Apress', address='2855 Telegraph Avenue',city='Berkeley', state_province='CA', country='U.S.A.',website='http://www.apress.com/')
    >>> p1.save()
    >>> 

    调用django model API创建的对象必须通过save()插入数据库。

    如果要一步完成对象的创建和存储到数据库,就使用管理器的creae方法,即“object.creae()”。

    >>> from books.models import Publisher
    >>> p1 = Publisher.objects.create(name='Apress',address='2855 Telegraph Avenue',city='Berkeley', state_province='CA', country='U.S.A.',website='http://www.apress.com/')
    >>> p2 = Publisher.objects.create(name="O'Reilly",address='10 Fawcett St.', city='Cambridge',state_province='MA', country='U.S.A.',website='http://www.oreilly.com/')
    >>> publisher_list = Publisher.objects.all()
    >>> publisher_list
    [<Publisher: Publisher object>, <Publisher: Publisher object>]
    >>> 

    2、删

    在对象上调用delete()方法

    删除一条数据

    >>> p = Publisher.objects.get(name="O'Reilly")
    >>> p.delete()

    删除一部分数据

    找到某几个要删除的结果集,然后delete

    >>> Publisher.objects.filter(country='USA').delete()

    全部删除

    为预防错误,全部删除需要显示调用all()然后调用delete()

    >>> Publisher.objects.all().delete()

    3、改

    赋新值然后调用save()就是更新了,而且是全部字段都更新。

    liuxiaoyan@development:~/mysite$ python manage.py shell
    Python 2.7.3 (default, Feb 27 2014, 19:58:35) 
    [GCC 4.6.3] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    (InteractiveConsole)
    >>> from books.models import Publisher
    >>> p = Publisher(name='Apress',address='2855 Telegraph Ave.', city='Berkeley',state_province='CA',country='U.S.A.',website='http://www.starof.com/')
    >>> p.save()
    >>> p.id
    5L
    >>> p.name = 'lxy'
    >>> p.save()
    >>> p.id
    5L

    过程如下:

    第一次调用save()方法插入一条记录对应一个主键,把该主键值赋给对象实例p,再次调用save()方法不会创建新记录,而是去更新全部列。这会导致一个问题,比如我要修改name列, 其他进程同时要修改name之外的列,可能会有冲突。所以局部更新比较明智。

    局部更新

    调用管理器的update方法。相当于updte SQL,即update table set propertie='xxx' where name='xxx'。

    >>> Publisher.objects.filter(name='lxy').update(city='wuxi')
    1L
    >>> 

    update()可以同时更新多条记录

    比如把所有的城市都换成shanghai

    >>> Publisher.objects.all().update(city='shanghai')         
    3L
    >>> 

    4、查

    数据库的查询操作都是通过绑定在该模型上的管理器(objects)的相应方法(如all)。

    全部查询,返回结果集

    用Publisher.objects.all()来取出所有记录,但是并不是select * from table,而是显示列出所有字段。

    liuxiaoyan@development:~/mysite$ python manage.py shell
    Python 2.7.3 (default, Feb 27 2014, 19:58:35) 
    [GCC 4.6.3] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    (InteractiveConsole)
    >>> from books.models import Publisher
    >>> p1 = Publisher(name='Apress', address='2855 Telegraph Avenue',city='Berkeley', state_province='CA', country='U.S.A.',website='http://www.apress.com/')
    >>> p1.save()
    >>> p2 = Publisher(name="O'Reilly", address='10 Fawcett St.',city='Cambridge', state_province='MA', country='U.S.A.',website='http://www.oreilly.com/')
    >>> p2.save()
    >>> publisher_list = Publisher.objects.all()
    >>> publisher_list
    [<Publisher: Publisher object>, <Publisher: Publisher object>]
    >>> 

    Note:

    模型,这里就是Publisher,通过模型来获得数据。

    objects:属性,被称为管理器,所有模型自动拥有管理器属性,管理数据。

    部分查询,返回结果集

    使用管理器的filter()方法。

    >>> Publisher.objects.filter(name="Apress")
    [<Publisher: Apress>]

    相当where SQL ,即于select * from table where propertie=“xxx”。

    给定多个参数相当于and SQL,即select * from table where propertie1="xxx" and propertie2="xxx"

    >>> Publisher.objects.filter(country="U.S.A.", state_province="CA")
    [<Publisher: Apress>, <Publisher: lxy>]

    filter方法还可以使用其他类型查询,用__contains相当于like SQL,即select * from table where name like '%xxx%'

    >>> Publisher.objects.filter(name__contains='lx')
    [<Publisher: lxy>]

    返回单个对象,而非结果集

    使用管理器的get()方法。

    >>> Publisher.objects.get(name='lxy')
    <Publisher: lxy>

    要注意的是返回结果集和和没有查询结果都会抛异常。

    返回结果集

    >>> Publisher.objects.get(city="Berkeley")
    Traceback (most recent call last):
      File "<console>", line 1, in <module>
      File "/usr/lib/python2.7/dist-packages/django/db/models/manager.py", line 132, in get
        return self.get_query_set().get(*args, **kwargs)
      File "/usr/lib/python2.7/dist-packages/django/db/models/query.py", line 367, in get
        % (self.model._meta.object_name, num, kwargs))
    MultipleObjectsReturned: get() returned more than one Publisher -- it returned 2! Lookup parameters were {'city': 'Berkeley'}

    查询没有结果

    >>> Publisher.objects.get(name='lxx')
    Traceback (most recent call last):
      File "<console>", line 1, in <module>
      File "/usr/lib/python2.7/dist-packages/django/db/models/manager.py", line 132, in get
        return self.get_query_set().get(*args, **kwargs)
      File "/usr/lib/python2.7/dist-packages/django/db/models/query.py", line 365, in get
        % self.model._meta.object_name)
    DoesNotExist: Publisher matching query does not exist.

    查询结果排序

    使用管理器的order_by()方法。相当于order by SQL,即selsect * from table order by properties。

    >>> Publisher.objects.all()               
    [<Publisher: Apress>, <Publisher: O'Reilly>, <Publisher: lxy>]
    >>> Publisher.objects.all().order_by("name")
    [<Publisher: Apress>, <Publisher: lxy>, <Publisher: O'Reilly>]
    >>> Publisher.objects.order_by("name") 

    如果是根据名字逆向排序就加个减号前缀。

    >>> Publisher.objects.order_by("-name")
    [<Publisher: O'Reilly>, <Publisher: lxy>, <Publisher: Apress>]

    如果不想每次都写order_by,可以在模型里添加Meta类的ordering选项。

        class Meta:
            ordering=['name']

    连接查询

     过滤和排序查询,用“链式”操作。类似where和order by的组合,即select * from table where properite='xxx' order by xxx。

    >>> Publisher.objects.filter(country="U.S.A.").order_by("-name")
    [<Publisher: O'Reilly>, <Publisher: lxy>, <Publisher: Apress>]
    >>> 

    限制查询结果数量

    以下[0]取得第一个结果,相当于limit 1,即selsect * from table order by xxx limit 1。

    >>> Publisher.objects.filter(country="U.S.A.").order_by("-name")[0]
    <Publisher: O'Reilly>

    以下返回两个对象,相当于offset 0 limit 2,即没隔0个的取,总共取2个。

    >>> Publisher.objects.filter(country="U.S.A.").order_by("-name")[0:2]
    [<Publisher: O'Reilly>, <Publisher: lxy>]

    不管是使用get(),filter(),还是all(),不管得到的是单个记录,还是记录集,得到后,就是类似在之前的模型中定义的类的实例对象,此时,就可以进行取出实例的其他字段的数据,或者进行在模型类中定义的其他逻辑函数的操作了。

    5、按我们的需要显示查询信息

    普通情况下list结果都是类似:

    >>> publisher_list
    [<Publisher: Publisher object>, <Publisher: Publisher object>]
    >>> 

    我们想看点详细的信息,或者特定的信息,就给模型对象添加一个方法__unicode__(),类似java中的toString()方法。

    liuxiaoyan@development:~/mysite/books$ cat models.py
    from django.db import models
    
    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__()方法生效,退出python shell,然后再次运行python manage.py shell进入即可,不需要同步数据库,现在就可以看到想看的内容了。

    liuxiaoyan@development:~/mysite$ python manage.py shell
    Python 2.7.3 (default, Feb 27 2014, 19:58:35) 
    [GCC 4.6.3] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    (InteractiveConsole)
    >>> from books.models import Publisher
    >>> publisher_list = Publisher.objects.all()
    >>> publisher_list
    [<Publisher: Apress>, <Publisher: O'Reilly>]
    >>> 
    View Code

    6、添加行为到模型

    和添加__unicode__()一样。

    Django模型不只为对象定义了数据库表的结果,还定义了对象的行为。新添加的__unicode__()方法就是告诉模型怎样显示自己。

    六、访问外键值

    前面提到出版商和书是一对多的关系,即一本书只有一个出版商。在Book模型定义中可以看出

    publisher = models.ForeignKey(Publisher)

    出版社是以书的外键存在的。

    1、通过多端访问一端

    可以通过书来访问出版社,间接访问出版社的名字,地址,网站等各种属性。

    liuxiaoyan@development:~/mysite$ python manage.py shell
    Python 2.7.3 (default, Feb 27 2014, 19:58:35) 
    [GCC 4.6.3] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    (InteractiveConsole)
    >>> from books.models import Book
    >>> b=Book.objects.get(id=1)
    >>> b.publisher
    <Publisher: Apress>
    >>> b.publisher.website
    u'http://www.apress.com/'
    >>> b.publisher.address
    u'2855 Telegraph Avenue'
    >>> 

    2、通过一端访问多端

    通过一个出版社可以获取该出版社出版的所有书,或者可以通过关键字查询该出版社出版的符合某条件的书。

    >>> from books.models import Publisher
    >>> p=Publisher.objects.get(name="Apress")
    >>> p.book_set.all()
    [<Book: 《平凡的世界》>, <Book: 《说话之道》>]
    >>> p.book_set.filter(title__icontains='平凡')
    [<Book: 《平凡的世界》>]
    >>> 

    这里用到一个book_set,通过一个“publisher”对象,直接获取books,用publisher.book_set.all()。这里的book_set是一个QuerySet,所以可以进行数据过滤。而book_set这个属性则是由模型名称的小写加_set组成的。

    七、访问多对多值

    多对多和外键的工作方式相同,但是处理的都是QuerySet而不是模型实例。

    1、通过Book访问作者

    查看一本书的所有作者,

    liuxiaoyan@development:~/mysite$ python manage.py shell
    Python 2.7.3 (default, Feb 27 2014, 19:58:35) 
    [GCC 4.6.3] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    (InteractiveConsole)
    >>> from books.models import Book
    >>> b=Book.objects.get(id='5')
    >>> b.authors.all()
    [<Author: xiaoyan liu>, <Author: yao lu>]
    >>> b.authors.filter(first_name="yao")
    [<Author: yao lu>]
    >>> 

    2、通过Author访问Book

    查看一个作者的所有书,使用author.book_set

    >>> from books.models import Author
    >>> a=Author.objects.get(first_name='yao',last_name='lu')
    >>> a.book_set.all()
    [<Book: 童年>, <Book: 《平凡的世界》>]
    >>> 

    和外键一样,这里属性名book_set,是在数据模型后面追加_set。

    资源链接:

    http://djangobook.py3k.cn/2.0/chapter05/ 

    http://djangobook.py3k.cn/2.0/chapter10/

    django的教程

  • 相关阅读:
    flink 使用processFunction函数的sideOutPut实现filter操作(java版)
    flink 状态编程之RichFlatMapFunction用法-java
    java flink之eventTime和window
    java spark sql 计算各个省份广告点击数的top3
    java spark 计算各个省份广告点击数的top3
    java streaming转换算子window,countByWindow
    java spark转换算子sortByKey
    java spark转换算子join、leftOuterJoin、rightOuterJoin、fullOuterjoin
    java spark转换算子groupByKey、reduceByKey、aggregateByKey
    java spark转换算子union、intersection、subtract
  • 原文地址:https://www.cnblogs.com/starof/p/4268363.html
Copyright © 2011-2022 走看看