Django实践:让用户拥有自己的数据,权限管理



引言

本文简要介绍在一个Django项目中如何让各个用户账户拥有自己的数据,包括:未登录不能访问数据,登录用户只能访问自己的数据等权限管理操作。


一、使用装饰器@login_required限制访问

1. 添加装饰器@login_required

  利用装饰器(decorator)@login_required,可以让某些页面,只允许已经登录的用户访问。首先用from django.contrib.auth.decorators import login_required导入login_required()函数,然后@login_required放在相应的函数定义之前,在运行函数之前,会先运行装饰器login_required()函数,检查是否已登录。以topics()函数为例:

from django.shortcuts import render
from django.http import HttpResponseRedirect, Http404
from django.urls import reverse
from django.contrib.auth.decorators import login_required
from .models import Topic, Entry
from .forms import TopicForm, EntryForm

@login_required
def topics(request):
    """显示所有的主题"""
    topics = Topic.objects.order_by('date_added')
    context = {'topics': topics}
    return render(request, 'learning_logs/topics.html', context)

  打开页面时候是显示主页:
在这里插入图片描述
  点击Topics按钮的时候,显示页面找不到:
在这里插入图片描述

2. 重定向到登录界面

  通过修改settings.py代码,将404页面重定向到登录界面,添加如下:

# My settings
LOGIN_URL = '/login/'

在这里插入图片描述


二、将数据管理到账户

1. 修改模型代码

  首先用from django.contrib.auth.models import User导入User,然在Topic类中添加owner = models.ForeignKey(User, on_delete=models.CASCADE),将字段owner 建立起到模型User 的外键关系。

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

class Topic(models.Model):
    """用户学习的主题"""
    text = models.CharField(max_length=200)
    date_added = models.DateTimeField(auto_now_add=True)
    owner = models.ForeignKey(User, on_delete=models.CASCADE)

    def __str__(self):
        """返回模型的字符串"""
        return self.text

2. 确定当前有哪些用户

  Terminal命令行中输入python manage.py shell ,然后用User.objects.all()查看用户名和id。我们这里有两个用户mt和mat。

(base) E:\myPrograms\leraning_log>python manage.py shell
Python 3.8.3 (default, Jul  2 2020, 17:30:36) [MSC v.1916 64 bit (AMD64)]
Type 'copyright', 'credits' or 'license' for more information
IPython 7.16.1 -- An enhanced Interactive Python. Type '?' for help.

In [1]: from django.contrib.auth.models import User

In [2]: User.objects.all()
Out[2]: <QuerySet [<User: mt>, <User: mat>]>

In [3]: for user in User.objects.all():
   ...:     print(user.username, user.id)
   ...: 
mt 1
mat 2

3. 迁移数据库

2.3.1. makemigrations

  Terminal命令行中输入python manage.py makemigrations learning_logs ,在弹出的提示中会要求我们给owner指定默认值,会让我们选择要么添加默认值,要么退出在models.py中添加默认值(黄色方框)。我们根据提示选择“1”指定默认值(红色方框),在指定默认值的时候,要求我们将用户账户id作为参数传入,我们选择“1”(绿色方框,代表mt(超级用户))将超级用户mt作为默认值指定给owner,运行成功后将field owner添加到topic中,结果如(蓝色方框)所示,成功后会在learning_logs/migrations/下增加一个0003_topic_owner.py文件。

Terminal命令行中代码如下:
在这里插入图片描述

(base) E:\myPrograms\leraning_log>python manage.py makemigrations learning_logs
No changes detected in app 'learning_logs'

(base) E:\myPrograms\leraning_log>python manage.py makemigrations learning_logs
You are trying to add a non-nullable field 'owner' to topic without a default; we can't do that (the database needs something t
o populate existing rows).
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
 2) Quit, and let me add a default in models.py
Select an option: 1
Please enter the default value now, as valid Python
The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now
Type 'exit' to exit this prompt
>>> 1
Migrations for 'learning_logs':
  learning_logs\migrations\0003_topic_owner.py
    - Add field owner to topic

0003_topic_owner.py中的代码如下:

rom django.conf import settings
from django.db import migrations, models
import django.db.models.deletion

