Python之路,Day15 - Django适当进阶篇
Python之路,Day15 - Django适当进阶篇
本节内容
学员管理系统练习
Django ORM操作进阶
用户认证
Django练习小项目:学员管理系统设计开发
带着项目需求学习是最有趣和效率最高的,今天就来基于下面的需求来继续学习Django
项目需求:
1.分讲师\学员\课程顾问角色,
2.学员可以属于多个班级,学员成绩按课程分别统计
3.每个班级至少包含一个或多个讲师
4.一个学员要有状态转化的过程 ,比如未报名前,报名后,毕业老学员
5.客户要有咨询纪录, 后续的定期跟踪纪录也要保存
6.每个学员的所有上课出勤情况\学习成绩都要保存
7.学校可以有分校区,默认每个校区的员工只能查看和管理自己校区的学员
8.客户咨询要区分来源

#_*_coding:utf-8_*_
from django.db import models # Create your models here.
from django.core.exceptions import ValidationError from django.db import models
from django.contrib.auth.models import User class_type_choices= (('online',u'网络班'),
('offline_weekend',u'面授班(周末)',),
('offline_fulltime',u'面授班(脱产)',),
)
class UserProfile(models.Model):
user = models.OneToOneField(User)
name = models.CharField(u"姓名",max_length=32)
def __unicode__(self):
return self.name class School(models.Model):
name = models.CharField(u"校区名称",max_length=64,unique=True)
addr = models.CharField(u"地址",max_length=128)
staffs = models.ManyToManyField('UserProfile',blank=True)
def __unicode__(self):
return self.name class Course(models.Model):
name = models.CharField(u"课程名称",max_length=128,unique=True)
price = models.IntegerField(u"面授价格")
online_price = models.IntegerField(u"网络班价格")
brief = models.TextField(u"课程简介")
def __unicode__(self):
return self.name class ClassList(models.Model):
course = models.ForeignKey('Course')
course_type = models.CharField(u"课程类型",choices=class_type_choices,max_length=32)
semester = models.IntegerField(u"学期")
start_date = models.DateField(u"开班日期")
graduate_date = models.DateField(u"结业日期",blank=True,null=True)
teachers = models.ManyToManyField(UserProfile,verbose_name=u"讲师") #def __unicode__(self):
# return "%s(%s)" %(self.course.name,self.course_type) class Meta:
verbose_name = u'班级列表'
verbose_name_plural = u"班级列表"
unique_together = ("course","course_type","semester") class Customer(models.Model):
qq = models.CharField(u"QQ号",max_length=64,unique=True)
name = models.CharField(u"姓名",max_length=32,blank=True,null=True)
phone = models.BigIntegerField(u'手机号',blank=True,null=True)
stu_id = models.CharField(u"学号",blank=True,null=True,max_length=64)
#id = models.CharField(u"身份证号",blank=True,null=True,max_length=128)
source_type = (('qq',u"qq群"),
('referral',u"内部转介绍"),
('51cto',u"51cto"),
('agent',u"招生代理"),
('others',u"其它"),
)
source = models.CharField(u'客户来源',max_length=64, choices=source_type,default='qq')
referral_from = models.ForeignKey('self',verbose_name=u"转介绍自学员",help_text=u"若此客户是转介绍自内部学员,请在此处选择内部学员姓名",blank=True,null=True,related_name="internal_referral") course = models.ForeignKey(Course,verbose_name=u"咨询课程")
class_type = models.CharField(u"班级类型",max_length=64,choices=class_type_choices)
customer_note = models.TextField(u"客户咨询内容详情",help_text=u"客户咨询的大概情况,客户个人信息备注等...")
status_choices = (('signed',u"已报名"),
('unregistered',u"未报名"),
('graduated',u"已毕业"),
) status = models.CharField(u"状态",choices=status_choices,max_length=64,default=u"unregistered",help_text=u"选择客户此时的状态")
consultant = models.ForeignKey(UserProfile,verbose_name=u"课程顾问")
date = models.DateField(u"咨询日期",auto_now_add=True) class_list = models.ManyToManyField('ClassList',verbose_name=u"已报班级",blank=True) def __unicode__(self):
return "%s,%s" %(self.qq,self.name ) class ConsultRecord(models.Model):
customer = models.ForeignKey(Customer,verbose_name=u"所咨询客户")
note = models.TextField(u"跟进内容...")
status_choices = ((1,u"近期无报名计划"),
(2,u"2个月内报名"),
(3,u"1个月内报名"),
(4,u"2周内报名"),
(5,u"1周内报名"),
(6,u"2天内报名"),
(7,u"已报名"),
)
status = models.IntegerField(u"状态",choices=status_choices,help_text=u"选择客户此时的状态") consultant = models.ForeignKey(UserProfile,verbose_name=u"跟踪人")
date = models.DateField(u"跟进日期",auto_now_add=True) def __unicode__(self):
return u"%s, %s" %(self.customer,self.status) class Meta:
verbose_name = u'客户咨询跟进记录'
verbose_name_plural = u"客户咨询跟进记录" class CourseRecord(models.Model):
course = models.ForeignKey(ClassList,verbose_name=u"班级(课程)")
day_num = models.IntegerField(u"节次",help_text=u"此处填写第几节课或第几天课程...,必须为数字")
date = models.DateField(auto_now_add=True,verbose_name=u"上课日期")
teacher = models.ForeignKey(UserProfile,verbose_name=u"讲师")
def __unicode__(self):
return u"%s 第%s天" %(self.course,self.day_num)
class Meta:
verbose_name = u'上课纪录'
verbose_name_plural = u"上课纪录"
unique_together = ('course','day_num') class StudyRecord(models.Model):
course_record = models.ForeignKey(CourseRecord, verbose_name=u"第几天课程")
student = models.ForeignKey(Customer,verbose_name=u"学员")
record_choices = (('checked', u"已签到"),
('late',u"迟到"),
('noshow',u"缺勤"),
('leave_early',u"早退"),
)
record = models.CharField(u"上课纪录",choices=record_choices,default="checked",max_length=64)
score_choices = ((100, 'A+'),
(90,'A'),
(85,'B+'),
(80,'B'),
(70,'B-'),
(60,'C+'),
(50,'C'),
(40,'C-'),
(0,'D'),
(-1,'N/A'),
(-100,'COPY'),
(-1000,'FAIL'),
)
score = models.IntegerField(u"本节成绩",choices=score_choices,default=-1)
date = models.DateTimeField(auto_now_add=True)
note = models.CharField(u"备注",max_length=255,blank=True,null=True) def __unicode__(self):
return u"%s,学员:%s,纪录:%s, 成绩:%s" %(self.course_record,self.student.name,self.record,self.get_score_display()) class Meta:
verbose_name = u'学员学习纪录'
verbose_name_plural = u"学员学习纪录"
unique_together = ('course_record','student')

