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.objects.filter(entry__headline__contains='Lennon', entry__pub_date__year=2008)
### 查询结果是分别满足两个条件的并集

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]

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


 

 





 

你可能感兴趣的:(django)