Django(Python框架):Django模型设计与数据库操作_第1页
Django(Python框架):Django模型设计与数据库操作_第2页
Django(Python框架):Django模型设计与数据库操作_第3页
Django(Python框架):Django模型设计与数据库操作_第4页
Django(Python框架):Django模型设计与数据库操作_第5页
已阅读5页,还剩12页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Django(Python框架):Django模型设计与数据库操作1Django模型基础1.1模型字段类型在Django中,模型字段类型是定义数据库表结构的关键。每种字段类型都有其特定的用途和属性,下面是一些常见的字段类型:CharField:用于存储固定长度的字符串,如姓名、地址等。需要指定max_length参数。TextField:用于存储长文本,如文章内容。没有长度限制。IntegerField:存储整数。FloatField:存储浮点数。BooleanField:存储布尔值,True或False。DateTimeField:存储日期和时间。ForeignKey:定义与其他模型的一对多关系。OneToOneField:定义与其他模型的一对一关系。ManyToManyField:定义与其他模型的多对多关系。1.1.1示例代码fromdjango.dbimportmodels

classAuthor(models.Model):

name=models.CharField(max_length=100)

bio=models.TextField()

birth_date=models.DateField()

classBook(models.Model):

title=models.CharField(max_length=200)

author=models.ForeignKey(Author,on_delete=models.CASCADE)

publication_date=models.DateField()

price=models.FloatField()在这个例子中,Author模型包含姓名、简介和出生日期字段,而Book模型包含标题、作者(与Author模型的外键关系)、出版日期和价格字段。1.2模型字段选项模型字段选项允许你进一步定制字段的行为,例如设置默认值、是否允许空值、字段的唯一性等。以下是一些常用的字段选项:null:是否允许数据库字段为NULL。blank:是否允许表单字段为空。default:字段的默认值。unique:字段是否必须是唯一的。choices:字段的可选值列表。help_text:在表单中显示的字段帮助文本。1.2.1示例代码fromdjango.dbimportmodels

classCategory(models.Model):

name=models.CharField(max_length=50,unique=True)

description=models.TextField(blank=True,null=True)

classProduct(models.Model):

name=models.CharField(max_length=100)

price=models.FloatField(default=0.0)

category=models.ForeignKey(Category,on_delete=models.CASCADE)

stock=models.IntegerField(default=0)在这个例子中,Category模型的name字段被设置为唯一,而description字段允许为空和空字符串。Product模型的price和stock字段有默认值。1.3模型关系Django支持多种模型间的关系,包括一对一、一对多和多对多关系。这些关系通过特定的字段类型来定义。1.3.1示例代码fromdjango.dbimportmodels

classProfile(models.Model):

user=models.OneToOneField(User,on_delete=models.CASCADE)

bio=models.TextField()

classPost(models.Model):

author=models.ForeignKey(User,on_delete=models.CASCADE)

title=models.CharField(max_length=200)

content=models.TextField()

classTag(models.Model):

name=models.CharField(max_length=50)

posts=models.ManyToManyField(Post)在这个例子中,Profile模型与User模型是一对一关系,Post模型与User模型是一对多关系,而Tag模型与Post模型是多对多关系。1.4模型方法模型方法可以添加额外的功能,如自定义保存方法、计算属性等。下面是一个自定义保存方法的例子:1.4.1示例代码fromdjango.dbimportmodels

classBook(models.Model):

title=models.CharField(max_length=200)

author=models.CharField(max_length=100)

publication_date=models.DateField()

defsave(self,*args,**kwargs):

#在保存前执行一些逻辑,例如检查标题是否为空

ifnotself.title:

raiseValueError("Titlecannotbeempty")

super().save(*args,**kwargs)

def__str__(self):

returnf"{self.title}by{self.author}"在这个例子中,Book模型有一个自定义的save方法,用于在保存前检查标题是否为空。同时,__str__方法被重写,以便在管理界面中更友好地显示模型实例。以上就是Django模型设计与数据库操作的基础内容,通过这些知识,你可以开始构建复杂的数据模型,并有效地与数据库进行交互。2模型设计最佳实践2.1数据规范化数据规范化是数据库设计中的一个关键步骤,旨在减少数据冗余和提高数据完整性。在Django中,通过合理设计模型字段和关系,可以实现数据的规范化。2.1.1示例:避免冗余字段假设我们有以下两个模型,分别代表Department(部门)和Employee(员工):fromdjango.dbimportmodels