常用ORM操作

1 from django.db import models
2
3 class Blog(models.Model):
4 name = models.CharField(max_length=100)
5 tagline = models.TextField()
6
7 def __str__(self): # __unicode__ on Python 2
8 return self.name
9
10 class Author(models.Model):
11 name = models.CharField(max_length=50)
12 email = models.EmailField()
13
14 def __str__(self): # __unicode__ on Python 2
15 return self.name
16
17 class Entry(models.Model):
18 blog = models.ForeignKey(Blog)
19 headline = models.CharField(max_length=255)
20 body_text = models.TextField()
21 pub_date = models.DateField()
22 mod_date = models.DateField()
23 authors = models.ManyToManyField(Author)
24 n_comments = models.IntegerField()
25 n_pingbacks = models.IntegerField()
26 rating = models.IntegerField()
27
28 def __str__(self): # __unicode__ on Python 2
29 return self.headline

创建
|
1
2
3
|
>>> from blog.models import Blog>>> b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')>>> b.save() |
This performs an INSERT SQL statement behind the scenes. Django doesn’t hit the database until you explicitly call save().
The save() method has no return value.
处理带外键关联或多对多关联的对象
ForeignKey的关联
|
1
2
3
4
5
|
>>> from blog.models import Entry>>> entry = Entry.objects.get(pk=1)>>> cheese_blog = Blog.objects.get(name="Cheddar Talk")>>> entry.blog = cheese_blog>>> entry.save() |
ManyToManyField关联
|
1
2
3
|
>>> from blog.models import Author>>> joe = Author.objects.create(name="Joe")>>> entry.authors.add(joe) |
添加多个ManyToMany对象
|
1
2
3
4
5
|
>>> 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) |
查询

