Django之models database总结(二)

显然,关系型数据库的强大之处在于,表与表之间存在关联,Django提供了定义常见的三种类型的数据库关系的方法:many-to-one, many-to-many 和one-to-one.。

1.many-to-one

为了定义一个many-to-one的关系,使用django.db.models.ForeignKey.其中ForeignKey需要一个位置参数:model关联的类。举个例子:
如果一个Car model有一个制造商Manufacturer,就是说,一个Manufacturer制造很多cars但是呢,一个Car只有一个Manufacturer,使用下面方法定义:

from django.db import models
class Manufacturer(models.Model):
  # ...
  pass
class Car(models.Model):
  manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
  # ...

同样,你也可以创建一个递归的关系(就是说,一个对象many-to-one关系它自身),如下: models.ForeignKey(’self’, on_delete=models.CASCADE).你也可以创建一个关系,其model尚未定义,你可以使用它的model名,而不是model对象自身。如下:

from django.db import models
class Car(models.Model):
  manufacturer = models.ForeignKey(
    'Manufacturer',
    on_delete=models.CASCADE,
  )
  # ...
class Manufacturer(models.Model):
  # ...
  pass

这种技巧在多种场合下都有使用到,比如:

products/models.py
  from django.db import models
  class AbstractCar(models.Model):
    manufacturer = models.ForeignKey('Manufacturer', on_delete=models.CASCADE)

    class Meta:
      abstract = True
production/models.py
  from django.db import models
  from products.models import AbstractCar
  class Manufacturer(models.Model):
    pass
  class Car(AbstractCar):
    pass
  # Car.manufacturer will point to `production.Manufacturer` here.

为了引用定义在其他application中的model,你可以明确指定带有application标签的model.比如,如上一个制作商Manufacturer在另一个application名为production中定义,你可以这样引用:

class Car(models.Model):
  manufacturer = models.ForeignKey(
    'production.Manufacturer',
    on_delete=models.CASCADE,
  )

这种引用类型在两个application有关联时非常有用。一个数据库的索引是由ForeignKey自动创建的,你可以设置db_index的值为False来关闭这项设置。接下来,具体地看看ForeignKey类其他的一些参数:

  • ForeignKey.on_delete
    当一个被ForeignKey引用的对象删除后,django将会通过指定on_delete参数来仿真sql约束的行为。举例,假如你有一个可以为空的ForeignKey并且当引用类被删除时,你希望置空:
user = models.ForeignKey(
  User,
  models.SET_NULL,
  blank=True,
  null=True,
)

所有on_delete可能的值如下:
CASCADE,PROTECT,SET_NULL,SET_DEFAULT,SET(),DO_NOTHING

  • ForeignKey.limit_choices_to
    对该字段可用的选择设置一个限制,当该字段通过ModelForm或者admin进行渲染的时候。值为一个字段,或者Q对象。
staff_member = models.ForeignKey(
  User,
  on_delete=models.CASCADE,
    limit_choices_to={'is_staff': True},
  )
  • ForeignKey.related_name
    通过被关联的类访问自己的名称。同时也是related_query_name的默认值。注意,当定义抽象models的关联时,该值是必须要设置的。如果你不想django创建一个逆向的关联,设置该参数为'+'或者以'+'结尾。举例:
user = models.ForeignKey(
  User,
  on_delete=models.CASCADE,
  related_name='+',
)

这将确保,User model不会有一个逆向的关联到当前的model.

  • ForeignKey.related_query_name
    目标model反向过滤的名称,默认为related_name参数的值。如果related_name的值和它都没设置,该参数的默认值为model的名称.
class Tag(models.Model):
  article = models.ForeignKey(
    Article,
    on_delete=models.CASCADE,
    related_name="tags",
    related_query_name="tag",)
  name = models.CharField(max_length=255)
Article.objects.filter(tag__name="important")

