【Django】入门 | urls.py | views.py | models数据库

一、基础

查看Django版本

...\> py -m django --version

1.创建项目

会在当前目录下创建一个mysite目录

...\> django-admin startproject mysite

目录结构如下:
mysite/ 根目录只是项目的容器,可以将它重命名为任何名字,没有影响
manage.py
mysite/ 包含你的项目,它是一个纯 Python 包
init.py
settings.py
urls.py
asgi.py
wsgi.py

2.创建应用

会在当前目录下创建一个应用

...\> py manage.py startapp polls

目录结构如下:
polls/
init.py
admin.py
apps.py
migrations/
init.py
models.py
tests.py
views.py

3.运行服务器

浏览器访问http://localhost:8000/…

...\> py manage.py runserver
#更换服务器监听端口
...\> py manage.py runserver 8080
#更换服务器监听IP,在端口之前输入新的(0 是 0.0.0.0 的简写)
...\> py manage.py runserver 0:8000

4.创建管理员账号

http://127.0.0.1:8000/admin/

...\> py manage.py createsuperuser
Username: admin
Email address: admin@example.com
#最后在输入密码

5.Admin页面

向Admin页面加入应用

#在polls的admin中注册
from django.contrib import admin

from .models import Question

admin.site.register(Question)

6.应用中的views和urls文件

**视图views必须要做的事:返回的是一个 HttpResponse ,或者抛出一个异常。**响应可以是一个 HTML 页面、一个 404 错误页面、重定向页面、XML 文档、或者一张图片…代码写在哪里都可以,只要在 Python 目录下面,一般放在项目的 views.py 文件中。
polls的views:

from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello, world. You're at the polls index.")

polls的urls:

rom django.urls import path

from . import views

urlpatterns = [
    path('', views.index, name='index'),
]

函数path():
参数route:route 是一个匹配 URL 的准则(类似正则表达式),这些准则不会匹配 GET 和 POST 参数或域名
参数view:当 Django 找到了一个匹配的准则,就会调用这个特定的视图函数,并传入一个 HttpRequest 对象作为第一个参数
参数kwargs:任意个关键字参数可以作为一个字典传递给目标视图函数。
参数name:为你的 URL 取名能使你在 Django 的任意地方唯一地引用它

mysite的urls:

from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path('polls/', include('polls.urls')),
    path('admin/', admin.site.urls),
]

函数 include() 允许引用其它 URLconfs。每当 Django 遇到 include() 时,它会截断与此项匹配的 URL 的部分,并将剩余的字符串发送到 URLconf 以供进一步处理。

urls.py中的path(),url(),re_path()

url是Django 1.x中写法,Django2.1中开始舍弃url的写法,引入path和re_path,其中re_path可看作url函数的替代。
主要的区别:

  • 模块不同(引入文件不同)
  • url参数表示不同
url

url参数规则:

  • 需要开始符^和结尾符$
  • 参数匹配一个 ()就是一个匹配参数

(?P<匹配的字段名>正则表达式)

  • 进行匹配是不包括get或者post请求方式的参数及域名比如www.qq.com/blog?num=1并不会匹配?后边的字符
from django.conf.urls import url

    urlpatterns=[
          url(r'^page/$',views.page),
          url(r'^page(?P<num>[0-9]+)$',views.page)
    ]
    
    #views
    
    def page(request,num='1'):
         pass
path

url参数规则:

  • 直接写路径,不用开始符号结束符号,不支持正则表达
  • 参数匹配用尖括号比如<int:a>,尖括号内前边代表参数的类型,后面代表参数的名称。这个转换器也有许多类型:
    • int 匹配0和正整数
    • str 匹配任何空字符串但不包括/
    • slug 可理解为注释 匹配任何ascii码包括连接线和下划线
    • uuid 匹配一个uuid对象(该对象必须包括破折号—,所有字母必须小写)
    • path 匹配所有的字符串 包括/(意思就是path前边和后边的所有)
from django.urls import path
re_path

当URL不能被路径和转换器语法定义时,就需要使用正则表达式,也就是说要用re_path了
具体语法之后再补充