1 all_entries = Entry.objects.all() #查询所有
2 Entry.objects.filter(pub_date__year=2006) #查询所有pub_date为2006年的纪录
3 Entry.objects.all().filter(pub_date__year=2006) #与上面那句一样
4 >>> Entry.objects.filter( #链式查询
5 ... headline__startswith='What'
6 ... ).exclude(
7 ... pub_date__gte=datetime.date.today()
8 ... ).filter(
9 ... pub_date__gte=datetime(2005, 1, 30)
10 ... )
11
12 one_entry = Entry.objects.get(pk=1) #单条查询
13
14 Entry.objects.all()[:5] #查询前5条
15 Entry.objects.all()[5:10] #你猜
16
17 Entry.objects.order_by('headline')[0] #按headline排序取第一条
18
19 Entry.objects.filter(pub_date__lte='2006-01-01') #相当于sql语句SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01';
20
21 Entry.objects.get(headline__exact="Cat bites dog") #相当于SELECT ... WHERE headline = 'Cat bites dog';
22 Blog.objects.get(name__iexact="beatles blog") #与上面相同,只是大小写不敏感
23
24 Entry.objects.get(headline__contains='Lennon') #相当 于SELECT ... WHERE headline LIKE '%Lennon%';

#This example retrieves all Entry objects with a Blog whose name is 'Beatles Blog':
Entry.objects.filter(blog__name='Beatles Blog') Blog.objects.filter(entry__headline__contains='Lennon')
对同一表内不同的字段进行对比查询,In the examples given so far, we have constructed filters that compare the value of a model field with a constant. But what if you want to compare the value of a model field with another field on the same model?
Django provides F expressions to allow such comparisons. Instances of F() act as a reference to a model field within a query. These references can then be used in query filters to compare the values of two different fields on the same model instance.
For example, to find a list of all blog entries that have had more comments than pingbacks, we construct an F() object to reference the pingback count, and use that F() object in the query:
|
1
2
|
>>> from django.db.models import F>>> Entry.objects.filter(n_comments__gt=F('n_pingbacks')) |
Django supports the use of addition, subtraction, multiplication, division, modulo, and power arithmetic with F() objects, both with constants and with other F() objects. To find all the blog entries with more than twice as many comments as pingbacks, we modify the query:
|
1
|
>>> Entry.objects.filter(n_comments__gt=F('n_pingbacks') * 2) |
To find all the entries where the rating of the entry is less than the sum of the pingback count and comment count, we would issue the query:
|
1
|
>>> Entry.objects.filter(rating__lt=F('n_comments') + F('n_pingbacks')) |
For date and date/time fields, you can add or subtract a timedelta object. The following would return all entries that were modified more than 3 days after they were published:
|
1
2
|
>>> from datetime import timedelta>>> Entry.objects.filter(mod_date__gt=F('pub_date') + timedelta(days=3)) |
Caching and QuerySets
Each QuerySet contains a cache to minimize database access. Understanding how it works will allow you to write the most efficient code.
In a newly created QuerySet, the cache is empty. The first time a QuerySet is evaluated – and, hence, a database query happens – Django saves the query results in the QuerySet’s cache and returns the results that have been explicitly requested (e.g., the next element, if the QuerySet is being iterated over). Subsequent evaluations of the QuerySet reuse the cached results.
Keep this caching behavior in mind, because it may bite you if you don’t use your QuerySets correctly. For example, the following will create two QuerySets, evaluate them, and throw them away:
|
1
2
|
>>> print([e.headline for e in Entry.objects.all()])>>> print([e.pub_date for e in Entry.objects.all()]) |
That means the same database query will be executed twice, effectively doubling your database load. Also, there’s a possibility the two lists may not include the same database records, because an Entry may have been added or deleted in the split second between the two requests.
To avoid this problem, simply save the QuerySet and reuse it:
|
1
2
3
|
>>> queryset = Entry.objects.all()>>> print([p.headline for p in queryset]) # Evaluate the query set.>>> print([p.pub_date for p in queryset]) # Re-use the cache from the evaluation. |
When QuerySets are not cached¶
Querysets do not always cache their results. When evaluating only part of the queryset, the cache is checked, but if it is not populated then the items returned by the subsequent query are not cached. Specifically, this means that limiting the querysetusing an array slice or an index will not populate the cache.
For example, repeatedly getting a certain index in a queryset object will query the database each time:
|
1
2
3
|
>>> queryset = Entry.objects.all()>>> print queryset[5] # Queries the database>>> print queryset[5] # Queries the database again |
However, if the entire queryset has already been evaluated, the cache will be checked instead:
|
1
2
3
4
|
>>> queryset = Entry.objects.all()>>> [entry for entry in queryset] # Queries the database>>> print queryset[5] # Uses cache>>> print queryset[5] # Uses cache |
Complex lookups with Q objects(复杂查询)
Keyword argument queries – in filter(), etc. – are “AND”ed together. If you need to execute more complex queries (for example, queries with OR statements), you can use Q objects.
A Q object (django.db.models.Q) is an object used to encapsulate a collection of keyword arguments. These keyword arguments are specified as in “Field lookups” above.
For example, this Q object encapsulates a single LIKE query:
|
1
2
|
from django.db.models import QQ(question__startswith='What') |
Q objects can be combined using the & and | operators. When an operator is used on two Q objects, it yields a new Q object.
For example, this statement yields a single Q object that represents the “OR” of two "question__startswith" queries:
|
1
|
Q(question__startswith='Who') | Q(question__startswith='What') |
This is equivalent to the following SQL WHERE clause:
|
1
|
WHERE question LIKE 'Who%' OR question LIKE 'What%' |
You can compose statements of arbitrary complexity by combining Q objects with the & and | operators and use parenthetical grouping. Also, Q objects can be negated using the ~ operator, allowing for combined lookups that combine both a normal query and a negated (NOT) query:
|
1
|
Q(question__startswith='Who') | ~Q(pub_date__year=2005) |
Each lookup function that takes keyword-arguments (e.g. filter(), exclude(), get()) can also be passed one or more Qobjects as positional (not-named) arguments. If you provide multiple Q object arguments to a lookup function, the arguments will be “AND”ed together. For example:
|
1
2
3
4
|
Poll.objects.get( Q(question__startswith='Who'), Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))) |
... roughly translates into the SQL:
SELECT * from polls WHERE question LIKE 'Who%'
AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')
Lookup functions can mix the use of Q objects and keyword arguments. All arguments provided to a lookup function (be they keyword arguments or Q objects) are “AND”ed together. However, if a Q object is provided, it must precede the definition of any keyword arguments. For example:
|
1
2
3
|
Poll.objects.get( Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)), question__startswith='Who') |
... would be a valid query, equivalent to the previous example; but:
|
1
2
3
4
|
# INVALID QUERYPoll.objects.get( question__startswith='Who', Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))) |
... would not be valid.
更新
Updating multiple objects at once
|
1
2
|
# Update all the headlines with pub_date in 2007.Entry.objects.filter(pub_date__year=2007).update(headline='Everything is the same') |
在原有数据的基础上批量自增
Calls to update can also use F expressions to update one field based on the value of another field in the model. This is especially useful for incrementing counters based upon their current value. For example, to increment the pingback count for every entry in the blog:
|
1
|
>>> Entry.objects.all().update(n_pingbacks=F('n_pingbacks') + 1) |
However, unlike F() objects in filter and exclude clauses, you can’t introduce joins when you use F() objects in an update – you can only reference fields local to the model being updated. If you attempt to introduce a join with an F() object, a FieldErrorwill be raised:
|
1
2
|
# THIS WILL RAISE A FieldError>>> Entry.objects.update(headline=F('blog__name')) |
Aggregation(聚合)

