django orm 一对多多对一
django orm 一对多多对一
1. django orm实战
1.1. 模型类
models.py
  
from django.db import models  
# Create your models here.  
class TableTest(models.Model):  
    book_name = models.CharField(max_length=100)  
    class Meta:  
        db_table = "testtable"  
        verbose_name = '测试表'  
        verbose_name_plural = '测试表s'  
        ordering = ['book_name']  
class Book(models.Model):  
    nid = models.AutoField(primary_key=True)  
    title = models.CharField(max_length=32, default=None)  
    create_time = models.DateTimeField()  
    price = models.DecimalField(decimal_places=2, max_digits=8, default=None)  
    publish_id = models.ForeignKey(to="Publish", on_delete=models.CASCADE, null=True, blank=True)  
    authors = models.ManyToManyField(to='Author')  
    def __str__(self):  
        return str(self.nid) + ':' + self.title  
class Publish(models.Model):  
    nid = models.AutoField(primary_key=True)  
    name = models.CharField(max_length=32)  
    email = models.CharField(max_length=32)  
class Author(models.Model):  
    name = models.CharField(max_length=32)  
    age = models.IntegerField()  
    email = models.CharField(max_length=32)  
    ad = models.OneToOneField(to="AuthorDetail", on_delete=models.CASCADE)  
class AuthorDetail(models.Model):  
    address = models.CharField(max_length=32)  
    telephone = models.CharField(max_length=11)  
  
1.2. 一对一:实质也是使用外键
  
    # 模拟数据插入  
    for i in range(10):  
        name = fak.name()  
        age = random.randint(10,80)  
        email = fak.ascii_email()  
        addr = fak.address()  
        telephone = fak.phone_number()  
        print(name, age, email, telephone)  
        # continue  
        res = AuthorDetail.objects.create(address=addr, telephone=telephone)  
        Author.objects.create(name=name,  
                              age=age,  
                              email=email,  
                              # ad=res,  
                              ad_id=res.pk  
                              )  
  
注意:如果参数名为ad,值需要是对象;如果参数名为ad_id,值为int即可
级联操作体现在orm层,数据库层只有外键约束。
1.3. 多对多
  
# 模拟数据插入  
    pub_list = [i[0] for i in Publish.objects.values_list('nid')]  
    author_list = [i[0] for i in Author.objects.values_list('id')]  
    # print(pub_list, author_list)  
    for i in range(100):  
        book_name = fak.word()  
        create_time = fak.date_time()  
        price = random.uniform(10,1000)  
        publish_id = random.choice(pub_list)  
        author = random.sample(author_list, random.randint(1, len(author_list)))  
        print(publish_id, author)  
        book = Book.objects.create(  
            title=book_name,  
            create_time=create_time,  
            price=price,  
            publish_id_id=publish_id,  
        )  
        book.authors.set(author)  
  
它实质是生成dbtest_author_book表,表中三个字段,id,author_id,bok_id,后两者均为外键;
# 插入 x = Book.objects.create(title='book_1', create_time=datetime.datetime.now(), price=34, publish_id_id=21) # 无法直接对manytomany参数赋值 x.authors.add(19) x.authors.add(199) # 199超限了,数据库中查看外键约束有效,奇怪的是没有异常 x.authors.add(1,2,3,4) # 合法数据添加成功,不合法数据被忽略 x.authors.remove(2) x.authors.clear() x.authors.set(1) x.authors.set([1,2,3,4]) # 删除后重添加
1.4. 查询
  
# 一对多查询  
    # 正查  
    book = Book.objects.get(nid='1')  
    # 取到关联的对象  
    publish = book.publish_id  
    print(publish.name)  
    # 反查  
    publish = Publish.objects.get(nid='1')  
    books = publish.book_set.all()  
    # 多对多查询  
    book = Book.objects.get(nid='1')  
    authors = book.authors.all()  
    author = Author.objects.get(id='1')  
    book = author.book_set.all()  
    # 一对一  
    author = Author.objects.get(id='1')  
    ad = author.ad  
    author_detail = AuthorDetail.objects.get(id='1')  
    author = author_detail.author  
  
基于对象的跨表查询(基于子查询)
  
# 一对多查询  
    # 正查  
    book = Book.objects.get(nid='1')  
    # 取到关联的对象  
    publish = book.publish_id  
    print(publish.name)  
    # 反查  
    publish = Publish.objects.get(nid='1')  
    books = publish.book_set.all()  
    # 多对多查询  
    book = Book.objects.get(nid='1')  
    authors = book.authors.all()  
    author = Author.objects.get(id='1')  
    book = author.book_set.all()  
    # 一对一  
    author = Author.objects.get(id='1')  
    ad = author.ad  
    author_detail = AuthorDetail.objects.get(id='1')  
    author = author_detail.author  
  