from django.urls import re_path
正则表达式的使用
正则路径中的无名分组

无名分组按位置传参,一一对应。views 中除了 request,其他形参的数量要与 urls 中的分组数量一致。

#urls.py
urlpatterns = [
    path('admin/', admin.site.urls),
    re_path("^index/([0-9]{4})/$", views.index),
]

#views.py
from django.shortcuts import HttpResponse
def index(request,year):
    print(year) # 一个形参代表路径中一个分组的内容,按顺序匹配
    return HttpResponse('菜鸟教程')
正则路径中的有名分组

(?P<组名>正则表达式)

有名分组按关键字传参,与位置顺序无关。views 中除了 request,其他形参的数量要与 urls 中的分组数量一致, 并且 views 中的形参名称要与 urls 中的组名对应。

#urls.py
urlpatterns = [
    path('admin/', admin.site.urls),
    re_path("^index/(?P[0-9]{4})/(?P[0-9]{2})/$", views.index),
]

#views.py
from django.shortcuts import HttpResponse
def index(request, year, month):
    print(year,month) # 一个形参代表路径中一个分组的内容,按关键字对应匹配
    return HttpResponse('菜鸟教程')
name=“路由别名”

在urls.py文件中,path等函数的第三个参数可设置路由别名。当redirect重定向时reverse反向解析时特别有用,用别名就免去url修改之后要修改对应其他文件url的烦恼。

在模板 templates 中的 HTML 文件中,利用 {% url “路由别名” %} 反向解析。

<form action="{% url 'login' %}" method="post"> 
<form action="{% url 'login' 10 %}" method="post"> 
<form action="{% url 'login' year=3333 %}" method="post">
#普通路径path("login1/", views.login, name="login")
return redirect(reverse("login"))

#正则路径的无名分组re_path(r"^login/([0-9]{2})/$", views.login, name="login")
return redirect(reverse("login",args=(10,)))

#正则路径的有名分组re_path(r"^login/(?P<year>[0-9]{4})/$", views.login, name="login")
return redirect(reverse("login",kwargs={"year":3333}))
命名空间

路由别名 name 没有作用域,Django 在反向解析 URL 时,会在项目全局顺序搜索,当查找到第一个路由别名 name 指定 URL 时,立即返回。当在不同的 app 目录下的urls 中定义相同的路由别名 name 时,可能会导致 URL 反向解析错误。
所以可以使用命名空间解决问题,可以使用下面的include函数解决,或者在app的urls.py文件中加入

#polls/urls.py
app_name = 'polls'
include()函数

用法:如果需要在当前urls中调用其他urls时比较好用
作用:用于urlpatterns中剔除掉path前面匹配到的部分,将剩下的部分交给include中的urls处理
1. include(module, namespace=None)

  • module:URLconf module (or module name)
#主项目下的urls.py
urlpatterns = [
    path('polls/', include('polls.urls')),
    path('admin/', admin.site.urls),
]

每当 Django 遇到 include() 时,它会截断前面匹配的 URL 的部分,并将剩余的字符串发送到inlcude中的URLconf 以供进一步处理。
2. include(pattern_list)

  • pattern_list:Iterable of path() and/or re_path() instances 必须是一个可迭代的path() 或者 re_path() 清单
    我这么理解的:也可以丢给同一个文件下的另一个匹配列表
extra_patterns = [
    url(r'^reports/$', credit_views.report),
    url(r'^reports/(?P<id>[0-9]+)/$', credit_views.report),
    url(r'^charge/$', credit_views.charge),
]
 
urlpatterns = [
    url(r'^$', main_views.homepage),
    url(r'^help/', include('apps.help.urls')),
    url(r'^credit/', include(extra_patterns)),
]

3. include((pattern_list, app_namespace), namespace=None)

#主项目下的urls.py
#include(("app名称.urls","app名称"))
path("app01/", include(("app01.urls","app01"))) 

#app01下的urls.py
path("login/", views.login, name="login")