1 from django.db import models
2
3 class Author(models.Model):
4 name = models.CharField(max_length=100)
5 age = models.IntegerField()
6
7 class Publisher(models.Model):
8 name = models.CharField(max_length=300)
9 num_awards = models.IntegerField()
10
11 class Book(models.Model):
12 name = models.CharField(max_length=300)
13 pages = models.IntegerField()
14 price = models.DecimalField(max_digits=10, decimal_places=2)
15 rating = models.FloatField()
16 authors = models.ManyToManyField(Author)
17 publisher = models.ForeignKey(Publisher)
18 pubdate = models.DateField()
19
20 class Store(models.Model):
21 name = models.CharField(max_length=300)
22 books = models.ManyToManyField(Book)
23 registered_users = models.PositiveIntegerField()


# Total number of books.
>>> Book.objects.count()
2452 # Total number of books with publisher=BaloneyPress
>>> Book.objects.filter(publisher__name='BaloneyPress').count()
73 # Average price across all books.
>>> from django.db.models import Avg
>>> Book.objects.all().aggregate(Avg('price'))
{'price__avg': 34.35} # Max price across all books.
>>> from django.db.models import Max
>>> Book.objects.all().aggregate(Max('price'))
{'price__max': Decimal('81.20')} # Cost per page
>>> Book.objects.all().aggregate(
... price_per_page=Sum(F('price')/F('pages'), output_field=FloatField()))
{'price_per_page': 0.4470664529184653} # All the following queries involve traversing the Book<->Publisher
# foreign key relationship backwards. # Each publisher, each with a count of books as a "num_books" attribute.
>>> from django.db.models import Count
>>> pubs = Publisher.objects.annotate(num_books=Count('book'))
>>> pubs
[<Publisher BaloneyPress>, <Publisher SalamiPress>, ...]
>>> pubs[0].num_books
73 # The top 5 publishers, in order by number of books.
>>> pubs = Publisher.objects.annotate(num_books=Count('book')).order_by('-num_books')[:5]
>>> pubs[0].num_books
1323