class Migration(migrations.Migration):

    dependencies = [
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
        ('learning_logs', '0002_entry'),
    ]

    operations = [
        migrations.AddField(
            model_name='topic',
            name='owner',
            field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
            preserve_default=False,
        ),
    ]

2.3.2. migrate

  Terminal命令行中输入python manage.py migrate ,完成数据库迁移。可以在命令行中交互的打印出topic和topic.owner验证:

(base) E:\myPrograms\leraning_log>python manage.py shell
Python 3.8.3 (default, Jul  2 2020, 17:30:36) [MSC v.1916 64 bit (AMD64)]
Type 'copyright', 'credits' or 'license' for more information
IPython 7.16.1 -- An enhanced Interactive Python. Type '?' for help.

In [1]: from learning_logs.models import Topic

In [2]: for topic in Topic.objects.all():
   ...:     print(topic, topic.owner)
   ...: 
Python mt
C++ mt
JAVA mt
MATLAB mt
C# mt
C mt
PostScript mt
Perl mt

三、只允许访问自己的主题

  在views.py中对topics()函数进行修改:
  将代码:

topics = Topic.objects.order_by('date_added')

  换成

topics = Topic.objects.filter(owner=request.user).order_by('date_added')

  用filter(owner=request.user)函数添加一个过滤器,让用户只能访问自己的主题。完整代码如下:

@login_required
def topics(request):
    """显示所有的主题"""
    topics = Topic.objects.filter(owner=request.user).order_by('date_added')
    context = {'topics': topics}
    return render(request, 'learning_logs/topics.html', context)

四、限制访问

保护用户的主题

  在views.py中对topic()函数进行修改,添加如下代码:

    if topic.owner != request.user:  # 验证访问页面的用户是否是拥有页面的用户
        raise Http404

  修改后的函数:

@login_required
def topic(request, topic_id):
    topic = Topic.objects.get(id=topic_id)
    if topic.owner != request.user:  # 验证访问页面的用户是否是拥有页面的用户
        raise Http404
    entries = topic.entry_set.order_by('-date_added')
    context = {'topic': topic, 'entries': entries}
    return render(request, 'learning_logs/topic.html', context)

保护页面edit_entry

  在views.py中对edit_entry()函数进行修改,添加如下代码:

    if topic.owner != request.user:  # 验证访问页面的用户是否是拥有页面的用户
        raise Http404

  修改后的函数:

@login_required
def edit_entry(request, entry_id):
    """Edit an existing entry."""
    entry = Entry.objects.get(id=entry_id)
    topic = entry.topic
    if topic.owner != request.user:
        raise Http404

    if request.method != 'POST':
        # Initial request; pre-fill form with the current entry.
        form = EntryForm(instance=entry)
    else:
        # POST data submitted; process data.
        form = EntryForm(instance=entry, data=request.POST)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('learning_logs:topic',
                                                args=[topic.id]))

    context = {'entry': entry, 'topic': topic, 'form': form}
    return render(request, 'learning_logs/edit_entry.html', context)

五、将新主题关联到当前用户

  在views.py中对new_topic()函数进行修改:
  将代码:

form.save()

  替换成:

new_entry = form.save(commit=False)
            new_entry.topic = topic
            new_entry.save()

  修改后的函数:

@login_required
def new_entry(request, topic_id):
    """Add a new entry for a particular topic."""
    topic = Topic.objects.get(id=topic_id)
    if topic.owner != request.user:
        raise Http404

    if request.method != 'POST':
        # No data submitted; create a blank form.
        form = EntryForm()
    else:
        # POST data submitted; process data.
        form = EntryForm(data=request.POST)
        if form.is_valid():
            new_entry = form.save(commit=False)
            new_entry.topic = topic
            new_entry.save()
            return HttpResponseRedirect(reverse('learning_logs:topic',
                                                args=[topic_id]))

    # context = {'topic': topic, 'form': form, 'topic_id': topic_id}
    context = {'topic': topic, 'form': form}
    return render(request, 'learning_logs/new_entry.html', context)

添加主题结果

在这里插入图片描述


参考文献

  1. 《Python编程从入门到实践》:https://ehmatthes.github.io/pcc/
  2. Django帮助文档:https://docs.djangoproject.com/zh-hans/2.0/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值