#reverse("app名称:路由别名")
return redirect(reverse("app01:login")

#{% url "app名称:路由别名" %}
<form action="{% url 'app01:login' %}" method="post">
views从urls接收参数

views:

def detail(request, question_id):
    return HttpResponse("You're looking at question %s." % question_id)
urlpatterns = [
    # ex: /polls/5/
    path('<int:question_id>/', views.detail, name='detail'),
]

detail(request=, question_id=34)
question_id=34 由 int:question_id 匹配生成。使用尖括号“捕获”这部分 URL,且以关键字参数的形式发送给视图函数。上述字符串的 :question_id> 部分定义了将被用于区分匹配模式的变量名,而 int: 则是一个转换器决定了应该以什么变量类型匹配这部分的 URL 路径。

抛出404错误和快捷函数
views.py中的render()
  • 可用来代替HttpResponse
  • 使用字典context作为参数{key:value}
  • context中的键值对对应HTML文件中{{key}}替换的值
from django.shortcuts import render
 
def runoob(request):
    context          = {}
    context['hello'] = 'Hello World!'
    return render(request, 'runoob.html', context)
views.py中的HttpRequest对象

HttpRequest即函数接收的request参数
常用属性:

属性描述
path请求页面的全路径,不包括域名—例如, “/hello/”,数据类型是字符串。
method请求中使用的HTTP方法的字符串表示。全大写表示。例如:if request.method == ‘GET’:
GET包含所有HTTP GET参数的类字典对象。参见QueryDict 文档。
POST包含所有HTTP POST参数的类字典对象。参见QueryDict 文档。
REQUEST为了方便,该属性是POST和GET属性的集合体,但是有特殊性,先查找POST属性,然后再查找GET属性。不建议使用。
COOKIES包含所有cookies的标准Python字典对象。Keys和values都是字符串。
body数据类型是二进制字节流,是原生请求体里的参数内容,在 HTTP 中用于 POST,因为 GET 没有请求体。在 HTTP 中不常用,而在处理非 HTTP 形式的报文时非常有用,例如:二进制图片、XML、Json 等。

还有:FILES、META、user、session、raw_post_data

常用方法:_getitem_(key)、has_key()、get_full_path()、is_secure()

QueryDict数据类型:一个类似于字典的对象。在HttpRequest对象中,
GET和POST属性是django.http.QueryDict类的实例。

get():(具体可以查询QueryDict的方法)返回字符串,如果该键对应有多个值,取出该键的最后一个值。

def runoob(request):
    name = request.GET.get("name")
    return HttpResponse('姓名:{}'.format(name))
def runoob(request):
    name = request.POST.get("name")
    return HttpResponse('姓名:{}'.format(name))

更多资料

views.py中的HttpResponse对象

响应对象主要有三种形式:HttpResponse()、render()、redirect()。它们返回的本质上也都是HttpResponse对象

  • HttpResponse(): 返回文本,参数为字符串,字符串中写文本内容。如果参数为字符串里含有 html 标签,也可以渲染。
  • render(): 返回文本,第一个参数为 request,第二个参数为字符串(页面名称),第三个参数为字典(可选参数,向页面传递的参数:键为页面参数名,值为views参数名)。
  • redirect():重定向,跳转新页面。参数为字符串,字符串中填写页面路径。一般用于 form 表单提交后,跳转到新页面。
def runoob(request):
    # return HttpResponse("菜鸟教程")
    return HttpResponse("<a href='http://https://www.runoob.com/>菜鸟教程</a>")
def runoob(request):
    name ="菜鸟教程"
    return render(request,"runoob.html",{"name":name})
def runoob(request):
    return redirect("/index/")

二、数据库

1.数据库配置

先设置TIME_ZONE为自己的时区
在mysite/settings.py中配置数据库

#该命令检查 INSTALLED_APPS 设置,为其中的每个应用创建需要的数据表
...\> py manage.py migrate
  1. 编辑 models.py 文件,改变模型。
  2. 运行 python manage.py makemigrations 为模型的改变生成迁移文件。
  3. 运行 python manage.py migrate 来应用数据库迁移。
    每次新建新的models,都要重复2、3步,不能直接第3步

2.Django ORM

ORM,对象关系映射,是通过使用描述对象和数据库之间的映射的元数据,将程序中的对象自动持久化到数据库中。
可以这样理解,ORM 会将 Python 代码转成为 SQL 语句,SQL 语句通过桥梁传送到数据库服务端,在数据库中执行 SQL 语句并将结果返回。

3.模型models

Django规定,如果要使用模型,必须要创建一个app。

创造model/表结构
  1. 类需继承自models.Model
  2. 类名代表数据库表名
  3. 没有在models设置主键,但是 Django 会自动添加一个 id 作为主键。
from django.db import models


class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')


class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)
  • CharField为字符串类型,必须有max_length设置最大长度(max_length在postgreSQL下亲自实践,不是字节数,而是字符数,10个数字,10个汉字,10个英文占位一模一样,混合也一样,在网上查过mysql数据库也好像也是一样的),verbose_name在django后台显示该英文字段的中文意思
  • IntegerField整型,在postgreSQL下亲自实践4个字节大小,也就是最大存储2^32-1的数,用来存秒数的话可以到68年的样子
  • DecimalField浮点型,max_digits=5表示整数部分和小数位数之和不大于5,decimal_places表示小数的最大位数,null=True表示字段可以为空,blank=True表示在admin后台中该数据栏可以为空
  • EmailField该字段必须符合邮箱格式
  • TextField字段位文本类型,长度没有限制
  • DateTimeField为日期类型,auto_now_add=True该条数据创建的时间,数据更新时,时间数值不变
  • auto_now=True该条数据创建的时间,数据更新时(即每次save时),时间数值也会改变。无法手动赋值,在admin管理器中是只读数据
  • ForeignKey多外键,第一个参数位你要关联的数据表,比如一个班级有多个学生,就属于一对多,外键要放到"多"的那张表,related_name是对外键取别名,常用在django的orm反向查询中
    更多Field类型,官网在Documentation页面搜索“field”
    Post’g’re’SQL特有的Field,官网
    更多有关数据库构造时函数的使用
    objects数据库查询常用语句,还挺全的