更多聚合查询例子:https://docs.djangoproject.com/en/1.9/topics/db/aggregation/
用户认证
|
1
2
3
4
5
6
7
8
9
10
11
|
from django.contrib.auth import authenticateuser = authenticate(username='john', password='secret')if user is not None: # the password verified for the user if user.is_active: print("User is valid, active and authenticated") else: print("The password is valid, but the account has been disabled!")else: # the authentication system was unable to verify the username and password print("The username and password were incorrect.") |
How to log a user out¶
|
1
2
3
4
5
|
from django.contrib.auth import logoutdef logout_view(request): logout(request) # Redirect to a success page. |
Python之路,Day15 - Django适当进阶篇的更多相关文章
- Python之路【第十七篇】:Django【进阶篇 】
Python之路[第十七篇]:Django[进阶篇 ] Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接 ...
- Python之路【第十七篇】:Django【进阶篇】
Python之路[第十七篇]:Django[进阶篇 ] Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接 ...
- Python之路,Day16 - Django 进阶
Python之路,Day16 - Django 进阶 本节内容 自定义template tags 中间件 CRSF 权限管理 分页 Django分页 https://docs.djangoproj ...
- Python之路【第十六篇】:Django【基础篇】
Python之路[第十六篇]:Django[基础篇] Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了O ...
- Python之路【第十九篇】:爬虫
Python之路[第十九篇]:爬虫 网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本.另外一些不常使用 ...
- Python之路【第十八篇】:Web框架们
Python之路[第十八篇]:Web框架们 Python的WEB框架 Bottle Bottle是一个快速.简洁.轻量级的基于WSIG的微型Web框架,此框架只由一个 .py 文件,除了Pytho ...
- Python之路【第十五篇】:Web框架
Python之路[第十五篇]:Web框架 Web框架本质 众所周知,对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端. 1 2 3 4 5 6 ...
- Python之路,Day8 - Socket编程进阶
Python之路,Day8 - Socket编程进阶 本节内容: Socket语法及相关 SocketServer实现多并发 Socket语法及相关 socket概念 socket本质上就是在2台 ...
- Python之路【第十四篇】:AngularJS --暂无内容-待更新
Python之路[第十四篇]:AngularJS --暂无内容-待更新
随机推荐
- YII Query Builder
今天遇到一个Query Builder 联合查询问题: 查询关联表某个字段的总数
- DIV+CSS外部字体引用
注意: 由于各个浏览器兼容问题大家还是少用这个,下面是具体的使用方法和效果截图: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN&qu ...
- python自动开发之第十八天
一.JS正则 test - 判断字符串是否符合规定的正则 rep = /\d+/; rep.test("asdfoiklfasdf89asdfasdf") # true rep = ...
- 怎么用notepad配置来运行C语音环境
想要运行C语言,我们可以用notepad软件来进行编辑,那么怎么用notepad 配置运行c语言开发环境呢? Notepad++是一款很好的编辑器,可以用来开发很多的工具,具体大家请看下文给大家详细讲 ...
- GC的前世与今生
GC的前世与今生 虽然本文是以.net作为目标来讲述GC,但是GC的概念并非才诞生不久.早在1958年,由鼎鼎大名的图林奖得主John McCarthy所实现的Lisp语言就已经提供了GC的功能,这是 ...
- seajs打包部署工具spm的使用总结
相信使用seajs的好处大家都是知道的,接触seajs好像是在半年前,当时还不知道页面阻塞问题,这里不带多余的话了. seajs实现了模块化的开发,一个网站如果分了很多很多模块的话,等开发完成了,发现 ...
- sublime text3入门笔记以及屏蔽sublime自动升级检测更新
两个月前学习python的时候,有人推荐这个程序员最好用的编辑器,我下载了之后,发现比notepad++要好用很多,目前来说,网上成熟的版本是sublime text2简体中文版,插件也是很兼容,我用 ...
- c# 循环语句练习题;
1. 求100以内质数的和 2. 兔子问题 3. 九九乘法表: 一行一行打印: 4. 有一张超大的纸: 纸质的厚度是0.01: 对折多少次,可以达到珠峰的高度: 按照8848来计算: ...
- 我的VSTO之路(二):VSTO程序基本知识
原文:我的VSTO之路(二):VSTO程序基本知识 开始之前,首先我介绍一下我的开发环境:VS2010 + Office 2010,是基于.Net framework 4.0和VSTO 4.0.以下的 ...
- 【HDOJ】2217 Visit
挺好的一道DP. /* 2217 */ #include <iostream> #include <cstdio> #include <cstring> #incl ...
