不可否认, django的文档写的很好, 也很多文档.
对于本人还是那句话: 如果使用文字不能把一件事物清楚地描述出来的话, 那么你对这件事物还是不清晰 . (^_^)
ORM类实例对象的创建
1. 使用类的__new__方法
2. 使用类Manager.create方法
两个类:
class Musician(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
instrument = models.CharField(max_length=100)
class Album(models.Model):
artist = models.ForeignKey(Musician)
name = models.CharField(max_length=100)
release_date = models.DateField()
num_stars = models.IntegerField()
创建对象:
1. 使用类的__new__方法:
In [6]: m = Musician(first_name='firename', last_name='lastname', instrument="something")
In [7]: m.id
这时, 新创建的对象是没有id的. 也就是还没有数据库的记录. 还需要使用方法把数据存在到数据库中:
In [8]: m.save()
In [9]: m.id
Out[9]: 2L
2. 使用类的Manager.creater方法:
In [4]: m = Musician.objects.create(first_name='firename', last_name='lastname', instrument="something")
In [5]: m.id
Out[5]: 3L
这时, 数据已经被添加到数据库表, 不用调用save方法
任何model类实例对象都有这两种方法创建.
ManyToOne Field添加引用实例
Album与Mussician的关系是"多对一", Album创建实例时多了一个条件: Album的__new__和Manager.create会检查artist参数是不是Musician的实例:
__new__方法:
In [12]: a = Album(artist=2, name='album name', release_date=datetime.datetime.now(), num_stars=10)
ValueError: Cannot assign "2": "Album.artist" must be a "Musician" instance.
Manager.create方法:
In [13]: a = Album.objects.create(artist=2, name='album name', release_date=datetime.datetime.now(), num_stars=10)
ValueError: Cannot assign "2": "Album.artist" must be a "Musician" instance.
* 传个与primary key相同的数字还是出错
需要在artist参数位置传入一个指定的实例:
步骤1: 使用Musician的__new__或者Manager.create创建Musician对象:
m = Musician(first_name='firename', last_name='lastname', instrument="something")
m.save() # 一定要被存在在数据库中才能被Album的创建方法正常使用, 则否出错.
a = Album(artist=m, name='album name', release_date=datetime.datetime.now(), num_stars=10)
a.save()
如果m不使用save()的情况:
In [27]: m = Musician(first_name='firename', last_name='lastname', instrument="something")
In [28]: a = Album(artist=m, name='album name', release_date=datetime.datetime.now(), num_stars=10)
In [29]: a.save()
IntegrityError: (1048, "Column 'artist_id' cannot be null")
出错. 说artist_id为null
使用对象:
有两个方向: 1. 从Foreign端; 2. 从被Foreign端
1. 从Foreign端
In [19]: a = Album.objects.get(pk=1)
In [20]: a.artist.id
Out[20]: 4L
In [22]: a.artist.first_name
Out[22]: u'firename'
这种引用方法很pythonic
2. 从被Foreign端
这时候被称为: The “other side” of a ForeignKey relation. 如果一个model类被其它类通过foreign key引用的话. 那么, 在被引用
的类和这个类的实例中, 会多一个属性:
In [61]: type Musician.album_set
-------> type(Musician.album_set )
Out[61]: <class 'django.db.models.fields.related.ForeignRelatedObjectsDescriptor'>
In [62]: m = Musician.objects.get(pk=1)
In [63]: type m.album_set
-------> type(m.album_set )
Out[63]: <class 'django.db.models.fields.related.RelatedManager'>
在django文档中有这样一句话:
Following relationships "backward"
If a model has a ForeignKey, instances of the foreign-key model will have
access to a Manager that returns all instances of the first model. By
default, this Manager is named FOO_set, where FOO is the source
model name, lowercased. This Manager returns QuerySets, which can be
filtered and manipulated as described in the "Retrieving objects"
作用就是能通过此方法找到一个对象都被哪些对象引用
# 下面是从album实例找到引用的musician实例
In [64]: a = Album.objects.get(pk=1)
In [65]: a.id
Out[65]: 1L
In [67]: a.artist.id
Out[67]: 4L
# 下面是从musician实例找到被哪个album实例引用了
In [68]: m = Musician.objects.get(pk=4)
In [70]: a_set = m.album_set.all()
In [71]: a_set.count()
Out[71]: 1
In [72]: a = a_set[0]
In [73]: a.id
Out[73]: 1L
蓝色的部分都是一样的, 表示是同一个album实例
ManyToMany Field添加引用实例
class Domain(models.Model):name = models.CharField(max_length=128)
is_singular = models.IntegerField()
description = models.CharField(max_length=32, default="")
object = models.ManyToManyField("Object")
class Object(models.Model):
name = models.CharField(max_length=128)
description = models.CharField(max_length=32, default="")
ManyToMany字段是可以引用(foreign)多个实例的. 这通过ManyToMany Field的add方法实例:
In [2]: domain = Domain(name = 'china', is_singular=1)
In [3]: domain.object.add
ValueError: 'Domain' instance needs to have a primary key value before a many-to-many relationship can be used.
In [5]: domain.object.add
Out[5]: <bound method ManyRelatedManager.add of <django.db.models.fields.related.ManyRelatedManager object at 0x9fa82ec>>
可以看出, ManyToMany Field的add方法是需要在save后才有的.
下面为ManyToMany Field增加引用实例:
In [6]: obj = Mod.Object(name="object1")
In [7]: domain.object.add(obj)
IntegrityError: (1048, "Column 'object_id' cannot be null")
* 与Foreign Field是一样的, 都是需要被引用的对象先存在于数据库表中!
In [8]: obj.save()
In [9]: domain.object.add(obj)
In [10]: domain.save()
* 调用obj.save后, 才成功添加引用实例!
还是可以引用多个实例的:
In [11]: obj = Object(name="object2")
In [12]: obj.save()
In [13]: domain.object.add(obj)
In [14]: domain.save()
* 这么多个save(), 是因为底层还是关系型数据库, 每一次save就对应着一次insert或者是update
通过through参数, 使用定制义的中间表, 此后, ManyToMany Field没有了add方法!
新的模型如下:class Domain(models.Model):
name = models.CharField(max_length=128)
is_singular = models.IntegerField()
description = models.CharField(max_length=32, default="")
object = models.ManyToManyField("Object", through="DomainObject")
class Object(models.Model):
name = models.CharField(max_length=128)
description = models.CharField(max_length=32, default="")
class DomainObject(models.Model):
domain = models.ForeignKey("Domain")
object = models.ForeignKey("Object")
# 找一找ManyToMany Field的add方法:
In [2]: domain = Mod.Domain(name = 'china', is_singular=1)
In [3]: domain.save()
In [4]: domain.add
AttributeError: 'Domain' object has no attribute 'add'
* 被掩了!
为ManyToMany Field添加引用实例需要使用如下方法:
In [6]: domain
Out[6]: <Domain: Domain object>
In [7]: obj
Out[7]: <Object: Object object>
In [8]: domain_object = Mod.DomainObject.objects.create(domain=domain, object=obj)
* 这里的Manager.create方法可以类的__new__方法
这是显式使用了中间表对应的类来生成映射关系.
使用对象:
和上面的ManyToOne情况一样, 有两个方向: 1. 从Foreign端; 2. 从被Foreign端
1. 从Foreign端In [23]: domain.object
Out[23]: <django.db.models.fields.related.ManyRelatedManager object at 0x9fa802c>
为一个Manager对象!
In [24]: objs = domain.object.all()
In [27]: for item in objs:
....: print item.id
1
2
可见, 这时间是需要指定select条件才能取回自己想要的对象
2. 从被Foreign端
In [28]: obj = domain.object.all()[0]
In [29]: obj.id
Out[29]: 1L
In [30]: domain.id
Out[30]: 1L
可见, ID为1的domain引用了ID为1的object, 反过来找:
In [35]: obj = Object.objects.get(pk=1)
In [39]: domain = obj.domain_set.get(pk=1)
In [40]: domain.id
Out[40]: 1L
改变RelatedManager的名字
class Musician(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
instrument = models.CharField(max_length=100)
class Album(models.Model):
artist = models.ForeignKey(Musician, related_name="Musician_set")
name = models.CharField(max_length=100)
release_date = models.DateField()
num_stars = models.IntegerField()
多了红色代码, 然后:
In [7]: m = Musician(first_name='first_name', last_name='last_name', instrument='instrument')
In [8]: m.Musician_set
Out[8]: <django.db.models.fields.related.RelatedManager object at 0x8de220c>
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.