外键
外键的创建

多对一:在models中创建外键时需要使用到类class ForeignKey(to,on_delete,**options)
多对多:MangToManyField

  • 第一个参数是引用的是哪个模型(如果是自己,直接写’self’,如果是别的包的模型,引入那个包写就行了)
  • 第二个参数是在使用外键引用的模型数据被删除了,这个字段该如何处理,比如有CASCADE、SET_NULL等
    • CASCADE:级联操作。如果外键对应的那条数据被删除了,那么这条数据也会被删除。
    • PROTECT:受保护。即只要这条数据引用了外键的那条数据,那么就不能删除外键的那条数据。如果我们强行删除,Django就会报错。
    • SET_NULL:设置为空。如果外键的那条数据被删除了,那么在本条数据上就将这个字段设置为空。如果设置这个选项,前提是要指定这个字段可以为空。
    • SET_DEFAULT:设置默认值。如果外键的那条数据被删除了,那么本条数据上就将这个字段设置为默认值。如果设置这个选项,== 前提是要指定这个字段一个默认值 ==。
    • SET():如果外键的那条数据被删除了。那么将会获取SET函数中的值来作为这个外键的值。SET函数可以接收一个可以调用的对象(比如函数或者方法),如果是可以调用的对象,那么会将这个对象调用后的结果作为值返回回去。== 可以不用指定默认值 ==
    • DO_NOTHING:不采取任何行为。一切全看数据库级别的约束。

一对多ForeignKey

from django.db import models

#一个类下可以有多篇文章,但一篇文章只能对应一个类
class Category(models.Model):
    name = models.CharField(max_length=100)

