一、创建一个Django项目
1、使用虚拟环境
#快速创建虚拟环境 python?-m?venv?prjvenv #激活虚拟环境 source?prjvenv/bin/activate
2、创建项目
#安装django pip?install?django #创建项目 django-admin?startproject?myblog
3、django设置
myblog/settings.py文件
TIME_ZONE='Asia/Shanghai'
4、数据库迁移
python?manage.py?migrate
5、启动
python?manage.py?runserver
二、视图和URL配置
myblog/views.py文件
from?django.http?import?HttpResponse #最简单视图 def?hello(request): ????return?HttpResponse("Hello?world") #带参数的视图 def?hours_ahead(request,?offset): ???????try: ???????????offset?=?int(offset) ???????except?ValueError: ???????????raise?Http404() ???????dt?=?datetime.datetime.now()?+?datetime.timedelta(hours=offset) ???????html?=?"In?%s?hour(s),?it?will?be??%s."?%?(offset,?dt) ???????return?HttpResponse(html)
myblog/urls.py 文件
from?django.conf.urls?import?url from?django.contrib?import?admin from?myblog.views?import?hello from?mysite.views?import?hours_ahead urlpatterns?=?[ ????url(r'^admin/',?admin.site.urls), ????url(r'^hello/$',hello), ????url(r'^time/plus/(\d{1,2})/$',?hours_ahead), ?]
三、使用Django模板
1、模板目录配置
myblog/settings.py文件
TEMPLATES?=?[ ????{ ????????'BACKEND':?'django.template.backends.django.DjangoTemplates', ????????'DIRS':?['app1/templates','app2/templates'...], ????????'APP_DIRS':?True, ????????'OPTIONS':?{ ????????????'context_processors':?[ ????????????????'django.template.context_processors.debug', ????????????????'django.template.context_processors.request', ????????????????'django.contrib.auth.context_processors.auth', ????????????????'django.contrib.messages.context_processors.messages', ????????????], ????????}, ????}, ] 如果想在项目根目录中放一些主模板(例如在?mysite/templates?目录中),需要像这样设定?DIRS: 'DIRS':?[os.path.join(BASE_DIR,?'templates')],
2、视图函数
from?django.shortcuts?import?render import?datetime def?current_datetime(request): ????now?=?datetime.datetime.now() ????return?render(request,?'current_datetime.html',?{'current_date':?now})
3、模板文件
myblog/templates/base.html文件
<!DOCTYPE?HTML?PUBLIC?"-//W3C//DTD?HTML?4.01//EN"> <html> <head> ????<title>{%?block?title?%}{%?endblock?%}</title> </head> <body> ????<h1>My?helpful?timestamp?site</h1> ????{%?block?content?%}{%?endblock?%} ????{%?block?footer?%}<hr> ????<p>Thanks?for?visiting?my?site.</p> ????{%?endblock?%} </body> </html>
四、模型
1、配置数据库
myblog/setting.py
DATABASES?=?{ ????'default':?{ ????'ENGINE':?'django.db.backends.sqlite3', ????'NAME':?os.path.join(BASE_DIR,?'db.sqlite3'), }?}
2、创建应用
python?manage.py?startapp?books
3、激活应用
?INSTALLED_APPS?=?( ????????... ????????'books', )
4、创建模型
myblogs/books/models.py
from?django.db?import?models class?Publisher(models.Model): ????name?=?models.CharField(max_length=30) ????address?=?models.CharField(max_length=50) ????city?=?models.CharField(max_length=60) ????state_province?=?models.CharField(max_length=30) ????country?=?models.CharField(max_length=50) ????website?=?models.URLField() ????def?__str__(self): ????????return?self.name class?Author(models.Model): ????first_name?=?models.CharField(max_length=30) ????last_name?=?models.CharField(max_length=40) ????email?=?models.EmailField() ????def?__str__(self): ????????return?self.last_name class?Book(models.Model): ????title?=?models.CharField(max_length=100) ????authors?=?models.ManyToManyField(Author) ????publisher?=?models.ForeignKey(Publisher,on_delete=models.CASCADE) ????publication_date?=?models.DateField() ????def?__str__(self): ????????return?self.title
5、迁移数据库
#括号中的内容可以不需要 python?manage.py?makemigrations?(books) python?manage.py?migrate
6、操作数据
新增数据
方式一: p1?=?Publisher(...) p1.save() 方式二: p1?=?Publisher.objects.create(...)
更新数据
方式一: p.name?=?'Apress?Publishing' p.save() 方式二: Publisher.objects.filter(id=52).update(name='Apress')???#推荐
查询数据
返回查询集合
Publisher.objects.all() Publisher.objects.filter(name='Apress')????#WHERE?name?=?'Apress'; Publisher.objects.filter(name__contains="press")?????#WHERE?name?LIKE?'%press%';
返回单个对象
Publisher.objects.get(name="Apress")???#不是1个对象就会报异常 try: ????p?=?Publisher.objects.get(name='Apress')??#数据库中存在一个数据 except?Publisher.DoesNotExist: ????print?("Apress?isn't?in?the?database?yet.")???#数据库中没有数据 else: ????print?("Apress?is?in?the?database.")????#有多个数据
删除
方式一:单个删除 p?=?Publisher.objects.get(name="O'Reilly") p.delete() 方式二:批量删除 Publisher.objects.filter(country='USA').delete() Publisher.objects.all().delete()
排序
方式一:使用order_by() Publisher.objects.order_by("name",?"age")???#根据姓名和年龄排序,-name/-age实现反向排序 方式二:在模型内定义 class?Publisher(models.Model): ????... ????class?Meta: ????????ordering?=?['name']
切片
Publisher.objects.order_by('name')[0:2]
五、后台管理
1、创建管理员用户
python?manage.py?createsuperuser
2、将模型添加到后台管理
myblog/books/admin.py文件
from?django.contrib?import?admin from?.models?import?Publisher,?Author,?Book admin.site.register(Publisher) admin.site.register(Author) admin.site.register(Book)
3、修改模型,使字段在后台输入时变为可选项
myblog/books/models.py
class?Book(models.Model): ????title?=?models.CharField(max_length=100) ????authors?=?models.ManyToManyField(Author) ????publisher?=?models.ForeignKey(Publisher,on_delete=models.CASCADE) ????publication_date?=?models.DateField(blank=True,?null=True)
注意:如果想让日期字段(如 DateField、TimeField、DateTimeField)或数值字段(如 IntegerField、DecimalField、FloatField)接受空值,要同时添加 null=True 和 blank=True。
4、通过模型字段的verbose_name值指定后台显示的字段别名
myblog/books/models.py
class?Author(models.Model): ????first_name?=?models.CharField(max_length=30) ????last_name?=?models.CharField(max_length=40) ????email?=?models.EmailField(blank=True,?verbose_name='e-mail')
5、自定义修改后台管理列表
myblog/books/admin.py文件
from?django.contrib?import?admin from?.models?import?Publisher,?Author,?Book #自定义Author的后台管理列表 class?AuthorAdmin(admin.ModelAdmin): ????????list_display?=?('first_name',?'last_name',?'email')??#定义显示字段 ????????search_fields?=?('first_name',?'last_name')????#添加字段搜索 #自定义Book的后台管理列表 class?BookAdmin(admin.ModelAdmin): ????????list_display?=?('title',?'publisher',?'publication_date')????#定义显示字段 ????????list_filter?=?('publication_date',)????#添加时间过滤器 ????????date_hierarchy?=?'publication_date'????#另一种日期过滤器 ????????ordering?=?('-publication_date',)??????#排序 ????????fields?=?('title',?'authors',?'publisher',?'publication_date')?#自定义修改表单 ????????filter_horizontal?=?('authors',)???????#使用选项框(多对多关系时使用) ????????raw_id_fields?=?('publisher',)?????????#通过id选择对应选项 admin.site.register(Publisher) admin.site.register(Author,AuthorAdmin) admin.site.register(Book,BookAdmin)
六、表单
(1)原生表单
1、获取request数据应该try或者设置默认值,防止报错
方式一:
def?ua_display_good1(request): ????try: ????????ua?=?request.META['HTTP_USER_AGENT'] ????except?KeyError: ????????ua?=?'unknown' ????return?HttpResponse("Your?browser?is?%s"?%?ua)
方式二:
def?ua_display_good2(request): ????ua?=?request.META.get('HTTP_USER_AGENT',?'unknown') ????return?HttpResponse("Your?browser?is?%s"?%?ua)
2、简单的表单提交及表单实例
get和post指向相同的url,根据 if ‘q’ in request.GET:判断是GET还是POST
模板页面
#表单页面:myblog/templates/search_form.html <html> <head> ????<title>Search</title> </head> <body> ????{%?if?errors?%}???#提示错误信息 ????<ul> ????????{%?for?error?in?errors?%} ????????<li>{{?error?}}</li> ????????{%?endfor?%} ????</ul> ????{%?endif?%} ????<form?action=""?method="get">??#action为空,表示提交到当前页面 ????????<input?type="text"?name="q"> ????????<input?type="submit"?value="Search"> ????</form> </body> </html>
#结果展示页面:myblog/templates/search_results.html <html> <head> ????<title>Book?Search</title> </head> <body> ????<p>You?searched?for:?<strong>{{?query?}}</strong></p> ????{%?if?books?%} ????<p>Found?{{?books|length?}}?book{{?books|pluralize?}}.</p> ????<ul> ????????{%?for?book?in?books?%} ????????<li>{{?book.title?}}</li> ????????{%?endfor?%} ????</ul> ????{%?else?%} ????<p>No?books?matched?your?search?criteria.</p> ????{%?endif?%} </body> </html>
视图函数:myblog/books/views.py文件
from?django.shortcuts?import?render from?django.http?import?HttpResponse def?search(request): ????errors?=?[] ????if?'q'?in?request.GET:?#?如果是post,则存在GET['q'] ????????q?=?request.GET['q'] ????????if?not?q: ????????????errors.append('Enter?a?search?term.')??#?提交了表单,但是内容为空 ????????elif?len(q)?>?20:??#?提交表单,长度超过限制 ????????????errors.append('Please?enter?at?most?20?characters.') ????????else:???#?正常提交数据 ????????????books?=?Book.objects.filter(title__icontains=q) ????????????return?render(request,?'search_results.html', ????????????????{'books':?books,?'query':?q}) ????return?render(request,?'search_form.html',{'errors':?errors})??#不存在GET['q']说明是GET请求
路由:myblog/urls.py文件
urlpatterns?=?[ ????... ????url(r'^search/$',views.search) ]
(2)Django表单模型
1、定义表单类
myblog/books/forms.py
from?django?import?forms class?ContactForm(forms.Form): ????subject?=?forms.CharField(max_length=100)??#?max_length指定最大长度 ????email?=?forms.EmailField(required=False) ????message?=?forms.CharField(widget=forms.Textarea)?#?widget参数,指定表现逻辑,此次指定为文本框 ????def?clean_message(self):????#?自定义验表单证器 ????????message?=?self.cleaned_data['message'] ????????num_words?=?len(message.split()) ????????if?num_words?<?4: ????????????raise?forms.ValidationError("Not?enough?words!") ????????return?message
自定义表单验证器:Django 的表单系统会自动查找名称以 clean_ 开头、以字段名结尾的方法。如果存在这样的方法,在验证过 程中调用。这里,clean_message() 方法会在指定字段的默认验证逻辑(这个 CharField 是必填的)执行完毕后调用。
2、视图函数
myblog/books/views.py
from?books.forms?import?ContactForm def?contact(request): ????if?request.method?==?'POST': ????????form?=?ContactForm(request.POST) ????????if?form.is_valid(): ????????????cd?=?form.cleaned_data ????????????#提示:如果没有配置邮件服务器,调用?send_mail()?时会抛出?ConnectionRefusedError。 ????????????send_mail( ????????????????cd['subject'], ????????????????cd['message'], ????????????????cd.get('email',?'noreply@example测试数据'), ????????????????['siteowner@example测试数据'], ????????????????) ????????????return?HttpResponseRedirect('/contact/thanks/') ????else: ????????form?=?ContactForm( ????????initial={'subject':?'I?love?your?site!'}??#?可以初始值 ????????) ????return?render(request,?'contact_form.html',?{'form':?form})
3、表单页面
myblogs/templates/contact_form.html
方式一:使用系统默认表单
?<html> ?<head> ????<title>Contact?us</title> </head> <body> ????<h1>Contact?us</h1> ????{%?if?form.errors?%} ????<p?style="color:?red;"> ????????Please?correct?the?error{{?form.errors|pluralize?}}?below. ????</p> ????{%?endif?%} ????<form?action=""?method="post"> ????{%?csrf_token?%} ????????<table> ????????????{{?form.as_table?}} ????????</table> ????????{%?csrf_token?%} ????????<input?type="submit"?value="Submit"> ????</form> </body> </html>
方式二:自定义表单外观样式
<html> <head> <title>Contact?us</title> </head> <body> ????<h1>Contact?us</h1> ????{%?if?form.errors?%} ????<p?style="color:?red;"> ????????Please?correct?the?error{{?form.errors|pluralize?}}?below. ????</p> ????{%?endif?%} ????<form?action=""?method="post"> ????????<div> ????????????{{?form.subject.errors?}} ????????????<label?for="id_subject">Subject:</label> ????????????{{?form.subject?}} ????????</div> ????????<div> ????????????{{?form.email.errors?}} ????????????<label?for="id_email">e-mail:</label> ????????????{{?form.email?}} ????????</div> ????????<div> ????????????{{?form.message.errors?}} ????????????<label?for="id_message">Message:</label> ????????????{{?form.message?}} ????????</div> ????????{%?csrf_token?%} ????????<input?type="submit"?value="Submit"> ????</form> </body> </html>
4、路由设置
myblogs/myblogs/urls.py
urlpatterns?=?[ ????... ????url(r'^contact/$',?views.contact), ]