zoukankan      html  css  js  c++  java
  • django学习之Model(一)

    认认真真学Django,从现在开始。

    学习资料来源于官方网站:https://docs.djangoproject.com/en/1.6/

    1-新建一个models.py

    1 from django.db import models
    2 
    3 class Person(models.Model):
    4     first_name = models.CharField(max_length=50)
    5     last_name = models.CharField(max_length=50)

    first_name 和 last_name 是 model 的 fields,对应于生成的数据库中的 column. 上述的Pesron model可以创建如下的数据库的表:

    1 CREATE TABLE myapp_person (
    2     "id" serial NOT NULL PRIMARY KEY,
    3     "first_name" varchar(30) NOT NULL,
    4     "last_name" varchar(30) NOT NULL
    5 );

    注释:

    1)-表的名称 myapp_person是从模型元数据中自动生成的,但是可以被重写。详见表的名称。

    2)-id这个field也是被自动添加的,也是可以重写的。详见下文中的自动生成基本的key fields.

    3)-例子中的CREATE TABLE 语句是用的PostgreSQL 语法,主要还是看你settings.py文件中的settings是怎么写的。

    2-使用models

    定义了models之后,需要告诉django你要使用它。如果你的例子model是在myapp.models,则在settings.py文件中的settings中的INSTALLED_APPS中添加如下:

    INSTALLED_APPS = (
        #...
        'myapp',
        #...
    )

    添加后,请运行python manage.py syncdb, 这个语句实际上就是创建了数据的表(table),如前所述的CREATE TABLE。

    3-Fields

    fields 是 models中最重要,也是唯一的必须部分。注意避免跟models API重名了,例如clean, save等。

     1 from django.db import models
     2 
     3 class Musician(models.Model):
     4     first_name = models.CharField(max_length=50)
     5     last_name = models.CharField(max_length=50)
     6     instrument = models.CharField(max_length=100)
     7 
     8 class Album(models.Model):
     9     artist = models.ForeignKey(Musician)
    10     name = models.CharField(max_length=100)
    11     release_date = models.DateField()
    12     num_stars = models.IntegerField()

    Field Types:

    django用fields来决定以下三件事情:

    1)-数据表中的column的数据类型,例如 INTEGER, VARCHAR

    2)-渲染一个表单form时默认的HTML中间件(widget)用到的,例如<input type="text">, <select>

    3)-django'admin所有的最小的需求,当自动生成表单的时候。

    model field reference 中有全部的field信息,也可以自己写field,参考writing custom model fields.

    Field Options:

    每个field都需要根据特点设定自己的一些参数,例如CharField需要有参数max_length,来规定database中的column的 VARCHAR的大小。

    也有一些共同那个的参数:

    null:如果True, django会把空值作为NULL存在database中。默认值为False

    blank:如果True, 这个field允许是空,默认值为False。注意与null值的不同。null值是纯粹与database相关的,而blank是用来作确认用的,例如,如果一个 field 的 blank=True, 表单 form 的确认就会允许这个 field 不填东西,如果 False 则该处必须填写。(可以理解为,先由 blank 来规定此处是否必填, 再由 null 来取值是空存 NULL 给 database 还是非空)

    choices:作为某个field的选项的二元数组。如果给出 choices ,默认的表单中间件就会是 select box, 而不是 text field 了,而且选项会被限制为 choices 中给出的值。

    有如下的例子:

    YEAR_IN_SCHOOL_CHOICES = (
        ('FR', 'Freshman'),
        ('SO', 'Sophomore'),
        ('JR', 'Junior'),
        ('SR', 'Senior'),
        ('GR', 'Graduate'),
    )

    数组中的第一个值(FR),是被存进 database 中的值,第二个值是在默认 form 或 自己写的ModelChoiceField 中显示的。假设已经写好一个 model 的对象(database中已经存入数据),get_F00_display方法会对有choices的field的数据显示进行处理,例如:

    from django.db import models
    
    class Person(models.Model):
        SHIRT_SIZES = (
            ('S', 'Small'),
            ('M', 'Medium'),
            ('L', 'Large'),
        )
        name = models.CharField(max_length=60)
        shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES)
    >>> p = Person(name="Fred Flintstone", shirt_size="L")
    >>> p.save()
    >>> p.shirt_size
    u'L'
    >>> p.get_shirt_size_display()
    u'Large'

    default:

    每个field的默认值。可以是一个值也可以是一个被调用的对象(callable object)。

    help_text:

    额外的help文字随着form中间件显示。即使你的这个field不会用在form表单上,这样对于文档也是有用的。

    primary_key:

    如果为True, 这个field是model的主关键字。如果你的model中没有primary_key=True的field,则django会自动给加上一个类型为IntegerField的field来存储主关键字。所以,除非你要重写默认的primary-key这个实现方法,那么就不需要设定primary_key=True。更多请参考Automatic primary key fields.

    unique:

    如果为True, 则这个field必须是整个table中的唯一的。

    以上只是简单的一个介绍,完备的资料请参考common model field option reference.

    Automatic primary key fields(自动生成主关键字的field):

    默认的,django给每个model都会自动生成下面的field:

    id = models.AutoField(primary_key=True)

     这是一个自动增加的主关键字。

    如果你要自己定义一个primary key,只要你在你需要的field中令primary_key=Ture,一旦django知道你设定了Field.primary_key, 它就不会自动创建id column了。

    每个model都确切的需要有一个field , 其primary_key=True.不论是自己声明的,还是自动添加的。

    Verbose field names:

    除了ForeignKey, ManyToManyFiled, OneToOneField外,每个field类型,都有一个可选择的参数verbose name,它放在参数列表的第一个。如果verbose name没有指定,django会用field的名字自动生成一个,下面这个例子的verbose name是person's first name:

    first_name = models.CharField("person's first name", max_length=30)

     而下面的则是first name:

    first_name = models.CharField(max_length=30)

     ForeignKey, ManyToManyField, OneToOneField的第一个参数是model class的名字,所以他们的verbose_name用法如下:

    poll = models.ForeignKey(Poll, verbose_name="the related poll")
    sites = models.ManyToManyField(Site, verbose_name="list of sites")
    place = models.OneToOneField(Place, verbose_name="related place")

     转换不是把verbose_name的首字母大写,django会在需要的时候自动完成大写转换。

    Relationships:

    显然,相关联的database是依赖于相关联的tables的。django提供了常见的三种database关联方式:many-to-one, many-to-many, one-to-one。

    Many-to-one relationships:

    用djangol.db.models.ForeignKey来实现many-to-one关系的。像用其他的field类型一样,把ForeignKey当作你的model的类的属性。

    ForeignKey需要一个位置的变量(即与谁建立关系)。例子如下:

    from django.db import models
    
    class Manufacturer(models.Model):
        # ...
        pass
    
    class Car(models.Model):
        manufacturer = models.ForeignKey(Manufacturer)
        # ...

    the model field reference中有更详细的介绍。

    一个建议(非必须),ForeignKey field的名字最好跟model的名字一样。也可以自己随便起名字,如下:

    class Car(models.Model):
        company_that_makes_it = models.ForeignKey(Manufacturer)
        # ...

    注释:ForeignKey field 接受很多别的变量(the model field reference),这些都是可选变量,可以定义这个relationships怎样工作。更多的db的API可以参照Making querise.

    Many-to-many relationships:

    用ManyToManyField来定义many-to-many关系,像前文所述来使用。也需要一个位置的变量(与谁建立关系)。例如,一个Pizza有多个Topping对象,也就是一个Topping对象对应多个Pizza,同时每个Pizza有多个topping对应,即多对多的关系,可以如下使用:

    from django.db import models
    
    class Topping(models.Model):
        # ...
        pass
    
    class Pizza(models.Model):
        # ...
        toppings = models.ManyToManyField(Topping)

    获取更多参考Making querise.

    同样建议使用相同名字来命名field,如上例,toppings.

    一般来讲,ManyToManyField实例应该是在form表单中编辑的,在上例中,toppings放在Pizza中(而不是Topping有一个pizzas这样的ManyToManyField),这是由于pizaa含有toppings更自然一些,像上例中这样设定,Pizza这个表单会让用户从中选择toppings.

    同样有很多非必须的变量,请参照Making querise.

    更多many-to-many relationships的fields:

    标准的ManyToManyField 对于简单的处理够用了,如果需要在两个model之间进行data的一些联系的话,需要更多的方法。

    例如,建立一个app来追踪音乐家和其所属群组间的关系。人与组之间是个多对多的关系,而还有很多的其他数据想要搜集,例如某人加入某组的日期。可以在Group中通过through方法来绑定进来一个Membership,建立起联系,如下:

    from django.db import models
    
    class Person(models.Model):
        name = models.CharField(max_length=128)
    
        # On Python 3: def __str__(self):
        def __unicode__(self):
            return self.name
    
    class Group(models.Model):
        name = models.CharField(max_length=128)
        members = models.ManyToManyField(Person, through='Membership')
    
        # On Python 3: def __str__(self):
        def __unicode__(self):
            return self.name
    
    class Membership(models.Model):
        person = models.ForeignKey(Person)
        group = models.ForeignKey(Group)
        date_joined = models.DateField()
        invite_reason = models.CharField(max_length=64)

    注意,Membership中,用ForeignKey来建立与Person和Group的关系。

    对于中间model有几个条件:

    1)-中间model有且只有一个target model来做ForeignKey

    2)-中间model有且只有一个source model来做ForeignKey

    3)-唯一的例外是有一个model是他自身的many-to-many relationship, 这样的中间model就可以有2个一样的ForeignKey的model了,但是起作用不同,一个作为target,一个作为source.

    4)-上一条情况下,要令symmetrical=False,见the model field reference

    下面是一个实例来理解这个through是如何工作的:

    >>> ringo = Person.objects.create(name="Ringo Starr")
    >>> paul = Person.objects.create(name="Paul McCartney")
    >>> beatles = Group.objects.create(name="The Beatles")
    >>> m1 = Membership(person=ringo, group=beatles,
    ...     date_joined=date(1962, 8, 16),
    ...     invite_reason="Needed a new drummer.")
    >>> m1.save()
    >>> beatles.members.all()
    [<Person: Ringo Starr>]
    >>> ringo.group_set.all()
    [<Group: The Beatles>]
    >>> m2 = Membership.objects.create(person=paul, group=beatles,
    ...     date_joined=date(1960, 8, 1),
    ...     invite_reason="Wanted to form a band.")
    >>> beatles.members.all()
    [<Person: Ringo Starr>, <Person: Paul McCartney>]

    与正常的多对多fields不同,不能用add, create, assignment来建立关系:

    # THIS WILL NOT WORK
    >>> beatles.members.add(john)
    # NEITHER WILL THIS
    >>> beatles.members.create(name="George Harrison")
    # AND NEITHER WILL THIS
    >>> beatles.members = [john, paul, ringo, george]

    因为用了through,写了一个中间model,所以就不能用add等方法来直接给多对多的关系来写入数据了,必须要用中间model来把target和source的数据连到一起(姑且这样理解),也就是说,没有额外数据->不用through->不用写中间model->可以用add等方法直接操作数据。

    同样的原因导致remove()方法不能用,但是可以用clear()方法,如下:

    >>> # Beatles have broken up
    >>> beatles.members.clear()
    >>> # Note that this deletes the intermediate model instances
    >>> Membership.objects.all()
    []

    一旦通过中间model(through)建立了多对多关系型数据库,就可以用query去访问了。

    注意体会下面4段代码:

    # Find all the groups with a member whose name starts with 'Paul'
    >>> Group.objects.filter(members__name__startswith='Paul')
    [<Group: The Beatles>]
    # Find all the members of the Beatles that joined after 1 Jan 1961
    >>> Person.objects.filter(
    ...     group__name='The Beatles',
    ...     membership__date_joined__gt=date(1961,1,1))
    [<Person: Ringo Starr]
    >>> ringos_membership = Membership.objects.get(group=beatles, person=ringo)
    >>> ringos_membership.date_joined
    datetime.date(1962, 8, 16)
    >>> ringos_membership.invite_reason
    u'Needed a new drummer.'
    >>> ringos_membership = ringo.membership_set.get(group=beatles)
    >>> ringos_membership.date_joined
    datetime.date(1962, 8, 16)
    >>> ringos_membership.invite_reason
    u'Needed a new drummer.'

     One-to-one relationships(一对一关系):

    用OneToOneField来定义这种关系。当利用主键(primarykey)来拓展另一个model的时候,这种一对一关系型就显得比较重要,也可以说是较常用的。

    one-to-one也需要一个位置的参数(与谁连接)。例如你要建立一个places的database,可能包括address, phone等信息,然后在它之上想要加一个school的database,就可以在school的model中添加OneToOneFiled(Places),实际上就是一种继承,毫无疑问是one-to-one的了。

    更多信息请参考 the model field reference

    很多地方理解不深,代码照搬官方指南,如有错误热盼指正。

  • 相关阅读:
    Qt ------ QPainter 和控件组件的重绘
    Qt error ------ no matching function for call to QObject::connect(QSpinBox*&, <unresolved overloaded function type>, QSlider*&, void (QAbstractSlider::*)(int))
    DHCP 服务器功能
    matlab --- plot画图
    网站跨域解决方案有哪些
    分布式Session一致性解决方案有哪些?
    博客收集
    idea快捷键
    Linux打包、压缩与解压详解
    lastIndex()与IndexOf()的区别
  • 原文地址:https://www.cnblogs.com/ee2213/p/3910178.html
Copyright © 2011-2022 走看看