class Article(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    # 是由Category影响Article
    category = models.ForeignKey('Category',on_delete=models.CASCADE)

多对多MangToManyField

class Author(models.Model):
   first_name = models.CharField(max_length=30)
   last_name = models.CharField(max_length=40)

#一本书可以有多个作者,一个作者可以写多本书
class Book(models.Model):
   title = models.CharField(max_length=100)
   authors = models.ManyToManyField(Author)

外键的使用

一对一OneToOneField = ForeignKey(…,unique=True)
一对一的反向查询用小写类名即可,不用加_set

一对多ForeignKey

article = Article.objects.first()
#可以直接得到相关的数据模型对象
article.category
article.category.name

#通过Category对象反向追溯article对象
category = Category.objects.first()
#属性名称article_set是由模型名称的小写(如Article)加_set组成的。
#在ForeignKey函数中有一个参数related_name,如果设置了这个参数就可以不用_set的形式了,可以直接用related_name的值,这一点同样适用于ManyToManyField函数。
#article_set只是一个 QuerySet,所以它可以像QuerySet一样,能实现数据过滤和分切
category.article_set.all()
category.article_set.filter(title__icontains='django')

多对多ManyToManyField
虽然两者间关系是一样的,但根据定义是ManyToMany写在谁那里还是有正向和反向的关系的。

b = Book.objects.get(id=50)
b.authors.all()

#反向查询
a = Author.objects.get(first_name='Adrian',last_name='Holovaty')
a.book_set.all()
添加数据

添加数据需要先创建对象,然后再执行 save 函数

#方法一:模型类实例化对象
question = Question(question_text = '.....')
......
question.save()

#方法二(推荐):通过 ORM 提供的 objects 提供的方法 create 来实现
question = Question.objects.create(question_text = '.....')
获取/查询数据
def testdb(request):
    # 初始化
    response = ""
    response1 = ""
      
    # 通过objects这个模型管理器的all()获得所有数据行,相当于SQL中的SELECT * FROM
    # 返回 QuerySet 类型数据
    list = Test.objects.all()
        
    # filter相当于SQL中的WHERE,可设置条件过滤结果
    # 返回 QuerySet 类型数据
    response2 = Test.objects.filter(id=1) 
    #response2 = Test.objects.filter(id=1,price = 300) 
	
	# exclude() 方法用于查询不符合条件的数据,用法跟filter一样
    
    # 获取单个对象,如果符合筛选条件的对象超过了一个或者没有一个都会抛出错误。
    response3 = Test.objects.get(id=1) 
    
    # 限制返回的数据 相当于 SQL 中的 OFFSET 0 LIMIT 2;
    # 但不能用负数,没有逆序索引
    Test.objects.order_by('name')[0:2]
    #数据排序
    Test.objects.order_by("id")
    Test.objects.order_by("id").reverse()	#对查询结果反转
    
    # 上面的方法可以连锁使用
    Test.objects.filter(name="runoob").order_by("id")
    # count(),first(),last()方法都能直接加在末尾
    
    # 输出所有数据
    for var in list:
        response1 += var.name + " "
    response = response1
    return HttpResponse("<p>" + response + "</p>")

数据库查询的函数语法
菜鸟教程——包含筛选下划线的使用,比上面的更全面

更新数据

修改数据可以使用 save() 或 update()

def testdb(request):
    # 修改其中一个id=1的name字段,再save,相当于SQL中的UPDATE
    # 对模型类的对象进行更新
    test1 = Test.objects.get(id=1)
    test1.name = 'Google'
    test1.save()
    
    # 另外一种方式,对QuerySet类型数据进行更新
    # 返回值:受影响的行数(整数)
    Test.objects.filter(id=1).update(name='Google')
    
    # 修改所有的列
    Test.objects.all().update(name='Google')
    
    return HttpResponse("<p>修改成功</p>")
删除数据

删除数据库中的对象只需调用该对象的delete()方法即可

# 数据库操作
def testdb(request):
    # 删除id=1的数据
    test1 = Test.objects.get(id=1)
    test1.delete()
    
    # 另外一种方式
    Test.objects.filter(id=1).delete()
    
    # 删除所有数据
    Test.objects.all().delete()
    
    return HttpResponse("<p>删除成功</p>")
自定义查询/筛选数据参考

django ORM 使用 sql 函数怎么写表达式?

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值