Django学习(2.2.1版本)
Posted xcxy-boke
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django学习(2.2.1版本)相关的知识,希望对你有一定的参考价值。
项目技术重难点分析:
表单提交与处理、文件的上传、session和cookie、ORM、JQuery、Ajax、json、xml、模板、后台管理、日志调试、缓存、安全。
模型层:模型是您的数据唯一而且准确的信息来源。它包含您正在储存的数据的重要字段和行为。一般来说,每一个模型都映射一个数据库表。
每各模型都是一个python的类,这些类继承 django.db.models.Model
模型类的每个属性都相当于一个数据库的字段
from django.db import models class Person(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30) ### 会映射成下面的 sql CREATE TABLE myapp_person ( "id" serial NOT NULL PRIMARY KEY, "first_name" varchar(30) NOT NULL, "last_name" varchar(30) NOT NULL );
myapp_person的名字由 app名称_class名称,id字段是一个默认字段,如果有主键则被覆盖,默认是不允许为空。
模型的使用:在setting中的INSTALLED_APPS中注册你的app名称,
INSTALLED_APPS = [ ‘django.contrib.admin‘, ‘django.contrib.auth‘, ‘django.contrib.contenttypes‘, ‘django.contrib.sessions‘, ‘django.contrib.messages‘, ‘django.contrib.staticfiles‘, ‘courses‘, # 以下4个是注册的app名称 ‘organization‘, ‘users‘, ‘captcha‘, ]
python manage.py makemigrations:相当于在该app下建立 migrations目录,并记录下你所有的关于modes.py的改动,比如0001_initial.py, 但是这个改动还没有作用到数据库文件
python manager.py migrate:将该改动作用到数据库文件,比如产生table,修改字段的类型等。
字段:
字段名备注:除了 ForeignKey
,ManyToManyField
和OneToOneField
,任何字段类型都接收一个可选的参数verbose_name
,如果未指定该参数值,Django会自动使用该字段的属性名作为该参数值,并且把下划线转换为空格。
null:字段是否为空,默认为False
blank:字段是否为空,默认为False(该注意选项对话与False
不同,null
选项仅仅是数据库层面的设置,然而blank
是涉及表单验证方面。如果一个字段设置为blank=True
,在进行表单验证时,接收的数据该字段值允许为空,而为设置blank=False
时,不允许为空。)
choices:该参数接收一个可迭代的列表或元组(基本单位为二元组)。如果指定了该参数,在实例化该模型时,该字段只能取选项列表中的值。每个二元组的第一个值会储存在数据库中,而第二个值将只会用于显示作用。
from django.db import models class Person(models.Model): SHIRT_SIZES = ( (‘S‘, ‘Small‘), (‘M‘, ‘Medium‘), (‘L‘, ‘Large‘), ) name = models.CharField(max_length=60) shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES)
default:该字段的默认值。可以是一个值或者是个可调用的对象,如果是个可调用对象,每次实例化模型时都会调用该对象。
help_text:使用表单小部件显示的额外“帮助”文本。即使您的字段未在表单上使用,它也对文档很有用。
primary_key:如果设置为True
,将该字段设置为该模型的主键。
unique:如果设置为True
,这个字段必须在整个表中保持值唯一。
多对一关系:使用 django.db.models.Model.ForeignKey 类,
# Car与Manufacturer 是多对一的关系,on_delete = models.CASCADE 是联级删除 from django.db import models class Manufacturer(models.Model): # ... pass class Car(models.Model): manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE) # ...
多对多关系:建一个多对多的表,显示的写出多对多表时可以记录除2的外键的字段。
from django.db import models class Person(models.Model): name = models.CharField(max_length=128) def __str__(self): return self.name class Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField(Person, through=‘Membership‘) def __str__(self): return self.name class Membership(models.Model): person = models.ForeignKey(Person, on_delete=models.CASCADE) group = models.ForeignKey(Group, on_delete=models.CASCADE) date_joined = models.DateField() invite_reason = models.CharField(max_length=64)
Meta选项:给模型赋予元型态数据,模型的元数据是指“所有不是字段的东西”,比如排序选项,数据库表名,abstract = True表示这个模型是一个抽象基类。
from django.db import models class Ox(models.Model): horn_length = models.IntegerField() class Meta: ordering = ["horn_length"] verbose_name_plural = "oxen"
继承模式:1. 抽象基类 2. 多表继承 3. 代理模型
抽象基类:当您想要将一些公共信息放入许多其他模型时,抽象基类非常有用。你写你的基类,并把abstract=True
在元类。然后,此模型不会用于创建任何数据库表。相反,当它用作其他模型的基类时,其字段将添加到子类的字段中。(基类不会产生数据表,只会共享数据,而子类产生数据表)
from django.db import models class CommonInfo(models.Model): name = models.CharField(max_length=100) age = models.PositiveIntegerField() class Meta: abstract = True class Student(CommonInfo): home_group = models.CharField(max_length=5)
Meta继承:如果子类没有Meta方法则会继承父类的Meta,也可以扩展父类的Meta方法。
from django.db import models class CommonInfo(models.Model): # ... class Meta: abstract = True ordering = [‘name‘] class Student(CommonInfo): # ... class Meta(CommonInfo.Meta): db_table = ‘student_info‘
多表继承:每个模型对应于自己的数据库表,子类不会继承父类的Meta
from django.db import models class Place(models.Model): name = models.CharField(max_length=50) address = models.CharField(max_length=80) class Restaurant(Place): serves_hot_dogs = models.BooleanField(default=False) serves_pizza = models.BooleanField(default=False)
代理继承:你可能只想更改 model 在 Python 层的行为实现。子类和父类共同操作同一个表。
from django.db import models class Person(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30) class MyPerson(Person): class Meta: proxy = True def do_something(self): # ... pass
ORM:提供数据操作的API
######### 以下是例子中用到的模型样例
from django.db import models class Blog(models.Model): name = models.CharField(max_length=100) tagline = models.TextField() def __str__(self): return self.name class Author(models.Model): name = models.CharField(max_length=200) email = models.EmailField() def __str__(self): return self.name class Entry(models.Model): blog = models.ForeignKey(Blog, on_delete=models.CASCADE) headline = models.CharField(max_length=255) body_text = models.TextField() pub_date = models.DateField() mod_date = models.DateField() authors = models.ManyToManyField(Author) n_comments = models.IntegerField() n_pingbacks = models.IntegerField() rating = models.IntegerField() def __str__(self): return self.headline
创建并保存对象:
# 在执行 save 时不会执行数据操作
from blog.models import Blog b = Blog(name=‘Beatles Blog‘, tagline=‘All the latest Beatles news.‘) b.save() # insert 操作 b5.name = ‘New name‘ # b5是Blog的实例 b5.save() # 执行update操作
保存ForeignKey、MarytoMaryFiled字段:
更新ForeignKey字段的工作方式与保存普通字段的方式完全相同。
from blog.models import Blog, Entry entry = Entry.objects.get(pk=1) cheese_blog = Blog.objects.get(name="Cheddar Talk") entry.blog = cheese_blog entry.save()
更新MarytoMaryFiled的方式是使用add方法:
# 只增加一条数据 from blog.models import Author joe = Author.objects.create(name="Joe") entry.authors.add(joe) # 增加多条数据 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)
select:(QuerySet对象是相互独立的,可以嵌套 filter 等)
all_entries = Entry.objects.all() # 获得Entry所有对象,返回包含QuerySet对象的列表 # filter是返回包含给定条件的QuerySet对象 # exclude是返回不包含给定条件的QuerySet对象 Entry.objects.filter(pub_date__year=2006) Entry.objects.all().filter(pub_date__year=2006) Entry.objects.filter( headline__startswith=‘What‘).exclude(pub_date__gte=datetime.date.today()).filter(pub_date__gte=datetime.date(2005, 1, 30)) # get 方法与 filter 类似,但是只返回一个数据,如果有0或多条数据则会报错 one_entry = Entry.objects.get(pk=1) # limit 操作 Entry.objects.all()[:5]
跨表查找:
Entry.objects.filter(blog__name=‘Beatles Blog‘) # 正向查询 Blog.objects.filter(entry__headline__contains=‘Lennon‘) # 反向查询,使用模型的小写名称__字段名 Blog.objects.filter(entry__authors__name=‘Lennon‘) Blog.objects.filter(entry__authors__name__isnull=True) Blog.objects.filter(entry__authors__isnull=False, entry__authors__name__isnull=True) # F查询,F查询专门对对象中某列值的操作 from django.db.models import F Entry.objects.filter(n_comments__gt=F(‘n_pingbacks‘)) Entry.objects.filter(n_comments__gt=F(‘n_pingbacks‘) * 2) Entry.objects.filter(rating__lt=F(‘n_comments‘) + F(‘n_pingbacks‘)) Entry.objects.filter(authors__name=F(‘blog__name‘)) # 使用双下划线表示法来跨越F()对象中的关系 Entry.objects.filter(mod_date__gt=F(‘pub_date‘) + timedelta(days=3)) Entry.objects.filter(headline__contains=‘%‘) # 包含关系,类似like # Q查询,Q查询可以组合使用 “&”, “|” 操作符,当一个操作符是用于两个Q的对象,它产生一个新的Q对象, # Q对象可以用 “~” 操作符放在前面表示否定,也可允许否定与不否定形式的组合。Q对象可以与关键字参数查询一起使用, #不过一定要把Q对象放在关键字参数查询的前面。 Poll.objects.get(Q(question__startswith=‘Who‘),Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))) SELECT * from polls WHERE question LIKE ‘Who%‘AND (pub_date = ‘2005-05-02‘ OR pub_date = ‘2005-05-06‘) Poll.objects.get(Q(pub_date=date(2005, 5, 2)) |Q(pub_date=date(2005, 5, 6)),question__startswith=‘Who‘)
# 删除,每一个QuerySet都有delete方法,返回已删除的对象数和具有每个对象类型的删除数的字典 Entry.objects.filter(pub_date__year=2005).delete() Entry.objects.all().delete() # 更新操作 Entry.objects.filter(pub_date__year=2007).update(headline=‘Everything is the same‘) b = Blog.objects.get(pk=1) Entry.objects.all().update(blog=b) Entry.objects.select_related().filter(blog=b).update(headline=‘Everything is the same‘) Entry.objects.all().update(n_pingbacks=F(‘n_pingbacks‘) + 1) Entry.objects.update(headline=F(‘blog__name‘))
聚合函数:
from django.db import models class Author(models.Model): name = models.CharField(max_length=100) age = models.IntegerField() class Publisher(models.Model): name = models.CharField(max_length=300) class Book(models.Model): name = models.CharField(max_length=300) pages = models.IntegerField() price = models.DecimalField(max_digits=10, decimal_places=2) rating = models.FloatField() authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE) pubdate = models.DateField() class Store(models.Model): name = models.CharField(max_length=300) books = models.ManyToManyField(Book)
aggregate:aggregate是一个终结子句QuerySet
,当被调用时,返回一个key-value的字典。名称是聚合值的标识符; 该值是计算的聚合。名称将根据字段名称和聚合函数自动生成。如果要手动指定聚合值的名称,可以通过在指定聚合子句时提供该名称来执行此操作:
>>> from django.db.models import Avg >>> Book.objects.aggregate(Avg(‘price‘)) ‘price__avg‘: 34.35 >>> Book.objects.aggregate(average_price=Avg(‘price‘)) ‘average_price‘: 34.35 >>> from django.db.models import Avg, Max, Min >>> Book.objects.aggregate(Avg(‘price‘), Max(‘price‘), Min(‘price‘)) ‘price__avg‘: 34.35, ‘price__max‘: Decimal(‘81.20‘), ‘price__min‘: Decimal(‘12.99‘)
annotate:返回的是QuerySet对象,只不过多了聚合函数字段,可以与任何 filter、order_by等连用。
# Build an annotated queryset >>> from django.db.models import Count >>> q = Book.objects.annotate(Count(‘authors‘)) # Interrogate the first object in the queryset >>> q[0] <Book: The Definitive Guide to Django> >>> q[0].authors__count 2
其他:
# order by Book.objects.annotate(num_authors=Count(‘authors‘)).order_by(‘num_authors‘) # 加 - 是DESC # values,查找那列 Author.objects.values(‘name‘).annotate(average_rating=Avg(‘book__rating‘))
Manager(提供数据库查询操作的接口):默认情况下,每个模型都会默认创建一个objects属性,你也可以显示的写在模型内、重命名、增加、修改objects。
from django.db import models class Person(models.Model): #... people = models.Manager()
# First, define the Manager subclass. class DahlBookManager(models.Manager): def get_queryset(self): return super().get_queryset().filter(author=‘Roald Dahl‘) # Then hook it into the Book model explicitly. 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.
原生sql的查询:
class Person(models.Model): first_name = models.CharField(...) last_name = models.CharField(...) birth_date = models.DateField(...) >>> for p in Person.objects.raw(‘SELECT * FROM myapp_person‘): ... print(p) John Smith Jane Jones >>> first_person = Person.objects.raw(‘SELECT * FROM myapp_person‘)[0]
数据库的设置:default必须存在
不同app使用不同数据库
DATABASES = ‘default‘: ‘ENGINE‘: ‘django.db.backends.sqlite3‘, ‘NAME‘: os.path.join(BASE_DIR, ‘db.sqlite3‘), , ‘db1‘: ‘ENGINE‘: ‘django.db.backends.mysql‘, ‘NAME‘: ‘django_advanced‘, ‘HOST‘: ‘127.0.0.1‘, ‘PORT‘: ‘3306‘, ‘USER‘: ‘root‘, ‘PASSWORD‘: ‘root‘,
设置setting:
DATABASES_APPS_MAPPING = ‘polls‘: ‘default‘, ‘polls2‘: ‘db1‘, DATABASE_ROUTERS = [‘my_blog.database_app_router.DatabaseAppsRouter‘] # 路由文件的路径
路由文件:database_app_router.py
from django.conf import settings class DatabaseAppsRouter(object): def db_for_read(self, model, **hints): app_label = model._meta.app_label # 取Meta下的app_label(app名称)属性 if app_label in settings.DATABASES_APPS_MAPPING: res = settings.DATABASES_APPS_MAPPING[app_label] print(res) return res return None def db_for_write(self, model, **hints): app_label = model._meta.app_label if app_label in settings.DATABASES_APPS_MAPPING: return settings.DATABASES_APPS_MAPPING[app_label] return None def allow_relation(self, obj1, obj2, **hints): # 获取对应数据库的名字 db_obj1 = settings.DATABASES_APPS_MAPPING.get(obj1._mata.app_label) db_obj2 = settings.DATABASES_APPS_MAPPING.get(obj2._mata.app_label) if db_obj1 and db_obj2: if db_obj1 == db_obj2: return True else: return False return None def db_for_migrate(self, db, app_label, model_name=None, **hints): if db in settings.DATABASES_APPS_MAPPING.values(): return settings.DATABASES_APPS_MAPPING.get(app_label) == db elif app_label in settings.DATABASES_APPS_MAPPING: return False return None
同一个app下使用不同的数据库:
class Book2(models.Model): author = models.CharField(max_length=1024, blank=True, null=True) title = models.CharField(max_length=1024) class Meta: app_label = ‘polls2‘
模板(存放在 templates 文件夹):用于分割文档的表示(presentation)和数据(data)的字符串文本。模板定义了占位符(placeholders)和各种定义文档应该如何显示的基本逻辑(即模板标签,template tag)。通常,模板用来生成 html,但是 Ddjango 模板同样能够生成任何基于文本的格式。 里面是变量,% %是模板标签(需要封闭),可以是for、if等循环分支语句, | 是过滤器(linux的管道符类似)
调用:render(from django.shortcuts import render),第一个参数是resquest,第二个是模板路径,第三个是变量参数(字典)
<html> <head><title>Ordering notice</title></head> <body> <p>Dear person_name ,</p> <p>Thanks for placing an order from company . It‘s scheduled to ship on ship_date|date:"F j, Y" .</p> <p>Here are the items you‘ve ordered:</p> <ul> % for item in item_list % <li> item </li> % endfor % </ul> % if ordered_warranty % <p>Your warranty information will be included in the packaging.</p> % endif % <p>Sincerely,<br /> company </p> </body> </html>
以上是关于Django学习(2.2.1版本)的主要内容,如果未能解决你的问题,请参考以下文章