classDepartment(models.Model):

name=models.CharField(max_length=100)

location=models.CharField(max_length=100)

classEmployee(models.Model):

name=models.CharField(max_length=100)

department_name=models.CharField(max_length=100)#冗余字段

department_location=models.CharField(max_length=100)#冗余字段

position=models.CharField(max_length=100)这里,Employee模型中的department_name和department_location字段是冗余的,因为这些信息已经存储在Department模型中。更好的设计是使用外键关系:fromdjango.dbimportmodels

classDepartment(models.Model):

name=models.CharField(max_length=100)

location=models.CharField(max_length=100)

classEmployee(models.Model):

department=models.ForeignKey(Department,on_delete=models.CASCADE)

name=models.CharField(max_length=100)

position=models.CharField(max_length=100)这样,每个员工都关联到一个部门,避免了数据的重复存储,提高了数据的一致性和完整性。2.2使用抽象基类抽象基类在Django模型中用于定义一组通用字段,这些字段可以被多个模型继承,而不会创建额外的数据库表。2.2.1示例:通用信息模型假设我们有多个模型,如Article、Comment和User,它们都需要包含创建时间和更新时间的字段。我们可以创建一个抽象基类TimestampedModel:fromdjango.dbimportmodels

fromdjango.utilsimporttimezone

classTimestampedModel(models.Model):

created_at=models.DateTimeField(auto_now_add=True)

updated_at=models.DateTimeField(auto_now=True)

classMeta:

abstract=True然后,其他模型可以继承这个抽象基类:classArticle(TimestampedModel):

title=models.CharField(max_length=200)

content=models.TextField()

classComment(TimestampedModel):

text=models.CharField(max_length=200)

article=models.ForeignKey(Article,on_delete=models.CASCADE)

classUser(TimestampedModel):

username=models.CharField(max_length=50)

email=models.EmailField()这样,Article、Comment和User模型都将自动包含created_at和updated_at字段,而无需为这些字段创建额外的数据库表。2.3模型继承Django模型可以继承自其他模型,这允许我们创建具有共同属性的模型基类,然后由具体模型继承这些属性。2.3.1示例:员工与经理模型假设我们想要创建一个Manager模型,它继承自Employee模型,但添加了额外的managed_department字段:fromdjango.dbimportmodels

classEmployee(models.Model):

name=models.CharField(max_length=100)

department=models.ForeignKey(Department,on_delete=models.CASCADE)

position=models.CharField(max_length=100)

classManager(Employee):

managed_department=models.ForeignKey(Department,on_delete=models.CASCADE,related_name='managers')这里,Manager模型继承了Employee模型的所有字段,并添加了managed_department字段。在数据库中,Manager将被视为Employee的一个子类,而不会创建一个额外的表。2.4模型信号Django的信号允许模型在某些操作(如创建、更新或删除)时触发事件。这可以用于执行额外的逻辑,如更新相关数据或发送通知。2.4.1示例:员工入职通知假设我们想要在员工创建时发送一个通知。我们可以使用post_save信号来实现:fromdjango.dbimportmodels

fromdjango.dispatchimportreceiver

fromdjango.core.mailimportsend_mail

classEmployee(models.Model):

name=models.CharField(max_length=100)

department=models.ForeignKey(Department,on_delete=models.CASCADE)

position=models.CharField(max_length=100)

@receiver(models.signals.post_save,sender=Employee)

defsend_employee_welcome_email(sender,instance,created,**kwargs):

ifcreated:

send_mail(

'Welcometoourcompany',

f'Dear{},\n\nWelcometoourcompany.Wearegladtohaveyouonboard.',

'from@',

[instance.email],

fail_silently=False,

)在这个例子中,send_employee_welcome_email函数是一个信号接收器,它在Employee模型的实例被创建后发送一封欢迎邮件。通过使用信号,我们可以将业务逻辑与模型操作解耦,使得代码更加模块化和可维护。以上示例展示了如何在Django中应用数据规范化、抽象基类、模型继承和模型信号,以创建更高效、更一致和更易于维护的模型设计。3数据库操作3.1查询数据在Django中,查询数据主要通过模型的objects管理器进行。objects是一个默认的管理器,可以调用各种方法来执行数据库查询。3.1.1示例代码#假设我们有一个名为Book的模型

