• Django 拾遗


    1.python_2_unicode_compatible装饰器

    from django.db import models
    from django.utils.encoding import python_2_unicode_compatible
    
    @python_2_unicode_compatible # 当你想支持python2版本的时候才需要这个装饰器
    class Question(models.Model):
        # ...
        def __str__(self):   # 在python2版本中使用的是__unicode__
            return self.question_text
    
    @python_2_unicode_compatible 
    class Choice(models.Model):
        # ...
        def __str__(self):
            return self.choice_text

    2.URLconf的命名空间 app_name

    现实中很显然会有5个、10个、更多的app同时存在一个项目中。Django用URL name区分这些app之间的关系

    from django.conf.urls import url
    from . import views
    app_name = 'polls'  # 关键是这行
    urlpatterns = [
        url(r'^$', views.index, name='index'),
        url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
        url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
        url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
    ]
    
    
    <li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>

    3.404错误错误页

    get_object_or_404() 替代get()

    get_list_or_404() 替代filter()

    from django.shortcuts import get_object_or_404, render
    from .models import Question
    # ...
    def detail(request, question_id):
        question = get_object_or_404(Question, pk=question_id)
        return render(request, 'polls/detail.html', {'question': question})

    4.HttpResponseRedirect 当POST数据处理成功后,建议用此函数;

      reverse 帮助我们避免在视图函数中硬编码URL;

    from django.shortcuts import get_object_or_404, render
    from django.http import HttpResponseRedirect, HttpResponse
    from django.urls import reverse
    from .models import Choice, Question
    # ...
    
    def vote(request, question_id):
        question = get_object_or_404(Question, pk=question_id)
        try:
            selected_choice = question.choice_set.get(pk=request.POST['choice'])
        except (KeyError, Choice.DoesNotExist):
            # 发生choice未找到异常时,重新返回表单页面,并给出提示信息
            return render(request, 'polls/detail.html', {
            'question': question,
            'error_message': "You didn't select a choice.",
            })
        else:
            selected_choice.votes += 1
            selected_choice.save()
            # 成功处理数据后,自动跳转到结果页面,防止用户连续多次提交。
    # 例如'/polls/3/results/',其中的3是某个question.id的值。重定向后将进入polls:results对应的视图,并将question.id传递给它
    return HttpResponseRedirect(reverse('polls:results', args=(question.id,))) from django.shortcuts import get_object_or_404, render def results(request, question_id): question = get_object_or_404(Question, pk=question_id) return render(request, 'polls/results.html', {'question': question}) <h1>{{ question.question_text }}</h1> <ul> {% for choice in question.choice_set.all %} <li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li> {% endfor %} </ul> <a href="{% url 'polls:detail' question.id %}">Vote again?</a>

    5.查看一个包安装路径

    python -c "import django; print(django.__path__)"

    6.FileField upload_to

    # upload_to参数也可以接收一个回调函数
    # user_directory_path这种回调函数,必须接收两个参数,然后返回一个Unix风格的路径字符串。参数instace代表一个定义了FileField的模型的实例,说白了就是当前数据记录。filename是原本的文件名。
    def
    user_directory_path(instance, filename): #文件上传到MEDIA_ROOT/user_<id>/<filename>目录中 return 'user_{0}/{1}'.format(instance.user.id, filename) class MyModel(models.Model): upload = models.FileField(upload_to=user_directory_path) class MyModel(models.Model): # 文件被传至`MEDIA_ROOT/uploads`目录,MEDIA_ROOT由你在settings文件中设置 upload = models.FileField(upload_to='uploads/') # 或者 # 被传到`MEDIA_ROOT/uploads/2015/01/30`目录,增加了一个时间划分 upload = models.FileField(upload_to='uploads/%Y/%m/%d/')

    7.递归外键 self ,典型的例子就是评论系统!一条评论可以被很多人继续评论

    class Comment(models.Model):
        title = models.CharField(max_length=128)
        text = models.TextField()
        parent_comment = models.ForeignKey('self', on_delete=models.CASCADE)

    8.on_delete

    on_delete
    当一个被外键关联的对象被删除时,Django将模仿on_delete参数定义的SQL约束执行相应操作。比如,你有一个可为空的外键,并且你想让它在关联的对象被删除时,自动设为null,可以如下定义:
    user = models.ForeignKey(
        User,
        models.SET_NULL,
        blank=True,
        null=True,
    )
    该参数可选的值都内置在django.db.models中,包括:
        CASCADE:模拟SQL语言中的ON DELETE CASCADE约束,将定义有外键的模型对象同时删除!(该操作为当前Django版本的默认操作!)
        PROTECT:阻止上面的删除操作,但是弹出ProtectedError异常
        SET_NULL:将外键字段设为null,只有当字段设置了null=True时,方可使用该值。
        SET_DEFAULT:将外键字段设为默认值。只有当字段设置了default参数时,方可使用。
        DO_NOTHING:什么也不做。
        SET():设置为一个传递给SET()的值或者一个回调函数的返回值。注意大小写。

    9.related_query_name

    反向关联查询名。用于从目标模型反向过滤模型对象的名称。(过滤和查询在后续章节会介绍)

    class Tag(models.Model):
        article = models.ForeignKey(
            Article,
            on_delete=models.CASCADE,
            related_name="tags",
            related_query_name="tag",       # 注意这一行
        )
        name = models.CharField(max_length=255)
    
    # 现在可以使用‘tag’作为查询名了
    Article.objects.filter(tag__name="important")

    10.through(定义中间表)

    如果你想自定义多对多关系的那张额外的关联表,可以使用这个参数!参数的值为一个中间模型。

    最常见的使用场景是你需要为多对多关系添加额外的数据,比如两个人建立QQ好友的时间。

    通常情况下,这张表在数据库内的结构是这个样子的:

    中间表的id列....模型对象的id列.....被关联对象的id列
    # 各行数据
    

    如果自定义中间表并添加时间字段,则在数据库内的表结构如下:

    中间表的id列....模型对象的id列.....被关联对象的id列.....时间对象列
    # 各行数据
    

    看下面的例子:

    from django.db import models
    
    class Person(models.Model):
        name = models.CharField(max_length=50)
    
    class Group(models.Model):
        name = models.CharField(max_length=128)
        members = models.ManyToManyField(
            Person,
            through='Membership',       ## 自定义中间表
            through_fields=('group', 'person'),
        )
    
    class Membership(models.Model):  # 这就是具体的中间表模型
        group = models.ForeignKey(Group, on_delete=models.CASCADE)
        person = models.ForeignKey(Person, on_delete=models.CASCADE)
        inviter = models.ForeignKey(
            Person,
            on_delete=models.CASCADE,
            related_name="membership_invites",
        )
        invite_reason = models.CharField(max_length=64)

    上面的代码中,通过class Membership(models.Model)定义了一个新的模型,用来保存Person和Group模型的多对多关系,并且同时增加了‘邀请人’和‘邀请原因’的字段。

    through参数在某些使用场景中是必须的,至关重要,请务必掌握!

    through_fields

    接着上面的例子。Membership模型中包含两个关联Person的外键,Django无法确定到底使用哪个作为和Group关联的对象。所以,在这个例子中,必须显式的指定through_fields参数,用于定义关系。

    through_fields参数接收一个二元元组('field1', 'field2'),field1是指向定义有多对多关系的模型的外键字段的名称,这里是Membership中的‘group’字段(注意大小写),另外一个则是指向目标模型的外键字段的名称,这里是Membership中的‘person’,而不是‘inviter’。

    再通俗的说,就是through_fields参数指定从中间表模型Membership中选择哪两个字段,作为关系连接字段。

    11.自定义错误页面

    • handler400 —— django.conf.urls.handler400。
    • handler403 —— django.conf.urls.handler403。
    • handler404 —— django.conf.urls.handler404。
    • handler500 —— django.conf.urls.handler500。

    首先,在根URLconf中额外增加下面的条目:

    # 增加的条目
    handler400 = views.bad_request
    handler403 = views.permission_denied
    handler404 = views.page_not_found
    handler500 = views.page_error

    然后在,views.py文件中增加四个处理视图:

    def page_not_found(request):
        return render(request, '404.html')
    
    
    def page_error(request):
        return render(request, '500.html')
    
    
    def permission_denied(request):
        return render(request, '403.html')
    
    def bad_request(request):
        return render(request, '400.html')

    注意:setttings 改成 DEBUG = False ALLOWED_HOSTS = ['*']

    12.csv文件下载

    import csv
    from django.http import StreamingHttpResponse
    class Echo(object):
        """An object that implements just the write method of the file-like
        interface.
        """
        def write(self, value):
            """Write the value by returning it, instead of storing in a buffer."""
            return value
    
    
    def some_view(request):
        # # Create the HttpResponse object with the appropriate CSV header.
        response = HttpResponse(content_type='text/csv')
        response['Content-Disposition'] = 'attachment; filename="somefilename.csv"'
    
        writer = csv.writer(response)
        writer.writerow(['First row', 'Second row', 'Third row', 'Fourth row'])
        rows = (["Row {}".format(idx), str(idx + 10), str(idx + 20), str(idx + 30)] for idx in range(65536))
        for row in rows:
            writer.writerow(row)
        return response
    
    
        # rows = (["Row {}".format(idx), str(idx+10),str(idx+20),str(idx+30)] for idx in range(65536))
        # pseudo_buffer = Echo()
        # writer = csv.writer(pseudo_buffer)
        # response = StreamingHttpResponse((writer.writerow(['First row', 'Second row', 'Third row', 'Fourth row'])),
        #                                  content_type="text/csv")
        # response = StreamingHttpResponse((writer.writerow(row) for row in rows),
        #                                  content_type="text/csv")
        # response['Content-Disposition'] = 'attachment; filename="somefilename.csv"'
        # return response

    13.

    CP: http://www.liujiangblog.com/course/django/96

  • 相关阅读:
    选择和冒泡
    马尔科夫模型
    网络IO
    java项目相对路径
    MySQL 数据类型
    基于 Token 的身份验证方法
    git 打标签
    git版本回退
    robotframework使用过程中的一些总结
    robotframework安装robotframework-requests库遇到的几种问题
  • 原文地址:https://www.cnblogs.com/icemonkey/p/10608206.html
Copyright © 2020-2023  润新知