django 查询数据

重要的事情写在前面,嵌套序列化,根据外键来查询,如果定义了related_name="name",在定义序列化器时可以使用name=序列化器名字(many=True),这是反向查询,通过定义的related_name定义的名字,在一个不相关的表中查询出所有的字段,例子:

class OrderInfo(BaseModel):
    """
    订单信息
    """
    PAY_METHODS_ENUM = {
        "CASH": 1,
        "ALIPAY": 2
    }

    PAY_METHOD_CHOICES = (
        (1, "货到付款"),
        (2, "支付宝"),
    )

    ORDER_STATUS_ENUM = {
        "UNPAID": 1,
        "UNSEND": 2,
        "UNRECEIVED": 3,
        "UNCOMMENT": 4,
        "FINISHED": 5
    }

    ORDER_STATUS_CHOICES = (
        (1, "待支付"),
        (2, "待发货"),
        (3, "待收货"),
        (4, "待评价"),
        (5, "已完成"),
        (6, "已取消"),
    )

    order_id = models.CharField(max_length=64, primary_key=True, verbose_name="订单号")
    user = models.ForeignKey(User, on_delete=models.PROTECT, verbose_name="下单用户")
    address = models.ForeignKey(Address, on_delete=models.PROTECT, verbose_name="收获地址")
    total_count = models.IntegerField(default=1, verbose_name="商品总数")
    total_amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="商品总金额")
    freight = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="运费")
    pay_method = models.SmallIntegerField(choices=PAY_METHOD_CHOICES, default=1, verbose_name="支付方式")
    status = models.SmallIntegerField(choices=ORDER_STATUS_CHOICES, default=1, verbose_name="订单状态")


    class Meta:
        db_table = "tb_order_info"
        verbose_name = '订单基本信息'
        verbose_name_plural = verbose_name


class OrderGoods(BaseModel):
    """
    订单商品
    """
    SCORE_CHOICES = (
        (0, '0分'),
        (1, '20分'),
        (2, '40分'),
        (3, '60分'),
        (4, '80分'),
        (5, '100分'),
    )
    order = models.ForeignKey(OrderInfo, related_name='skus', on_delete=models.CASCADE, verbose_name="订单")
    sku = models.ForeignKey(SKU, on_delete=models.PROTECT, verbose_name="订单商品")
    count = models.IntegerField(default=1, verbose_name="数量")
    price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="单价")
    comment = models.TextField(default="", verbose_name="评价信息")
    score = models.SmallIntegerField(choices=SCORE_CHOICES, default=5, verbose_name='满意度评分')
    is_anonymous = models.BooleanField(default=False, verbose_name='是否匿名评价')
    is_commented = models.BooleanField(default=False, verbose_name='是否评价了')

    class Meta:
        db_table = "tb_order_goods"
        verbose_name = '订单商品'
        verbose_name_plural = verbose_name

 

上面表中黄色字段,是关建字段,下面是对应的序列化器.

class OrderShowSerializer(serializers.ModelSerializer):

    sku = AASerializer()
    class Meta:
        model = OrderGoods
        fields = ('count', 'price', 'sku')

        # depth = 1


class OrderListSerializer(serializers.ModelSerializer):
    skus = OrderShowSerializer(many=True)
    create_time = serializers.DateTimeField(read_only=True,format='%Y-%m-%d %H:%M')
    class Meta:
        model = OrderInfo
        exclude = ('address',)

上面在序列化器中的定义skus字段,下面的exclude(' ')里面除了OrderInfo里面的"address"字段,其他全部返回,结果如下:

  1. results[{order_id: "20190513150156000000001", skus: [{count: 1, price: "3388.00", sku: {,…}}],…},…]
    1. 0{order_id: "20190513150156000000001", skus: [{count: 1, price: "3388.00", sku: {,…}}],…}
      1. create_time"2019-05-13 15:01"
      2. freight"10.00"
      3. order_id"20190513150156000000001"
      4. pay_method2
      5. skus[{count: 1, price: "3388.00", sku: {,…}}]
        1. 0{count: 1, price: "3388.00", sku: {,…}}
          1. count1
          2. price"3388.00"
          3. sku{,…}
      6. status1
      7. total_amount"3398.00"
      8. total_count1
      9. update_time"2019-05-13T15:01:56.670260+08:00"
      10. user1

