Django基础核心技术

目录

模型(Model)的设计

Django models def __str__(self)有什么作用?

Django Model中字段(Field)的可选项和必选项

 一个复杂点的Django Model模型

常见的Django Model META类选项

URL的设计与配置

Django URL传递参数的方法path和_re_path

URL的命名及reverse()方法

URL如何指向基于类的视图(View)

通过URL方法传递额外的参数


Django网络应用开发的5项基础核心技术包括模型(Model)的设计,URL的配置,View(视图)的编写,Template(模板)的设计和Form(表单)的使用。

模型(Model)的设计


每个Django model实际上是个类,继承了models.Model。每个Model应该包括属性,关系(比如单对单,单对多和多对多)和方法。当你定义好Model模型后,Django的接口会自动帮你在数据库生成相应的数据表(table)。这样你就不用自己用SQL语言创建表格或在数据库里操作创建表格了。

# models.py
from django.db import models

class Publisher(models.Model):
    name = models.CharField(max_length=30)
    address = models.CharField(max_length=60)

    def __str__(self):
        return self.name
		
class Book(models.Model):
    name = models.CharField(max_length=30)
    description = models.TextField(blank=True, default='')
    publisher = ForeignKey(Publisher, on_delete = models.CASCADE)
    add_date = models.DateField()

    def __str__(self):
        return self.name

Django models def __str__(self)有什么作用?

这个方法是当print 输出实例对象或str() 实例对象时,调用这个方法

很多编程语言都有这个机制, 如Java 中的 toString方法 。

Django Model中字段(Field)的可选项和必选项

字段与选项(必选项为黄色标注)

CharField() 字符字段

 

  • max_length = xxx or None

  • 如不是必填项,可设置blank = True和default = ''

  • 如果用于username, 想使其唯一,可以设置unique = True

  • 如果有choice选项,可以设置 choices = XXX_CHOICES

TextField() 文本字段

  • max_length = xxx

  • 如不是必填项,可设置blank = True和default = ''

DateField() and DateTimeField() 日期与时间字段

  • 一般建议设置默认日期default date.

  • For DateField: default=date.today - 先要from datetime import date

  • For DateTimeField: default=timezone.now - 先要from django.utils import timezone

  • 对于上一次修改日期(last_modified date),可以设置: auto_now=True

EmailField() 邮件字段

 

  • 如不是必填项,可设置blank = True和default = ''

  • 一般Email用于用户名应该是唯一的,建议设置unique = True

IntegerField(), SlugField(), URLField(),BooleanField()

  • 可以设置blank = True or null = True

  • 对于BooleanField一般建议设置defautl = True or False

FileField(upload_to=None, max_length=100) - 文件字段

  • upload_to = "/some folder/"

  • max_length = xxxx

ImageField(upload_to=None, height_field=None, width_field=None, max_length=100,)

  • upload_to = "/some folder/"

  • 其他选项是可选的.

ForeignKey(to, on_delete, **options) - 单对多关系

 

  • to必需指向其他模型,比如 Book or 'self' .

  • 必需指定on_delete options(删除选项): i.e, "on_delete = models.CASCADE" or "on_delete = models.SET_NULL" .

  • 可以设置"default = xxx" or "null = True" .

  • 如果有必要,可以设置 "limit_choices_to = ",如下面例子。

  • staff_member = models.ForeignKey( User, on_delete=models.CASCADE, limit_choices_to={'is_staff': True}, )

  • 可以设置 "related_name = xxx" 便于反向查询。

ManyToManyField(to, **options) - 多对多关系

 

  • to 必需指向其他模型,比如 User or 'self' .

  • 设置 "symmetrical = False " if 多对多关系不是对称的

  • 设置 "through = 'intermediary model' " 如果需要建立中间模型来搜集更多信息

  • 可以设置 "related_name = xxx" 便于反向查询。

 一个复杂点的Django Model模型

# models.py

from django.db import models
from django.contrib.auth.models import User
from datetime import date


