Django点滴(四)---ORM对象存取

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()







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值