上面是返回数据,重点在skus它有自己的属性,下面那条0{count:1.....},是因为skus可能包含多个值,每个值有自己的属性,下面就是属性了,目前是第一层嵌套.

  1. 0{order_id: "20190513150156000000001", skus: [{count: 1, price: "3388.00", sku: {,…}}],…}
    1. create_time"2019-05-13 15:01"
    2. freight"10.00"
    3. order_id"20190513150156000000001"
    4. pay_method2
    5. skus[{count: 1, price: "3388.00", sku: {,…}}]
      1. 0{count: 1, price: "3388.00", sku: {,…}}
        1. count1
        2. price"3388.00"
        3. sku{,…}
          1. default_image_url"http://image.meiduo.site:8888/group1/M00/00/02/CtM3BVrRdICAO_CRAAcPaeOqMpA2024091"
          2. name"华为 HUAWEI P10 Plus 6GB+64GB 钻雕蓝 移动联通电信4G手机 双卡双待"
          3. price"3388.00"
    6. status1
    7. total_amount"3398.00"
    8. total_count1
    9. update_time"2019-05-13T15:01:56.670260+08:00"
    10. user1
数据和上面的一样,重点在sku上,sku是第二层嵌套数据,如和打到这种效果,看上面,在序列化器中有一行紫色的代码sku = AASerializer()
这行代码的重点在于,括号里面啥都没有.
class AASerializer(serializers.ModelSerializer):

    class Meta:
        model = SKU
        fields = ('default_image_url', 'name', 'price')

上面就是那行紫色代码关联的序列化器了.中间会有有一些可能写的不是很清楚,仔细看结果.会有答案.

 

django中数据库操作——in操作符

 

django一对多关系中,为了实现按照一端查询多端,之前都是用extra操作符,经过查看官方文档还有in这个操作符,用这个实现更简单。直接上代码:

根据查询条件模糊查询所有符合条件的机架列表,然后根据机架列表查出相应的设备,之前是用下面这种实现方式:

 

[python] view plain copy
 
  1. rackid = request.POST['rackid']  
  2. retdir['rackid'] = rackid  
  3. racks = Rack.objects.filter(rackid__icontains = rackid)  
  4. ids = ""  
  5. for rack in racks:  
  6.     ids += str(rack.id) + ","  
  7. ids = ids[0:-1]  
  8. if ids == None or ids == '':  
  9.     ids = '0'  
  10. equipments = Equipment.objects.extra(where=['rack_id IN ('+ ids +')'])  


现在用in操作符,实现更简单,效率更高:

 

[python] view plain copy
 
  1. rackid = request.POST['rackid']  
  2. retdir['rackid'] = rackid  
  3. racks = Rack.objects.filter(rackid__icontains = rackid)  
  4. equipments = Equipment.objects.filter(rack__in = racks)  


其中机架跟设备是一对多的关系。

参考官方文档:

 

跨关系查找

 

Django 提供一个有力且直观的方法来“追踪”查找中的关系,即会在后台自动处理 SQL 中的 JOIN 。要跨越一个关系,只要使用跨模块的关联字段即可,并用两个下划线分隔,直到得到你想要的字段为止。

以下例子可以获得名称为 'Beatles Blog' 的 Blog 的所有条目。

>>> Entry.objects.filter(blog__name__exact='Beatles Blog')

这种跨越的深度是无限的。

跨越也可以是反向的。要指向一个“反向”的关系,请使用模型的小写名称。