class Restaurant(models.Model):
    name = models.TextField()
    address = models.TextField(blank=True, default='')
    telephone = models.TextField(blank=True, default='')
    url = models.URLField(blank=True, null=True)
    user = models.ForeignKey(User, default=1,on_delete=models.CASCADE)
    date = models.DateField(default=date.today)

    def __str__(self):
        return self.name

class Dish(models.Model):
    name = models.TextField()
    description = models.TextField(blank=True,  default='')
    price = models.DecimalField('USD amount', max_digits=8, decimal_places=2, blank=True, null=True)
    user = models.ForeignKey(User, default=1, on_delete=models.CASCADE)
    date = models.DateField(default=date.today)
    image = models.ImageField(upload_to="myrestaurants", blank=True, null=True)
# Related name "dishes" allows you to use restaurant.dishes.all to access all dishes objects
# instead of using restaurant.dish_set.all
    restaurant = models.ForeignKey(Restaurant, null=True, related_name='dishes', on_delete=models.CASCADE)

    def __str__(self):
        return self.name

# This Abstract Review can be used to create RestaurantReview and DishReview

class Review(models.Model):
    RATING_CHOICES = ((1, 'one'), (2, 'two'), (3, 'three'), (4, 'four'), (5, 'five'))
    rating = models.PositiveSmallIntegerField('Rating', blank=False, default=3, choices=RATING_CHOICES)
    comment = models.TextField(blank=True, null=True)
    user = models.ForeignKey(User, default=1, on_delete=models.CASCADE)
    date = models.DateField(default=date.today)

    class Meta:
        abstract = True

class RestaurantReview(Review):
    restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE)
    
    def __str__(self):
        return "{} review".format(self.restaurant.name)

我们的Dish模型里有一个restaurant的字段,建立了一个单对多的关系。我们可以通过dish.restaurant.name直接查询到菜肴所属的餐厅的名字。然而我们Restaurant模型里并没有dish的字段,我们如何根据restaurant查询到某个餐厅的所有菜肴呢?Django非常聪明,可以通过在dish小写后面加上'_set'进行反向查询。我们本来可以直接通过restaurant.dish_set.all的方法来进行查找的,然而这个方法并不直观。为了解决这个问题,我们在dish模型里设置'related_name = dishes", 这样我们就可以直接通过restaurant.dishes.all来反向查询所有菜肴了。注意一但你设置了related name, 你将不能再通过_set方法来反向查询。

restaurant = models.ForeignKey(Restaurant, related_name='dishes', on_delete=models.CASCADE)

第2个细节你需要关注的是Review模型里,我们设置了META选项: Abstract = True。这样一来Django就会认为这个模型是抽象类,而不会在数据库里创建review的数据表。实际上Model自带的META选项还有很多,都非常有用。

常见的Django Model META类选项

# models.py
from django.db import models

class Meta:
    # 按Priority降序, order_date升序排列.
    get_latest_by = ['-priority', 'order_date']
    # 自定义数据库里表格的名字
    db_table = 'music_album'
    # 按什么排序
    ordering = ['pub_date']
    # 定义APP的标签
    app_label = 'myapp'
    # 声明此类是否为抽象
    abstract = True
    # 添加授权
    permissions = (("can_deliver_pizzas", "Can deliver pizzas"),)

URL的设计与配置

URL通常与视图(View)一起工作的。服务器收到用户请求后,会根据urls.py里的关系条目,去视图View里查找到与请求对应的处理方法,从而返回给客户端http页面数据。这和其它web开发的路由机制(Router)是一个道理。如果你还不知道视图是什么,那么你只需要记住:视图收到用户的请求后,展示给用户看得见的东西。

例子:

# blog/urls.py
from django.urls import path

from . import views

urlpatterns = [
    path('blog/', views.index),
      path('blog/article/<int:id>/', views.article),
]

# blog/views.py
def index(request):
    # 展示所有文章
    
def article(request, id):
    # 展示某篇具体文章

那么这段代码是如何工作的?

  • 当用户在浏览器输入/blog/时,URL收到请求后会调用视图views.py里的index方法,展示所有文章。

  • 当用户在浏览器输入/blog/article/<int:id>/时,URL不仅调用了views.py里的article方法,而且还把参数文章id通过<>括号的形式传递给了视图。int这里代表只传递整数,传递的参数名字是id。

 