frommyapp.modelsimportBook

#查询所有书籍

all_books=Book.objects.all()

#查询第一条数据

first_book=Book.objects.first()

#查询最后一条数据

last_book=Book.objects.last()

#查询特定id的书籍

book=Book.objects.get(id=1)

#查询特定条件的书籍

books_by_author=Book.objects.filter(author='JohnDoe')3.1.2描述all()方法返回模型的所有实例。first()和last()方法分别返回查询结果中的第一条和最后一条数据。get()方法用于获取单个对象,如果找不到或找到多个,会抛出异常。filter()方法用于根据指定的条件过滤数据。3.2过滤数据过滤数据是Django数据库操作中最常用的功能之一,它允许你根据模型字段的值来选择数据。3.2.1示例代码#查询价格在10到20之间的书籍

books_in_price_range=Book.objects.filter(price__gte=10,price__lte=20)

#查询标题包含“Python”的书籍

books_with_python=Book.objects.filter(title__contains='Python')

#查询出版日期在2020年之后的书籍

books_after_2020=Book.objects.filter(publication_date__year__gt=2020)

#查询作者为“JohnDoe”且价格低于15的书籍

books_by_john_under_15=Book.objects.filter(author='JohnDoe',price__lt=15)3.2.2描述price__gte和price__lte分别表示价格大于等于和小于等于。title__contains用于查找标题中包含特定字符串的书籍。publication_date__year__gt用于过滤出版年份大于指定值的书籍。过滤条件可以组合使用,如同时过滤作者和价格。3.3排序数据Django允许你对查询结果进行排序,可以按照升序或降序排列。3.3.1示例代码#按价格升序排序

books_sorted_by_price_asc=Book.objects.all().order_by('price')

#按价格降序排序

books_sorted_by_price_desc=Book.objects.all().order_by('-price')

#按出版日期升序排序,然后按价格降序排序

books_sorted_by_date_and_price=Book.objects.all().order_by('publication_date','-price')3.3.2描述order_by()方法用于排序,字段前加-表示降序。可以同时指定多个排序字段,Django会按照指定的顺序进行排序。3.4聚合数据聚合数据是Django中处理数据集的统计信息,如计算平均值、最大值、最小值等。3.4.1示例代码fromdjango.db.modelsimportAvg,Max,Min,Count,Sum

#计算所有书籍的平均价格

average_price=Book.objects.all().aggregate(Avg('price'))

#找到最贵的书籍的价格

max_price=Book.objects.all().aggregate(Max('price'))

#找到最便宜的书籍的价格

min_price=Book.objects.all().aggregate(Min('price'))

#计算书籍总数

total_books=Book.objects.all().aggregate(Count('id'))

#计算所有书籍的总价格

total_price=Book.objects.all().aggregate(Sum('price'))3.4.2描述aggregate()方法用于执行聚合操作,可以使用Django提供的聚合函数如Avg、Max、Min、Count和Sum。聚合函数需要指定要操作的字段,如Avg('price')计算价格的平均值。聚合操作返回一个字典,其中键是聚合函数的别名,值是计算结果。以上示例展示了如何在Django中执行基本的数据库操作,包括查询、过滤、排序和聚合数据。这些操作是构建复杂查询和数据处理任务的基础。4Django模型实例操作4.1创建实例在Django中,模型实例的创建是与数据库交互的基础。当你定义了一个模型后,可以通过实例化该模型类来创建新的数据库记录。4.1.1示例代码#models.py

fromdjango.dbimportmodels

classBook(models.Model):

title=models.CharField(max_length=100)

author=models.CharField(max_length=100)

publication_date=models.DateField()

price=models.DecimalField(max_digits=5,decimal_places=2)

#views.py

from.modelsimportBook

fromdatetimeimportdate

defcreate_book(request):

#创建一个Book实例

book=Book(title="Python编程",author="GuidovanRossum",publication_date=date(2020,1,1),price=59.99)