下例可以获得至少一个条目的头条包含 'Lennon' 的所有Blog 对象:

>>> Blog.objects.filter(entry__headline__contains='Lennon')

如果你跨越了多重关系并且其中的一个模型没有符合条件的值,那么 Django 会把模型视作空对象(即所有值为 NULL ),而不是非法对象。因此在前述情况下不会引发错误。例如:

Blog.objects.filter(entry__authors__name='Lennon')

假设有一个相关联的 作者``( Author )模型,如果没有 ``作者 与任何一个条目关联,那么就会视作也没有名称 与之关联。这样处理比因为作者 缺失而引发错误要好。通常这也是你想要的处理方式。唯一会产生混淆的是当你使用isnull 的时候。就象下例:

Blog.objects.filter(entry__authors__name__isnull=True)

会返回包括 名字 为空的 作者 和 作者 为空的条目 两种情况的Blog 对象。如果你不希望包括后一种情况的对象,你可以这样写:

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

跨越多值关系

当你基于一个 多对多字段 对象或一个反向外键 过滤时,有两种不同的过滤方法值得注意。对于博客 与条目 关系( 博客 对于条目 是一对多关系),我们可能会想要查找一个博客,这个必须博客包括一个符合以下条件的条目:在条目的头条中包含"Lennon" 字样,并且发布日期为 2008 年。或者我们也可以会想要查找一个博客,这个博客必须符合以下条件:包含一个头条中有"Lennon" 字样的条目,并且包含一个发布日期为 2008 年的条目。因为一个博客 对应于多个条目 ,所以上述两种查询都是可能的,在特定情况下都是有用的。

同样,一个 多对多字段 也会引发类似情况。例如,假设一个条目 字段有一个名为标记 ( tags )的多对多字段。我们可以会想要查找既有"music" 标记又有"bands" 标记的条目。或者我们也可能会想要查找标记为 "music" ,状态为"public" 的条目。

对于上述两种方法, Django 中的 filter() 和exclude() 使用相同的方式来处理。在一个filter() 中的所有条件必须同时符合。在连续的filter() 中的条件对于多值关系情况下,这些条件是并列的(都对应于主模型的对象),而不是嵌套的(对应于前一个filter() 产生的对象)。

都迷糊了吧,来一个例子清醒一下。要查找一个博客,这个必须博客包括一个符合以下条件的条目:在条目的头条中包含 "Lennon" 字样,并且发布日期为 2008 年。即条目必须同时符合两个条件。我们这样写:

Blog.objects.filter(entry__headline__contains='Lennon',
        entry__pub_date__year=2008)

要查找一个博客,这个博客必须符合以下条件:包含一个头条中有 "Lennon" 字样的条目,并且包含一个发布日期为 2008 年的条目。但对于同一个条目不一定要同时符合两个条件。我们这样写:

Blog.objects.filter(entry__headline__contains='Lennon').filter(
        entry__pub_date__year=2008)

在第二个例子中,第一个过滤器限定了特定条件的博客,第二个过滤器 进一步 限定了同时符合第二个条件的博客。匹配第二个过滤器的条目不一定匹配第一个过滤器。两个过滤器的条件都是针对某个博客而言的,而不是针对某个条目而言的。

以上方式也同样用于 exclude() 。

 

数据库操作API:

 