注意当你配置URL时,别忘了把你的app(比如blog)urls加入项目的URL配置里(mysite/urls.py), 如下图所示:

from django.conf.urls import url, include

urlpatterns = [
    url(r'^/', include('blog.urls')),
] 

Django URL传递参数的方法path和_re_path

写个URL很简单,但如何通过URL把参数传递给给视图view是个技术活。Django URL提供了两种匹配方式传递参数: path和re_path。path是正常参数传递,re_path是采用正则表达式regex匹配。path和re_path传递参数方式如下:

  • path方法:采用双尖括号<变量类型:变量名>或<变量名>传递,例如<int:id>, <slug:slug>或<username>。

  • re_path方法: 采用命名组(?P<变量名>表达式)的方式传递参数。

下图两种传递文章id给视图函数的方式是一样的。re_path里引号前面的小写r表示引号里为正则表达式, 请忽略'\'不要转义,^代表开头,$代表以结尾,\d+代表正整数。

# blog/urls.py
from django.urls import path, re_path

from . import views

urlpatterns = [
    path('blog/article/<int:id>/', views.article, name = 'article'),
   re_path(r'^blog/article/(?P<id>\d+)/$', views.article, name='article'),
]

# View (in blog/views.py)

def article(request, id):
    # 展示某篇文章

URL的命名及reverse()方法

你注意到没?我们在上述代码中还给URL取了一个名字 'article'。这个名字大有用处,相当于给URL取了个全局变量的名字。它可以让你能够在Django的任意处,尤其是模板内显式地引用它。假设你需要在模板中通过链接指向一篇具体文章,下面那种方式更好?

方法1: 使用命名URL
<a href="{% url 'article' id %}">Article</a>

方法2: 使用常规URL - 不建议
<a href="blog/article/id">Article</a>

如果你还没意识到方法1的好处,那么想想吧,假设你需要把全部模板链接由blog/article/id改为blog/articles/id, 那种方法更快?改所有模板,还是改URL配置里的一个字母?

 

可惜的是命名的URL一般只在模板里使用,不能直接在视图里使用。如果我们有了命名的URL,我们如何把它转化成常规的URL在视图里使用呢?Django提供的reverse()方法很容易实现这点。假设不同的app(比如news和blog)里都有article这个命名URL, 我们怎么区分呢? 我们只需要在article前面加上blog这个命名空间即可。

from django.urls import reverse

# output blog/article/id
reverse('blog:article', args=[id])

URL如何指向基于类的视图(View)

目前path和re_path都只能指向视图view里的一个函数或方法,而不能指向一个基于类的视图(Class based view)。Django提供了一个额外as_view()方法,可以将一个类伪装成方法。这点在当你使用Django在带的view类或自定义的类时候非常重要。具体使用方式如下:

# blog/urls.py
from django.urls import path, re_path

from . import views

urlpatterns = [
      path('', views.ArticleList.as_view(), name='article_list'),
    path('blog/article/<int:id>/', views.article, name = 'article'),
    re_path(r'^blog/article/(?P<id>\d+)/$', views.article, name='article'),
]

# View (in blog/views.py)
from django.views.generic import ListView
from .views import Article

class ArticleList(ListView):

    queryset = Article.objects.filter(date__lte=timezone.now()).order_by('date')[:5]
    context_object_name = 'latest_article_list'
   template_name = 'blog/article_list.html'

def article(request, id):
    # 展示某篇文章

通过URL方法传递额外的参数

在你配置URL时,你还可以通过字典的形式传递额外的参数给视图, 而不用把这个参数写在链接里。如下面案例所示:

# blog/urls.py
from django.urls import path, re_path

from . import views

urlpatterns = [

    path('', views.ArticleList.as_view(), name='article_list', {'blog_id': 3}),
    re_path(r'^blog/article/(?P<id>\d+)/$', views.article, name='article'),
]

View视图详解

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值