#保存到数据库

book.save()4.1.2描述在上述代码中,我们首先从models.py导入了Book模型。然后在views.py中,我们创建了一个Book实例,设置了其属性,如标题、作者、出版日期和价格,最后调用save()方法将这个实例保存到数据库中。4.2更新实例更新模型实例意味着修改数据库中已存在的记录。这可以通过加载实例,修改其属性,然后再次保存来实现。4.2.1示例代码#views.py

from.modelsimportBook

defupdate_book(request):

#加载Book实例

book=Book.objects.get(title="Python编程")

#修改属性

book.price=69.99

#保存更改

book.save()4.2.2描述在这个例子中,我们使用Book.objects.get()方法来从数据库中加载一个特定的Book实例。然后,我们修改了price属性,将其从59.99更新为69.99,最后再次调用save()方法来保存这些更改到数据库。4.3删除实例删除模型实例意味着从数据库中永久移除一条记录。这可以通过调用实例的delete()方法来实现。4.3.1示例代码#views.py

from.modelsimportBook

defdelete_book(request):

#加载Book实例

book=Book.objects.get(title="Python编程")

#删除实例

book.delete()4.3.2描述在删除实例的代码中,我们首先使用Book.objects.get()来加载一个特定的Book实例。然后,我们调用delete()方法来从数据库中删除这个实例。这将永久移除该记录,因此在执行此操作前应谨慎。4.4实例方法Django允许你在模型类中定义自定义方法,这些方法可以用于执行与该模型实例相关的特定操作。4.4.1示例代码#models.py

fromdjango.dbimportmodels

fromdatetimeimportdate

classBook(models.Model):

title=models.CharField(max_length=100)

author=models.CharField(max_length=100)

publication_date=models.DateField()

price=models.DecimalField(max_digits=5,decimal_places=2)

defis_recent(self):

"""检查书籍是否在最近一年内出版"""

returnself.publication_date>=date.today()-relativedelta(years=1)4.4.2描述在models.py中,我们定义了一个is_recent()方法,该方法检查书籍的publication_date属性是否在最近一年内。这可以通过比较当前日期与书籍的出版日期来实现。在实际应用中,你可能需要导入relativedelta函数,它来自dateutil.relativedelta模块,用于计算日期差。4.5总结通过上述示例,我们了解了如何在Django中创建、更新、删除模型实例,以及如何定义和使用实例方法。这些操作是Django应用中数据管理的核心部分,掌握它们对于开发功能丰富的Web应用至关重要。5高级数据库功能5.1事务管理事务管理是Django中一个重要的高级数据库功能,它确保了数据库操作的原子性、一致性、隔离性和持久性(ACID)。在Django中,你可以使用transaction.atomic()装饰器或withtransaction.atomic()上下文管理器来控制事务的边界。5.1.1示例:使用事务管理假设我们有两个模型Order和Product,我们需要在创建订单时更新产品的库存。如果库存更新失败,我们不希望订单被创建。fromdjango.dbimporttransaction

from.modelsimportOrder,Product

defcreate_order(product_id,quantity):

try:

withtransaction.atomic():

product=Product.objects.select_for_update().get(id=product_id)

ifproduct.stock<quantity:

raiseException("库存不足")

product.stock-=quantity

product.save()

order=Order.objects.create(product=product,quantity=quantity)

exceptExceptionase:

print(e)在这个例子中,我们使用transaction.atomic()上下文管理器来确保product.stock-=quantity和product.save()这两个操作在一个事务中完成。如果任何操作失败,整个事务将被回滚,确保数据的一致性。5.2数据库连接池Django默认使用数据库连接池来管理数据库连接,这可以提高应用程序的性能,尤其是在处理大量并发请求时。连接池允许应用程序重用数据库连接,而不是为每个请求创建和销毁连接。5.2.1如何配置在settings.py中,你可以通过设置CONN_MAX_AGE参数来控制连接池的连接最大年龄,超过这个时间的连接将被关闭并重新创建。DATABASES={

'default':{

'ENGINE':'django.db.backends.postgresql',

'NAME':'mydatabase',

'USER':'mydatabaseuser',

'PASSWORD':'mypassword',

'HOST':'',

'PORT':'5432',

'CONN_MAX_AGE':600,#设置连接的最大年龄为600秒

}

}5.3数据库路由Django的数据库路由功能允许你根据特定的规则将模型的读写操作路由到不同的数据库。这对于实现读写分离、数据分片等场景非常有用。5.3.1示例:定义路由规则首先,你需要在settings.py中定义多个数据库,并指定一个路由类。DATABASES={

'default':{

'ENGINE':'django.db.backends.postgresql',

'NAME':'mydatabase',

},

'slave':{

'ENGINE':'django.db.backends.postgresql',

'NAME':'mydatabase_slave',

}

}

