zoukankan      html  css  js  c++  java
  • Django ORM

    一、表单的建立

    在model.py中映射关系

        

        表名 <-------> 类名

        字段 <-------> 属性      

        表记录 <------->类实例对象


    1.1 建立基本映射关系

    #建立author表和authorDetail表,最终数据库表名称为app名+_author..
    class Author(models.Model):
        nid = models.AutoField(primary_key=True)   # 建立自增主键并可以省略 主键可以用pk查询,这里可以用nid也可以用pk
        name=models.CharField( max_length=32)      # CharField为字符串类型 最大长度为32
        age=models.IntegerField()
        email= models.EmailField()           
        # 与AuthorDetail建立一对一的外键关系 自动与autordetail表的主键建立foreignkey关联
        authorDetail=models.OneToOneField(to="AuthorDetail") 
    
    
    class AuthorDetail(models.Model):
        nid = models.AutoField(primary_key=True)
        birthday=models.DateField()
        telephone=models.BigIntegerField()
        addr=models.CharField( max_length=64)
    # 用IntegerField
    class Projects(models.Model):
        name = models.CharField(max_length=20)
        desc = models.CharField(max_length=120)
        member = models.ManyToManyField(to="Userinfo")
        choice = (
            (1, 'Conducting'),
            (2, 'Suspended'),
            (3, 'Planning'),
            (4, 'Finished')
        )
        status = models.IntegerField(choices=choice)
    
    # 或者用Charfield(官方示例)
    from django.db import models
    
    class Student(models.Model):
        FRESHMAN = 'FR'
        SOPHOMORE = 'SO'
        JUNIOR = 'JR'
        SENIOR = 'SR'
        YEAR_IN_SCHOOL_CHOICES = (
            (FRESHMAN, 'Freshman'),
            (SOPHOMORE, 'Sophomore'),
            (JUNIOR, 'Junior'),
            (SENIOR, 'Senior'),
        )
        year_in_school = models.CharField(
            max_length=2,
            choices=YEAR_IN_SCHOOL_CHOICES,
            default=FRESHMAN,
        )
    
        def is_upperclass(self):
            return self.year_in_school in (self.JUNIOR, self.SENIOR)
    
    # 如果选择过于复杂建议用foreignkey。注意区别
    选择
    # blank 和 null 的区别,前者限制的组件,后者限制的数据库
    # db_column 用来指定数据库中的字段名
    # db_index=True、False 用来指定是否是索引
    # db_tablespace 表空间,当有索引的时候,会作为索引的名字。在setting中可以设置DEFAULT_INDEX_TABLESPACE
    # Field.editable,如果为false,则不可编辑,那么admin和其它model则忽略掉这个字段。#
    # Field.error_messages,能够重写默认抛出的错误信息。
    # Field.help_text,将会作为提示信息显示在表单中。
    # Field.primary_key,这意味着null=False和unique=True,所以一个对象只能拥有一个主键。
    # Field.unique,当设定为True时,不需要再设定db_index,因为其本身就是一个索引的创建。注意的是,ManyToManyField和OneToOneField和FileField以外的其它类型都可以使用这个字段
    # Field.unique_for_date/Field.unique_for_month/Field.unique_for_year/Field,设置在DateField或者设置在DateTimeField上,可以设置和某个字段联合唯一。例如unique_for_data = "title". 这个字段和title字段就联合唯一了。
    # Field.verbose_name, 一个A human-readable name
    # Field.validators,指定验证器。
    # ForeignKey、ManyToManyField和OneToOneField需要通过Field.verbose_name才能自定义设置字段名,其它均可以每个字段类型都可在第一个参数上自定义设置字段的字段名。
    所有参数
    AutoField 这个不用亲自加
    BinaryField  A field to store raw binary data. It only supports bytes assignment. 
    NullBooleanField # 用这个代替BooleanField with null=True
    SlugField # 下文详解
    FileField  # 下文详解
    ImageField # 同FileField 但是多了width_field,height_field 属性
    
    DurationField A field for storing periods of time - modeled in Python by timedelta. When used on PostgreSQL, the data type used is an interval and on Oracle the data type is INTERVAL DAY(9) TO SECOND(6). Otherwise a bigint of microseconds is used.
    
    
    DateField  注意 DateField.auto_now和auto_now_add区别 前者每次改都更新,后者只第一次自动加
    BigIntegerField
    DecimalField
    GenericIPAddressField 保存IP地址的有protocol属性是ipv4还是v6
    BooleanField
    CharField
    TextField
    URLField
    UUIDField
    EmailField
    FloatField
    字段类型(除外键)
    https://www.cnblogs.com/ohmydenzi/p/5584846.html
    
    1、slug:用于生成一个有意义(valid, meaninful)URL  参考
    
    比如:http://stackoverflow.com/questions/427102/what-is-a-slug-in-django  后面的“what-is-a-slug-in-django”就是经过slug后的产物
    
    需要使用slugify功能:from django.utils.text import slugify
    
    例子:slugify(value)  If value is "Joel is a slug", the output will be "joel-is-a-slug".
    
    2、SlugField:也是起到类似作用,只不过这个一般是后台直接添加时使用,比如:slug = models.SlugField(unique=True)   这样在后台就有个slug框,填写后,URL中就包含slug中的内容。
    一般是先slugfy 然后再存入slugfield
    slug详解

     

    1.2 一对多关系

    class Author(models.Model):
        nid = models.AutoField(primary_key=True)  
        ......
        authorDetail=models.OneToOneField(to="AuthorDetail") 
        type = models.ForeignKey("TypeHome") #可以像这样直接关联外键完成一对多关系的建立
        orgnization = models.ForeignKey(verbose_name='所属博客', to='Blog', to_field='nid') # 也可以写清除 to 代表关联表,to_field代表关联字段。
    
    
    class Blog(models.Model):
        .....
    class TypeHome(models.Model):
        .....
    user=models.OneToOneField(User,on_delete=models.CASCADE)          --在老版本这个参数(models.CASCADE)是默认值
    
    owner=models.ForeignKey(UserProfile,on_delete=models.CASCADE)    --在老版本这个参数(models.CASCADE)是默认值
    
     
    
    参数说明:
    
    on_delete有CASCADE、PROTECT、SET_NULL、SET_DEFAULT、SET()五个可选择的值
    
    CASCADE:此值设置,是级联删除。
    
    PROTECT:此值设置,是会报完整性错误。
    
    SET_NULL:此值设置,会把外键设置为null,前提是允许为null。
    
    SET_DEFAULT:此值设置,会把设置为外键的默认值。
    
    SET():此值设置,会调用外面的值,可以是一个函数。
    2.0 必加on_delete
    staff_member = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        limit_choices_to={'is_staff': True},
    )
    
    # 或者利用函数
    def limit_pub_date_choices():
        return {'pub_date__lte': datetime.date.utcnow()}
    
    limit_choices_to = limit_pub_date_choices
    limit_choices_to
    ForeignKey.related_name 反向查找的时候用,如果不想反向查找用+
    related_name = "+"
    
    ForeignKey.related_query_name 是用下划线反向查找的时候用的名字
    related_name

    to_field 默认是被连接表的pk,如果要指定该字段一定加unique约束

    ForeignKey.db_constraint = True/ False 是否真的要在表上建立约束

    ForeignKey.swappable

    1.3 多对多关系

    class Article(models.Model):
        classification = models.ManyToManyField("Classif")  #可以直接写多对多关联另一张表,无需自己创建。
        tags = models.ManyToManyField(
            to="Tag",
            through='Article2Tag',
            through_fields=('article', 'tag'),  #中介模型,这种方式允许自定义多对多表,并添加自己需要的字段
        )
    
    class Classif(models.Model):
        ....
    class Tag(models.Model):
        ....
    
    class Article2Tag(models.Model):  #通过该表自定义多对多表
        article = models.ForeignKey(verbose_name='文章', to="Article", to_field='nid')
        tag = models.ForeignKey(verbose_name='标签', to="Tag", to_field='nid')
        OneMoreThing = models.CharField(max_length = 40)  #添加额外字段


    app直接用 'app名.类名' 
    hostuser = models.ForeignKey('usermanage.UserInfoTb')
     
    class Person(models.Model):
        name = models.CharField(max_length=50)
    
    class Group(models.Model):
        name = models.CharField(max_length=128)
        members = models.ManyToManyField(
            Person,
            through='Membership',
            through_fields=('group', 'person'),
        )
    
    class Membership(models.Model):
        group = models.ForeignKey(Group, on_delete=models.CASCADE)
        person = models.ForeignKey(Person, on_delete=models.CASCADE)
        inviter = models.ForeignKey(
            Person,
            on_delete=models.CASCADE,
            related_name="membership_invites",
        )
        invite_reason = models.CharField(max_length=64)
    through属性手动建立中间表

    ManyToManyField.db_table  在自动创建的情况下,用来指定中间表的表名。

     

    1.4 关于Class Meta

    abstract = True 表是否是虚拟表,如果为虚拟表可以用来继承但是不会生成数据库

    app_label = 'myapp'  如果在APP_INSTALLED外就要声明一下

    db_table  表名

    db_tablespace 表空间

    default_related_name 反向关联的名称,会一并把related_query_name更改

    class Question(models.Model):
        text = models.TextField()
        # ...
    
    class Answer(models.Model):
        question = models.ForeignKey(Question, on_delete=models.CASCADE)
        # ...
    
        class Meta:
            order_with_respect_to = 'question'
    
    # For example, if an Answer relates to a Question object, and a question has more than one answer, and the order of answers matters, you’d do this:
    order_with_respect_to

    Options.ordering 表查的时候的顺序例如ordering = ['-pub_date', 'author'] “-” 代表降序 或者ordering = [F('author').asc(nulls_last=True)]

    Options.indexes 主键

        class Meta:
            indexes = [
                models.Index(fields=['last_name', 'first_name']),
                models.Index(fields=['first_name'], name='first_name_idx'),
            ]
    index示例

    unique_togetherindex_together 联合索引

    class Article2Tag(models.Model):
        nid = models.AutoField(primary_key=True)
        article = models.ForeignKey(verbose_name='文章', to="Article", to_field='nid')
        tag = models.ForeignKey(verbose_name='标签', to="Tag", to_field='nid')
    
        class Meta:
            unique_together = [
                ('article', 'tag'),
            ]
    联合索引示例

    default_permissions 默认有('add', 'change', 'delete')

    permissions 添加除了增删改之外的权限

    permissions = (("can_deliver_pizzas", "Can deliver pizzas"),)
    This is a list or tuple of 2-tuples in the format (permission_code, human_readable_permission_name).
    
    # 吐槽一下官方这示例
    permission示例

     更多关于:FieldAPI:https://docs.djangoproject.com/en/2.0/ref/models/fields/#field-api-reference

     

    1.5 Manager对象

    from django.db import models
    
    class PollManager(models.Manager):
        def with_counts(self):
            from django.db import connection
            with connection.cursor() as cursor:
                cursor.execute("""
                    SELECT p.id, p.question, p.poll_date, COUNT(*)
                    FROM polls_opinionpoll p, polls_response r
                    WHERE p.id = r.poll_id
                    GROUP BY p.id, p.question, p.poll_date
                    ORDER BY p.poll_date DESC""")
                result_list = []
                for row in cursor.fetchall():
                    p = self.model(id=row[0], question=row[1], poll_date=row[2])
                    p.num_responses = row[3]
                    result_list.append(p)
            return result_list
    
    class OpinionPoll(models.Model):
        question = models.CharField(max_length=200)
        poll_date = models.DateField()
        objects = PollManager()
    
    可以通过OpinionPoll.objects.with_counts()访问返回列表
    自定义manager连接
    class DahlBookManager(models.Manager):
        def get_queryset(self):
            return super().get_queryset().filter(author='Roald Dahl')
    
    class Book(models.Model):
        title = models.CharField(max_length=100)
        author = models.CharField(max_length=50)
    
        objects = models.Manager() # The default manager. 这个是默认的就有
        dahl_objects = DahlBookManager() # The Dahl-specific manager. 这个是定制的
    
    # 平常用的就是隐形的Book.objects.all() 这里的objects就是这个
    对queryset修改
    class AuthorManager(models.Manager):
        def get_queryset(self):
            return super().get_queryset().filter(role='A')
    
    class EditorManager(models.Manager):
        def get_queryset(self):
            return super().get_queryset().filter(role='E')
    
    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        last_name = models.CharField(max_length=50)
        role = models.CharField(max_length=1, choices=(('A', _('Author')), ('E', _('Editor'))))
        people = models.Manager()
        authors = AuthorManager()
        editors = EditorManager()
    一个表中manager对象可以多个

    默认manager:

    Django interprets the first Manager defined in a class as the “default” Manager, and several parts of Django (including dumpdata) will use that Manager exclusively for that model.

    要指定default的话用Meta.default_manager_name,更深入的定制应定制Model._base_manager方法

    class PersonQuerySet(models.QuerySet):
        def authors(self):
            return self.filter(role='A')
    
        def editors(self):
            return self.filter(role='E')
    
    class PersonManager(models.Manager):
        def get_queryset(self):
            return PersonQuerySet(self.model, using=self._db)
    
        def authors(self):
            return self.get_queryset().authors()
    
        def editors(self):
            return self.get_queryset().editors()
    
    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        last_name = models.CharField(max_length=50)
        role = models.CharField(max_length=1, choices=(('A', _('Author')), ('E', _('Editor'))))
        people = PersonManager()
    
    # 可以调用Person.people.all(), Person.people.editors(), Person.people.authors()
    # 这里可以看到manager 定义的Book.objects.all() 中的objects, queryset定义的是后面的all()
    自定义queryset
    class Manager(object):
        # Tracks each time a Manager instance is created. Used to retain order.
        creation_counter = 0
    
        def __init__(self):
            super(Manager, self).__init__()
            self._set_creation_counter()
            self.model = None
            self._inherited = False
            self._db = None
    
        ...
    
        @property
        def db(self):
            return self._db or router.db_for_read(self.model)
    
        #######################
        # PROXIES TO QUERYSET #
        #######################
    
        def get_empty_query_set(self):
            return EmptyQuerySet(self.model, using=self._db)
    
        def get_query_set(self):
            """Returns a new QuerySet object.  Subclasses can override this method
            to easily customize the behavior of the Manager.
            """
            return QuerySet(self.model, using=self._db)
    
        def none(self):
            return self.get_empty_query_set()
    
        def all(self):
            return self.get_query_set()
    
        def count(self):
            return self.get_query_set().count()
    
        def dates(self, *args, **kwargs):
            return self.get_query_set().dates(*args, **kwargs)
    
        def distinct(self, *args, **kwargs):
            return self.get_query_set().distinct(*args, **kwargs)
    
        def extra(self, *args, **kwargs):
            return self.get_query_set().extra(*args, **kwargs)
    
        def get(self, *args, **kwargs):
            return self.get_query_set().get(*args, **kwargs)
    
        def get_or_create(self, **kwargs):
            return self.get_query_set().get_or_create(**kwargs)
    
        def create(self, **kwargs):
            return self.get_query_set().create(**kwargs)
    
        def bulk_create(self, *args, **kwargs):
            return self.get_query_set().bulk_create(*args, **kwargs)
    
        def filter(self, *args, **kwargs):
            return self.get_query_set().filter(*args, **kwargs)
    
        def aggregate(self, *args, **kwargs):
            return self.get_query_set().aggregate(*args, **kwargs)
    
        def annotate(self, *args, **kwargs):
            return self.get_query_set().annotate(*args, **kwargs)
    
        def complex_filter(self, *args, **kwargs):
            return self.get_query_set().complex_filter(*args, **kwargs)
    
        def exclude(self, *args, **kwargs):
            return self.get_query_set().exclude(*args, **kwargs)
    
        def in_bulk(self, *args, **kwargs):
            return self.get_query_set().in_bulk(*args, **kwargs)
    
        def iterator(self, *args, **kwargs):
            return self.get_query_set().iterator(*args, **kwargs)
    
        def latest(self, *args, **kwargs):
            return self.get_query_set().latest(*args, **kwargs)
    
        def order_by(self, *args, **kwargs):
            return self.get_query_set().order_by(*args, **kwargs)
    
        def select_for_update(self, *args, **kwargs):
            return self.get_query_set().select_for_update(*args, **kwargs)
    
        def select_related(self, *args, **kwargs):
            return self.get_query_set().select_related(*args, **kwargs)
    
        def prefetch_related(self, *args, **kwargs):
            return self.get_query_set().prefetch_related(*args, **kwargs)
    
        def values(self, *args, **kwargs):
            return self.get_query_set().values(*args, **kwargs)
    
        def values_list(self, *args, **kwargs):
            return self.get_query_set().values_list(*args, **kwargs)
    
        def update(self, *args, **kwargs):
            return self.get_query_set().update(*args, **kwargs)
    
        def reverse(self, *args, **kwargs):
            return self.get_query_set().reverse(*args, **kwargs)
    
        def defer(self, *args, **kwargs):
            return self.get_query_set().defer(*args, **kwargs)
    
        def only(self, *args, **kwargs):
            return self.get_query_set().only(*args, **kwargs)
    
        def using(self, *args, **kwargs):
            return self.get_query_set().using(*args, **kwargs)
    
        def exists(self, *args, **kwargs):
            return self.get_query_set().exists(*args, **kwargs)
    
        def _insert(self, objs, fields, **kwargs):
            return insert_query(self.model, objs, fields, **kwargs)
    
        def _update(self, values, **kwargs):
            return self.get_query_set()._update(values, **kwargs)
    
        def raw(self, raw_query, params=None, *args, **kwargs):
            return RawQuerySet(raw_query=raw_query, model=self.model, params=params, using=self._db, *args, **kwargs)
    manager类的原码
    # as_manager:
    # Django对QuerySet提供了一个方法as_manager(),可以由QuerySet创建于该QuerySet相应的Manager。
     #    默认复制Public方法。
     #    默认不复制Private方法。
     #    方法的queryset_only属性为True则不复制,为False则复制。
    
    
    class Person(models.Model):
        ...
        people = PersonQuerySet.as_manager()
    
    
    # from_queryset
    # 可以从QuerySet映射获取Manager,同样也可以从Manager映射获取QuerySet。
    class BaseManager(models.Manager):
        def manager_only_method(self):
            return
    
    class CustomQuerySet(models.QuerySet):
        def manager_and_queryset_method(self):
            return
    
    class MyModel(models.Model):
        objects = BaseManager.from_queryset(CustomQueryset)()
    半自动定制queryset(as_manager,from_queryset)

    1.6 自定义方法

    from django.db import models
    
    class Book(models.Model):
        title = models.CharField(max_length=100)
    
        @classmethod
        def create(cls, title):
            book = cls(title=title)
            # do something with the book
            return book
    
    book = Book.create("Pride and Prejudice")
    重写类方法
    class BookManager(models.Manager):
        def create_book(self, title):
            book = self.create(title=title)
            # do something with the book
            return book
    
    class Book(models.Model):
        title = models.CharField(max_length=100)
    
        objects = BookManager()
    
    book = Book.objects.create_book("Pride and Prejudice")
    用manage对象(推荐)

     

    二、表操作——基础

    2.1 记录插入

    publish_obj=Publish(name="人民出版社",city="北京",email="renMin@163.com")
    publish_obj.save() # 将数据保存到数据库
    方式一
    publish_obj=Publish.objects.create(name="人民出版社",city="北京",email="renMin@163.com")  #返回刚创建的对象
    方式二
    Entry.objects.bulk_create([
        Entry(headline="Python 3.0 Released"), Entry(headline="Python 3.1 Planned")])
    整体插入

    多对一

    #外键值=对象
    a = A.objects.get(name=11)
    如果b中有关联a的外键aobj
    b = B.objects.create(name =22 , aobj = a) 这样就创建成功了
    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)
    多对多添加

    2.2  记录修改

    两种方法

    两种方法;
    第一种修改并保存:
    aaaa = Author.objects.get(name="aaa")
    aaaa.gender = "female"
    aaaa.save()
    
    第二种:
    queryset对象.update(gender="female")
    这里不能是get()得到的对象,只能是.filter()或者.all()得到的对象
    b = Blog.objects.get(id=1)
    b.entry_set.set([e1, e2])

    2.3 删除表记录

    Entry.objects.filter(pub_date__year=2005).delete()
    也可以是.get().delete()
    
    在 Django 删除对象时,会模仿 SQL 约束 ON DELETE CASCADE 的行为,换句话说,删除一个对象时也会删除与它相关联的外键对象。例如:
    b = Blog.objects.get(pk=1)
    # This will delete the Blog and all of its Entry objects.
    b.delete()
    
    如果不想级联删除,可以设置为:
    pubHouse = models.ForeignKey(to='Publisher', on_delete=models.SET_NULL, blank=True, null=True)

    多表:b.auther.remove(p)

    三、查

    3.1 基本查询

    Entry.objects.filter(headline__startswith='What' ).exclude(pub_date__gte=datetime.date.today()).filter(pub_date__gte=datetime.date(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)
    print([e.headline for e in Entry.objects.all()])
    print([e.pub_date for e in Entry.objects.all()])
    # 查询了两次
    queryset = Entry.objects.all()
    print([p.headline for p in queryset]) # Evaluate the query set.
    print([p.pub_date for p in queryset]) # Re-use the cache from the evaluation.
    防止重复查询
    queryset = Entry.objects.all()
    print(queryset[5]) # Queries the database
    print(queryset[5]) # Queries the database again
    
    #################################
    queryset = Entry.objects.all()
    [entry for entry in queryset] # Queries the database
    print(queryset[5]) # Uses cache
    print(queryset[5]) # Uses cache
    性能相关:充分利用缓存提高性能

    3.2 常用方法

    1. get()

    one_entry = Entry.objects.get(pk=1)

    如果查询没有结果,get() will raise a DoesNotExist exception。而filter().first()不会

    2. filter()

    3. order_by()

    4. exclude()

    5. reverse()  

      reverse() method to reverse the order in which a queryset’s elements are returned

    6. distinct()

    7. values() / values_list() 

         values 返回字典,values_list()返回列表,都支持"__"查询 e.g. Entry.objects.values('blog_id')

      note:  that you can call filter(), order_by(), etc. after the values() call

    8. date()/ datetime()

      对dateField或者DatetimeField()字段使用,返回该字段按制定时间分类的datetime.date或datetime.datetime对象列表。

    >>> Entry.objects.dates('pub_date', 'day')
    [datetime.date(2005, 2, 20), datetime.date(2005, 3, 20)]

    9. Union,intersection,difference

    并,交,区别

    >>> qs1 = Author.objects.values_list('name')
    >>> qs2 = Entry.objects.values_list('headline')
    >>> qs1.union(qs2).order_by('name')
    
    qs1.intersection(qs2, qs3)
    
    
    qs1.difference(qs2, qs3)
    # Uses SQL’s EXCEPT operator to keep only elements present in the QuerySet but not in some other QuerySets.
    示例

    10. defer only

    defer 是当有很多表中有很多字段的时候延迟搜索,only代表相反操作

    defer返回的是QuerySet对象,使用了defer后,还可以结合QuerySet其他的函数,让整个语句结合更多的条件;如果取博客的文章列表,让容量很大的正文和副标题在数据库层不进行检索,看看代码:Blog.objects.defer("content", "subtitle")

    only是defer的相反操作,注意,在进行了only操作后其他字段全部是defer

    11. select_for_update 锁

    transaction的锁操作。

    参数nowait=True 当锁在其他事务手中的时候,是否阻塞。如果另一个事务是互斥锁需要skip_locked=True,默认情况下连表查询的相关行都会锁住,通过of=(。。)来定制是否锁住相关表。

    You can’t use select_for_update() on nullable relation.

    12. get_or_create()

    try:
        obj = Person.objects.get(first_name='John', last_name='Lennon')
    except Person.DoesNotExist:
        obj = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9))
        obj.save()
    
    ######## 用get or create 改写######
    obj, created = Person.objects.get_or_create(
        first_name='John',
        last_name='Lennon',
        defaults={'birthday': date(1940, 10, 9)},
    )
    
    
    
    
    
    ###########################################
    defaults = {'first_name': 'Bob'}
    try:
        obj = Person.objects.get(first_name='John', last_name='Lennon')
        for key, value in defaults.items():
            setattr(obj, key, value)
        obj.save()
    except Person.DoesNotExist:
        new_values = {'first_name': 'John', 'last_name': 'Lennon'}
        new_values.update(defaults)
        obj = Person(**new_values)
        obj.save()
    
    ###########update or create 改写##########
    obj, created = Person.objects.update_or_create(
        first_name='John', last_name='Lennon',
        defaults={'first_name': 'Bob'},
    )
    get_or_create/update_or_create

    3.3 切片

    切片的作用是实现sql中的limit操作

    Entry.objects.all()[5:10]
    Entry.objects.all()[:10:2]

    3.4其他方法

    1. count()

    Entry.objects.filter(headline__contains='Lennon').count() 注意这种方式必len(QuerySet)高效

    2. in_bulk()

    形成一个字典{unique名:queryset}的形式。默认是pk

    >>> Blog.objects.in_bulk([1])
    {1: <Blog: Beatles Blog>}
    >>> Blog.objects.in_bulk([1, 2])
    {1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>}
    >>> Blog.objects.in_bulk([])
    {}
    >>> Blog.objects.in_bulk()
    {1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>, 3: <Blog: Django Weblog>}
    >>> Blog.objects.in_bulk(['beatles_blog'], field_name='slug')
    {'beatles_blog': <Blog: Beatles Blog>}

    in_bulk

    3. iterator

    正常情况下,queryset是产生缓存的,以便后续的重复查找。但是对于大数据比较费内存,但是只用一次的查询操作用iterator。

    iterator() will read results directly, without doing any caching at the QuerySet level (internally, the default iterator calls iterator() and caches the return value).

    根据数据库的不同,query results will either be loaded all at once or streamed from the database using server-side cursors. Oracle 和 Postgres是用后者。

    4. latest/ earliest

    Entry.objects.latest('pub_date')
    Entry.objects.latest('pub_date', '-expire_date') 当pub_date相同的时候用expire_date的最新
    latest('-date') 和 earliest('date')相同

    5. first()/last()

    6. exists()是否存在

    3.5  查询'__'方法

    1. exact

    如果查询没有写__方法,默认是exact方法例如Entry.objects.get(headline__exact="Cat bites dog")Entry.objects.get(headline="Cat bites dog")

    2. iexact

    大小写不敏感的exact

    3. contains,startwith,endwith

      Entry.objects.get(headline__contains='Lennon')SELECT ... WHERE headline LIKE '%Lennon%';

      istartwith,iendwith,icontains 为大小写不敏感模式。

    4.  isnull 为空

      e.g.  Blog.objects.filter(entry__authors__isnull=False, entry__authors__name__isnull=True)

    5. gt, lt, gte, lte  > | < |  >= |  <=

    6. in e.g. Blog.objects.filter(pk__in=[1,4,7])

    7. range

      代表sql中的between...and;   e.g.  Entry.objects.filter(pub_date__range=(start_date, end_date))

    8. 关于时间:date; year; month; day; week; week_day; quarter; hour; minute; sesond;

    9. isnull 

      e.g. Entry.objects.filter(pub_date__isnull=True)

    10. regex iregex 

      e.g. Entry.objects.get(title__regex=r'^(An?|The) +')

     

    3.6 F函数

    用以实现字段数值变常量作为查询条件的查询

    Book.objects.filter(commnetNum__lt=F('keepNum'))
    Book.objects.filter(commnetNum__lt=F('keepNum')*2)
    Book.objects.all().update(price=F("price")+30) 

    The F() objects 支持位运算 .bitand(), .bitor(), .bitrightshift(), and .bitleftshift(). 例如 F('somefield').bitand(16)

    3.7 Q函数

    用以实现or ,not 等复杂的逻辑条件操作

    from django.db.models import Q
    bookList=Book.objects.filter(Q(authors__name="yuan")|Q(authors__name="egon"))
    
    #你可以组合& 和|  操作符以及使用括号进行分组来编写任意复杂的Q 对象。同时,Q 对象可以使用~ 操作符取反,这允许组合正常的查询和取反(NOT) 查询:
    bookList=Book.objects.filter(Q(authors__name="yuan") & ~Q(publishDate__year=2017)).values_list("title")

    3.8 Annotate()&Aggregate()

     这两个函数很像,前一个是返回包括注解值的queryset,后一个只返回结果

    q = Blog.objects.annotate(Count('entry'))
    >>> q[0].name
    'Blogasaurus'
    >>> q[0].entry__count
    42
    ## 也可以指定名称
    >>> q = Blog.objects.annotate(number_of_entries=Count('entry'))
    # The number of entries on the first blog, using the name provided
    >>> q[0].number_of_entries
    42
    >>> q = Blog.objects.aggregate(number_of_entries=Count('entry'))
    {'number_of_entries': 16}

     常用聚合函数:max, min, avg, count, stddev, sum, variance

    from django.db.models import Aggregate
    
    class Count(Aggregate):
        # supports COUNT(distinct field)
        function = 'COUNT'
        template = '%(function)s(%(distinct)s%(expressions)s)'
    
        def __init__(self, expression, distinct=False, **extra):
            super().__init__(
                expression,
                distinct='DISTINCT ' if distinct else '',
                output_field=IntegerField(),
                **extra
            )
    建立自己的聚合函数

    3.9 Select_related & prefetch_related

    select_related

    select_related实现join
    性能优化:select_related实现缓存

     其他: Chaining select_related calls works in a similar way to other methods - that is that select_related('foo', 'bar') is equivalent to select_related('foo').select_related('bar'). 如果要拿到所有的foreignkey可以select_related中不传参数,但是不推荐。depth参数设置递归深度

    详解:https://blog.csdn.net/cugbabybear/article/details/38342793

    prefetch_related

    prefetch_related()和select_related()的设计目的很相似,都是为了减少SQL查询的数量,但是实现的方式不一样。后者是通过JOIN语句,在SQL查询内解决问题。但是对于多对多关系,使用SQL语句解决就显得有些不太明智,因为JOIN得到的表将会很长,会导致SQL语句运行时间的增加和内存占用的增加。prefetch_related()的解决方法是,分别查询每个表,然后用Python处理他们之间的关系。例如 Restaurant.objects.prefetch_related('best_pizza__toppings'prefetch_related的主要实现方式是in操作

    详解: https://blog.csdn.net/cugbabybear/article/details/38362489

    四、其他

    4.1 事务

    from django.db import transaction
    
    with transaction.atomic():
        orm operations...

     

    4.2 实例对象的比较

    比较的是primary key

    >>> some_entry == other_entry 等同于 >>> some_entry.pk == other_entry.pk

    4.3 原生sql

    1. extra

    主要用来实现复杂的条件查询

    >>> qs.extra(
    ...     select={'val': "select col from sometable where othercol = %s"},
    ...     select_params=(someparam,),
    ... )
    
    >>> qs.annotate(val=RawSQL("select col from sometable where othercol = %s", (someparam,)))
    
    
    
    Blog.objects.extra(
        select={
            'entry_count': 'SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id'
        },
    )
    
    SELECT blog_blog.*, (SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id) AS entry_count
    FROM blog_blog;
    
    
    
    ##### where #####
    Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
    
    #SELECT * FROM blog_entry WHERE (foo='a' OR bar='a') AND (baz='a')

    2. raw()

    执行原生sql

    更多参考:https://docs.djangoproject.com/en/2.0/topics/db/sql/

    4.4  expression

    https://docs.djangoproject.com/en/2.0/ref/models/expressions/

     

    4.5 惰性QuerySet

    只有以下对Queryset的操作会进行查询

    Iteration

    Slicing

    Pickle/Caching

    repr

    len

    list

    bool

  • 相关阅读:
    UIWebView的高度不对问题
    SQL --分组【Group By】
    SQL--Order By
    SQL--空值处理
    SQ--模糊查询
    SQL 聚合函数
    SQL 语句的TOP,Distinct语句
    SQL约束
    1 翻译系列:什么是Code First(EF 6 Code First 系列)
    终极版:由简单工厂模式,升级到抽象工厂模式(用到反射)
  • 原文地址:https://www.cnblogs.com/yxi-liu/p/djangorm.html
Copyright © 2011-2022 走看看