Declare the ForeignKey with related_query_name,That's now the name of the reverse filter

  • ForeignKey.db_constraint
    控制是否在数据库中创建一个通外键的约束,默认值为True.设置为False,对数据库数据的完整性非常不利。如果设置为False,访问关联的类如果不存在就会报错。
    基于上述描述,举一个many-to-one相关的完整的例子:
from django.db import models
class Reporter(models.Model):
  first_name = models.CharField(max_length=30)
  last_name = models.CharField(max_length=30)
  email = models.EmailField()
  def __str__(self): # __unicode__ on Python 2
    return "%s %s" % (self.first_name, self.last_name)
class Article(models.Model):
  headline = models.CharField(max_length=100)
  pub_date = models.DateField()
  reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)
     def __str__(self): # __unicode__ on Python 2
    return self.headline
     class Meta:
    ordering = ('headline',)

具体python api接口使用的情景:

r = Reporter(first_name='John', last_name='Smith', email='[email protected]')
r.save()
r2 = Reporter(first_name='Paul', last_name='Jones', email='[email protected]')
r2.save()
from datetime import date
a = Article(id=None, headline="This is a test", pub_date=date(2005, 7, 27), reporter=r)
a.save()
a.reporter.id
1
a.reporter

r3 = Reporter(first_name='John', last_name='Smith', email='[email protected]')
Article.objects.create(headline="This is a test", pub_date=date(2005, 7, 27), reporter=r3)
Traceback (most recent call last):
...
ValueError: save() prohibited to prevent data loss due to unsaved related object 'reporter'.
new_article

new_article.reporter

new_article.reporter.id
1```

new_article2 = Article(headline="Paul's story", pub_date=date(2006, 1, 17))
r.article_set.add(new_article2)
new_article2.reporter

new_article2.reporter.id
1
r.article_set.all()
, , ]>

```r2.article_set.add(new_article2)
new_article2.reporter.id
2
new_article2.reporter
```

r.article_set.add(r2)
Traceback (most recent call last):
...
TypeError: 'Article' instance expected
r.article_set.all()
, ]>
r2.article_set.all()
]>
r.article_set.count()
2
r2.article_set.count()
1

r.article_set.filter(headline__startswith='This')
]>
Article.objects.filter(reporter__first_name='John')
, ]>
Article.objects.filter(reporter__first_name='John')
, ]>
Article.objects.filter(reporter__first_name='John', reporter__last_name='Smith')
, ]>
Article.objects.filter(reporter__pk=1)
, ]>
Article.objects.filter(reporter=1)
, ]>
Article.objects.filter(reporter=r)
, ]>
Article.objects.filter(reporter__in=[1,2]).distinct()
, , ]>
Article.objects.filter(reporter__in=[r,r2]).distinct()
, , ]>

```Article.objects.filter(reporter__in=Reporter.objects.filter(first_name='John')).distinct()
, ]>
Reporter.objects.filter(article__pk=1)
]>
Reporter.objects.filter(article=1)
]>
Reporter.objects.filter(article=a)
]>
Reporter.objects.filter(article__headline__startswith='This')
, , ]>
Reporter.objects.filter(article__headline__startswith='This').distinct()
]>
Reporter.objects.filter(article__headline__startswith='This').count()
3
Reporter.objects.filter(article__headline__startswith='This').distinct().count()
1
Reporter.objects.filter(article__reporter__first_name__startswith='John')
, , , ]>
Reporter.objects.filter(article__reporter__first_name__startswith='John').distinct()
]>
Reporter.objects.filter(article__reporter=r).distinct()
]>
Article.objects.all()
, , ]>
Reporter.objects.order_by('first_name')
, ]>
r2.delete()
Article.objects.all()
, ]>
Reporter.objects.order_by('first_name')
]>
Reporter.objects.filter(article__headline__startswith='This').delete()
Reporter.objects.all()

Article.objects.all()

你可能感兴趣的:(Django之models database总结(二))