类型描述
exact 精确匹配: polls.get_object(id__exact=14).
iexact 忽略大小写的精确匹配: polls.objects.filter(slug__iexact="foo") 匹配 fooFOOfOo, 等等.
contains 大小写敏感的内容包含测试: polls.objects.filter(question__contains="spam") 返回question 中包含 "spam" 的所有民意测验.(仅PostgreSQL 和 MySQL支持. SQLite 的LIKE 语句不支持大小写敏感特性. 对Sqlite 来说, contains 等于 icontains.)
icontains 大小写不敏感的内容包含测试:
gt 大于: polls.objects.filter(id__gt=4).
gte 大于等于.
lt 小于.
lte 小于等于.
ne 不等于.
in 位于给定列表中: polls.objects.filter(id__in=[1, 3, 4]) 返回一个 polls 列表(ID 值分别是 1或3或4).
startswith 大小写敏感的 starts-with: polls.objects.filter(question__startswith="Would"). (仅PostgreSQL 和MySQL支持. SQLite 的LIKE 语句不支持大小写敏感特性. 对Sqlite 来说,``startswith`` 等于 istartswith)
endswith 大小写敏感的 ends-with. (仅PostgreSQL 和 MySQL)
istartswith 大小写不敏感的 starts-with.
iendswith 大小写不敏感的 ends-with.
range 范围测试: polls.objects.filter(pub_date__range=(start_date, end_date)) 返回 pub_date 位于 start_date 和 end_date (包括)之间的所有民意测验
year 对 date/datetime 字段, 进行精确的  匹配: polls.get_count(pub_date__year=2005).
month 对 date/datetime 字段, 进行精确的  匹配:
day 对 date/datetime 字段, 进行精确的  匹配:
isnull True/False; 做 IF NULL/IF NOT NULL 查询: polls.objects.filter(expire_date__isnull=True).
xxxxx
class OrderInfo(BaseModel):
"""
订单信息
"""
PAY_METHODS_ENUM = {
"CASH": 1,
"ALIPAY": 2
}

PAY_METHOD_CHOICES = (
(1, "货到付款"),
(2, "支付宝"),
)

ORDER_STATUS_ENUM = {
"UNPAID": 1,
"UNSEND": 2,
"UNRECEIVED": 3,
"UNCOMMENT": 4,
"FINISHED": 5
}

ORDER_STATUS_CHOICES = (
(1, "待支付"),
(2, "待发货"),
(3, "待收货"),
(4, "待评价"),
(5, "已完成"),
(6, "已取消"),
)

order_id = models.CharField(max_length=64, primary_key=True, verbose_name="订单号")
user = models.ForeignKey(User, on_delete=models.PROTECT, verbose_name="下单用户")
address = models.ForeignKey(Address, on_delete=models.PROTECT, verbose_name="收获地址")
total_count = models.IntegerField(default=1, verbose_name="商品总数")
total_amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="商品总金额")
freight = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="运费")
pay_method = models.SmallIntegerField(choices=PAY_METHOD_CHOICES, default=1, verbose_name="支付方式")
status = models.SmallIntegerField(choices=ORDER_STATUS_CHOICES, default=1, verbose_name="订单状态")


class Meta:
db_table = "tb_order_info"
verbose_name = '订单基本信息'
verbose_name_plural = verbose_name


class OrderGoods(BaseModel):
"""
订单商品
"""
SCORE_CHOICES = (
(0, '0分'),
(1, '20分'),
(2, '40分'),
(3, '60分'),
(4, '80分'),
(5, '100分'),
)
order = models.ForeignKey(OrderInfo, related_name='skus', on_delete=models.CASCADE, verbose_name="订单")
sku = models.ForeignKey(SKU, on_delete=models.PROTECT, verbose_name="订单商品")
count = models.IntegerField(default=1, verbose_name="数量")
price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="单价")
comment = models.TextField(default="", verbose_name="评价信息")
score = models.SmallIntegerField(choices=SCORE_CHOICES, default=5, verbose_name='满意度评分')
is_anonymous = models.BooleanField(default=False, verbose_name='是否匿名评价')
is_commented = models.BooleanField(default=False, verbose_name='是否评价了')

class Meta:
db_table = "tb_order_goods"
verbose_name = '订单商品'
verbose_name_plural = verbose_name
posted @ 2019-05-18 14:10  C,python,linux,java  阅读(273)  评论(0)    收藏  举报