ps: 看了昆汀塔伦蒂诺的新片,Django原来d不发音啊,所以应该念“姜戈”(类似jungle的发音)。
无论是RoR还是Django,甚至颇具野心的前端框架EmberJs.data,将ORM集成于框架之中并赋予方便存储的API,大大提高了开发效率。不像Java世界中的Hibernate弄了个HQL查询语言,Django这里利用动态语言的优势,令CRUD语义更加自然(EJB3.0中JPA其实也有类似的意思)。当然你还是可以用纯粹的sql直接操作。
https://docs.djangoproject.com/en/dev/ref/models/instances/
这里先跳过如何用django.Models对数据库建模。假设已经存在下列ORM对象定义,Blog<-(一对一)->>Entry<<-(一对多)->Author。
class Blog(models.Model): name = models.CharField(max_length=100) tagline = models.TextField() def __unicode__(self): return self.name class Author(models.Model): name = models.CharField(max_length=50) email = models.EmailField() def __unicode__(self): return self.name class Entry(models.Model): blog = models.ForeignKey(Blog) headline = models.CharField(max_length=255) body_text = models.TextField() pub_date = models.DateField() mod_date = models.DateField() authors = models.ManyToManyField(Author) n_comments = models.IntegerField() n_pingbacks = models.IntegerField() rating = models.IntegerField() def __unicode__(self): return self.headline
基本CRUD操作
from blog.models import Blog, Entry, Author
blog = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
blog.save()
entry = Entry.objects.get(pk=1)
blog = Blog.objects.get(name="Beatles Blog")
entry.blog = blog # ForeignKey
entry.save()
john = Author.objects.create(name="John")
paul = Author.objects.create(name="Paul")
george = Author.objects.create(name="George")
ringo = Author.objects.create(name="Ringo")
entry.authors.add(john, paul, george, ringo) # ManyToManyField
all_author = Author.objects.all()
blog.delete()
Entry.objects.filter(pub_date__year=2007).update(headline='Everything is the same')
Entry.objects.all().update(n_pingbacks=F('n_pingbacks') + 1)
查询过滤器
分为
filter(**kwargs) 和
exclude(**kwargs)两种,前者是包含条件查询,后者是不包含条件查询。都返回QuerySet集合,并且可以级联查询。
如果明确地查询唯一对象,可以使用
get(**kwargs)
如果查询所有对象,使用all()就行。
Entry.objects.filter(
headline__startswith='What'
).exclude(
pub_date__gte=datetime.date.today()
).filter(
pub_date__gte=datetime(2005, 1, 30)
)
### blog的某一个entry满足两个条件,就返回该blog
Blog.objects.filter(entry__headline__contains='Lennon', entry__pub_date__year=2008)
### blog的某个entry满足前一条件,同时其另一个entry满足后一个条件,就返回该blog
Blog.objects.filter(entry__headline__contains='Lennon').filter(entry__pub_date__year=2008)
查询表达式
(注意字段名后面是两个下划线,再加查询表达式)。
比较,lte, le, gt, gte :
### SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01';
Entry.objects.filter(pub_date__lte='2006-01-01')
(精确)相等, id, pk:
### SELECT ... WHERE id = 14;
Blog.objects.get(id=14)
包含:
### SELECT ... WHERE headline LIKE '%Lennon%';
Entry.objects.get(headline__contains='Lennon')
此外,还有icontains、startswith、endswith、isnull, in, 等
关系传递的查询表达式
对某个对象的外键或关联对象直接作为查询条件。
Entry.objects.filter(blog__name__exact='Beatles Blog')
Blog.objects.filter(entry__authors__name='Lennon')
Blog.objects.filter(entry__authors__isnull=False, entry__authors__name__isnull=True)
分片查询
以下等同于
SELECT
*
FROM
Entry
OFFSET 5
LIMIT
3
Entry.objects.all()[5:8]
结果排序
以下对结果按某字段排序,再分片
Entry.objects.order_by('headline')[0:1]
F表达式(F Expression)
之前的查询表达式的右侧都是常量,而F表达式用于引用被查询对象的其他字段。
(n_xxx表示xxx字段按照数字类型处理。)
from django.db.models import F
from datetime import timedelta
Entry.objects.filter(n_comments__gt=F('n_pingbacks') * 2)
Entry.objects.filter(rating__lt=F('n_comments') + F('n_pingbacks'))
Entry.objects.filter(authors__name=F('blog__name'))
Entry.objects.filter(mod_date__gt=F('pub_date') + timedelta(days=3))
F('somefield').bitand(16)
利用Q对象(Q Object)的复杂查询
一旦查询条件使用了Q对象,所有条件就都必须是Q对象。Q对象可以用& (And), | (Or), ~ (Not)来运算。
from django.db.models import Q
### SELECT * from polls WHERE question LIKE 'Who%' AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')
Poll.objects.get(
Q(question__startswith='Who'),
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)
复制对象
将pk设为None后保存,即可生成新记录。如果对象有继承关系,还要将pk和id都设为None才行。
blog = Blog(name='My blog', tagline='Blogging is easy')
blog.save() # blog.pk == 1
blog.pk = None
blog.save() # blog.pk == 2
class ThemeBlog(Blog):
theme = models.CharField(max_length=200)
django_blog = ThemeBlog(name='Django', tagline='Django is easy', theme='python')
django_blog.save() # django_blog.pk == 3
django_blog.pk = None
django_blog.id = None
django_blog.save() # django_blog.pk == 4
注意,复制对象不会复制原有对象的关系,需要手动复制。
entry = Entry.objects.all()[0] # some previous entry old_authors = entry.authors.all() entry.pk = None entry.save() entry.authors = old_authors # saves new many2many relations
访问关系对象
无论是外键,还是一对多,多对多关系,都需要访问其他关系对象。
一对一关系时,正向、反向访问都直接用字段名即可。
一对多关系时,正向访问用字段名,反向访问用字段名加上"_set"后缀。关系对象集可以用add, remove, create, clear,count, filter等来操作。
Entry.objects.get(id=2).blog
Entry.objects.get(id=2).authors.filter(name__contains='John')
Blog.objects.get(id=1).entry_set.all()