DATABASE_ROUTERS=['myapp.routers.SlaveRouter']然后,创建一个路由类,实现db_for_read()和db_for_write()方法。#myapp/routers.py

classSlaveRouter:

defdb_for_read(self,model,**hints):

ifmodel._meta.app_label=='myapp':

return'slave'

returnNone

defdb_for_write(self,model,**hints):

ifmodel._meta.app_label=='myapp':

return'default'

returnNone在这个例子中,所有对myapp应用的模型的读操作将被路由到slave数据库,而写操作将被路由到default数据库。5.4自定义数据库后端Django允许你自定义数据库后端,以支持除了默认支持的数据库之外的其他数据库系统。自定义后端需要实现Django的数据库API,包括查询、事务管理、连接管理等。5.4.1示例:自定义后端自定义数据库后端需要创建一个新的Python包,实现base.DatabaseWrapper类。以下是一个简单的自定义后端示例,用于支持一个假设的数据库系统mydb。#mydb/backends/__init__.py

fromdjango.db.backends.base.baseimportBaseDatabaseWrapper

fromdjango.db.backends.base.featuresimportBaseDatabaseFeatures

fromdjango.db.backends.base.clientimportBaseDatabaseClient

fromdjango.db.backends.base.creationimportBaseDatabaseCreation

fromrospectionimportBaseDatabaseIntrospection

fromdjango.db.backends.base.operationsimportBaseDatabaseOperations

fromdjango.db.backends.base.schemaimportBaseDatabaseSchemaEditor

classDatabaseWrapper(BaseDatabaseWrapper):

vendor='mydb'

#实现BaseDatabaseWrapper中的所有方法

#mydb/backends/base.py

classDatabaseFeatures(BaseDatabaseFeatures):

#实现BaseDatabaseFeatures中的所有方法

classDatabaseClient(BaseDatabaseClient):

#实现BaseDatabaseClient中的所有方法

classDatabaseCreation(BaseDatabaseCreation):

#实现BaseDatabaseCreation中的所有方法

classDatabaseIntrospection(BaseDatabaseIntrospection):

#实现BaseDatabaseIntrospection中的所有方法

classDatabaseOperations(BaseDatabaseOperations):

#实现BaseDatabaseOperations中的所有方法

classDatabaseSchemaEditor(BaseDatabaseSchemaEditor):

#实现BaseDatabaseSchemaEditor中的所有方法然后,在settings.py中配置你的自定义后端。DATABASES={

'default':{

'ENGINE':'mydb.backends.mydb',

'NAME':'mydatabase',

}

}自定义后端需要实现Django数据库API的所有方法,这通常需要对目标数据库系统有深入的理解。在实际应用中,你可能需要参考Django的源代码和其他已支持的数据库后端实现来完成这个任务。6模型与表单6.1表单字段与模型字段在Django中,模型字段和表单字段虽然在功能上有所不同,但它们之间存在紧密的联系。模型字段用于定义数据库表结构,而表单字段则用于处理用户输入。理解两者之间的关系对于构建高效且用户友好的Web应用至关重要。6.1.1模型字段示例假设我们有一个User模型,用于存储用户信息:fromdjango.dbimportmodels

classUser(models.Model):

username=models.CharField(max_length=100)

email=models.EmailField()

age=models.IntegerField()6.1.2表单字段映射为了创建一个表单来处理User模型的输入,我们可以定义一个UserForm,其中的字段与模型字段相对应:fromdjangoimportforms

from.modelsimportUser

classUserForm(forms.ModelForm):

classMeta:

model=User

fields=['username','email','age']在这个例子中,User

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论