基于双下划线的跨表查询(基于join实现的)
KEY:正向查询按字段,反向查询按表明小写
  
# linux这本书的出版社名字  
    # 正向  
    name = Book.objects.filter(title='linux').values('publish_id__name')  
    # 反向  
    name = Publish.objects.filter(book__title='linux').values('name')  
    # 查询第一个出版社对用的所有书  
    # 正向  
    book = Publish.objects.filter(nid='1').values('book__title')  
    # 反向  
    book = Book.objects.filter(publish_id_id='1').values('title')  
    # 查询Linux这本书所有作者的手机号  
    telephone = Book.objects.filter(title='linux').values('authors__ad__telephone')  
    telephone = Author.objects.filter(book__title='linux').values('ad__telephone')  
    # 查询id=1的出版社的作者的书籍和作者的名字  
    title_name = Publish.objects.filter(nid='1').values('book__authors__name', 'book__title')  
    title_name = Book.objects.filter(publish_id_id=1).values('title', 'authors__name')  
    # 查询作者手机号的开头为110的书籍和出版社名称  
    title_name = Author.objects.filter(ad__address__startswith='北京').values('book__title', 'book__publish_id__name')  
  
聚合和分组
  
from django.db.models import Avg, Max, Sum, Min, Count  
    avg = Book.objects.all().aggregate(price=Avg('price'))  
    # 单表分组查询  
    # 查询每个出版社id以及对应大的书籍个数  
    count = Book.objects.values('publish_id').annotate(count=Count(1))  
    # values中的值为分类的参数  
    '''  
        select Count(1) from Book GROUP by publish_id  
    '''  
    # 跨表分组查询  
    # 查看每一个出版社名称以及对应的书籍个数  
    count = Book.objects.values('publish_id__name').annotate(count=Count(1))  
    count = Publish.objects.values('name').annotate(c=Count('book__nid'))  
    # 查找作者大于一个的书籍对应的作者数  
    query = Book.objects.annotate(c=Count('authors')).filter(c__gt=1).values('c', 'title')  
  
2. 问题
2.1. 问题1
直接使用django 的models插值发现报错
django.core.exceptions.ImproperlyConfigured: Requested setting INSTALLED_APPS, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.
原因:没有添加环境
解决办法:将路径添加到环境变量中,成功解决这个问题
3. 代码
操作代码
  
import datetime  
import random  
def db_test():  
    # 环境配置  
    import django  
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dj_site.settings')  
    django.setup()  
    from dbtest.models import Publish,Book,Author,AuthorDetail,TableTest  
    # 数据操作  
    from faker import Faker  
    fak = Faker('zh-CN')  
    """  
    book_list = []  
    for i in range(100):  
        book = Book(  
            title='book_%s' % i,  
            price=i * i,  
            create_time=datetime.datetime.now())  
        book_list.append(book)  
    Book.objects.bulk_create(book_list)  
    """  
    """  
    for i in range(30):  
        pub = Publish(  
            name=fak.company()[:32],  
            email=fak.company_email()[:32]  
        )  
        pub.save()  
        print(pub)  
    """  
    """  
    # 一对一插值  
    for i in range(10):  
        name = fak.name()  
        age = random.randint(10,80)  
        email = fak.ascii_email()  
        addr = fak.address()  
        telephone = fak.phone_number()  
        print(name, age, email, telephone)  
        # continue  
        res = AuthorDetail.objects.create(address=addr, telephone=telephone)  
        Author.objects.create(name=name,  
                              age=age,  
                              email=email,  
                              # ad=res,  
                              ad_id=res.pk  
                              )  
    """  
    pub_list = [i[0] for i in Publish.objects.values_list('nid')]  
    author_list = [i[0] for i in Author.objects.values_list('id')]  
    # print(pub_list, author_list)  
    for i in range(100):  
        book_name = fak.word()  
        create_time = fak.date_time()  
        price = random.uniform(10,1000)  
        publish_id = random.choice(pub_list)  
        author = random.sample(author_list, random.randint(1, len(author_list)))  
        print(publish_id, author)  
        book = Book.objects.create(  
            title=book_name,  
            create_time=create_time,  
            price=price,  
            publish_id_id=publish_id,  
        )  
        book.authors.set(author)  
db_test()  
  
    日拱一卒无有尽,功不唐捐终入海
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号