Python 从0开始 一步步基于Django创建项目(13)将数据关联到用户

文章描述了一个使用Django的city_infos应用程序如何将城市信息与用户关联,包括修改数据模型、更新数据库、实现用户权限控制,确保只有对应的用户可以查看和编辑相关条目。
摘要由CSDN通过智能技术生成

在city_infos应用程序中,每个城市信息条目是关联到城市的,所以只需要将城市条目关联到用户即可。

将数据关联到用户,就是把‘顶层’数据关联到用户。

设计思路:

1、修改顶层数据模型,向其中添加‘用户’属性

2、根据模型更新数据库

3、在数据显示部分,根据发起request的用户,显示与该用户匹配的内容

1)在cities页面显示与用户关联的city信息条目

2)在city页面,显示与那些city信息条目关联的具体信息

3)用户不能查看与自己不匹配的edit_entry页面,更不能进行编辑

4、将新主题关联到用户

5、确保主题下的新条目是其隶属的用户添加

步骤如下:

1、修改C:\D\Python\Python310\study\snap_gram\city_infos路径下的models.py文件。

首先在文件中包含django自带的User类。

from django.contrib.auth.models import User

然后修改City类

owner = models.ForeignKey(User,on_delete=models.CASCADE)

给City类添加owner属性,该属性值是User对象的ID,User对象的ID作为外键,与City对象相关联。采用级联删除,即删除对象的同时,删除该对象关联的City。

2、确认有哪些User对象的ID可用

使用django shell查询当前的用户信息。获得两个用户名称,及其ID。

(sg_env) C:\D\Python\Python310\study\snap_gram>python manage.py shell
Python 3.10.11 (tags/v3.10.11:7d4cc5a, Apr  5 2023, 00:38:17) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from django.contrib.auth.models import User
>>> User.objects.all()
<QuerySet [<User: sg_admin>, <User: 12344321>]>
>>> for user in User.objects.all():
...     print(user.username,user.id)
...
sg_admin 3
12344321 4
>>>

3、根据模型,更新数据库,

首先,生成数据库更新文件0002_city_owner。在文件中,要求将City表中,所有条目关联到ID为3的用户,即sg_admin

(sg_env) C:\D\Python\Python310\study\snap_gram>python manage.py makemigrations city_infos
It is impossible to add a non-nullable field 'owner' to city without specifying a default. This is because the database needs something to 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 manually define a default value in models.py.
Select an option: 1
Please enter the default value as valid Python.
The datetime and django.utils.timezone modules are available, so it is possible to provide e.g. timezone.now as a value.
Type 'exit' to exit this prompt
>>> 3
Migrations for 'city_infos':
  city_infos\migrations\0002_city_owner.py
    - Add field owner to city

其次,使用该更新文件,更新数据库。

(sg_env) C:\D\Python\Python310\study\snap_gram>python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, city_infos, contenttypes, sessions
Running migrations:
  Applying city_infos.0002_city_owner... OK

4、使用django shell查看city信息,确认数据库修改成功

(sg_env) C:\D\Python\Python310\study\snap_gram>python manage.py shell
Python 3.10.11 (tags/v3.10.11:7d4cc5a, Apr  5 2023, 00:38:17) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from city_infos.models import City
>>> for city in City.objects.all():
...     print(city.name,city.owner)
...
北京 sg_admin
墨尔本 sg_admin
悉尼 sg_admin
>>>

5、修改C:\D\Python\Python310\study\snap_gram\city_infos路径下的views.py文件,修改cities函数。使得登录用户只能查看隶属于自己的city条目。

@login_required
def cities(request):
    #request中包含发起请求的用户信息,核对用户信息与city的owner属性
    #用户信息一致,才能通过filter检查,展现出来
    cities = City.objects.filter(owner=request.user).order_by('date_added')
    context = {'cities':cities}
    return render(request,'city_infos/cities.html',context)

6、使用不同用户登录,查看cities页面

当以用户12344321登录时查看不到任何city信息,如下图所示:

以用户sg_admin登录时,则可查看到city信息,因为已经将这些信息全部关联到该用户。

7、修改C:\D\Python\Python310\study\snap_gram\city_infos路径下的views.py文件,修改city函数。使得登录用户只能查看隶属于自己的entry条目。

如果不做此处的修改,任何已登录的用户都可输入类似于http://localhost:8000/cities/1/的URL,来访问不隶属于自己的city主题的页面。

from django.http import Http404

@login_required
def city(request,city_id):
    city = City.objects.get(id=city_id)
    #核对用户,显示隶属于该用户的信息,否则抛出404错误
    if city.owner != request.user:
        raise Http404
    entries = city.entry_set.order_by('date_added')
    context = {'city':city,
               'entries':entries}
    return render(request,'city_infos/city.html',context)

8、修改C:\D\Python\Python310\study\snap_gram\city_infos路径下的views.py文件,修改edit_entry函数。使得登录用户只能查看隶属于自己的entry条目。

如果不做此处修改,将出现下图的问题。12344321用户查看了不隶属于自己的city的条目,并能够打开和编辑edit_entry页面

修改程序如下:

@login_required
def edit_entry(request,entry_id):
    #request=GET时,返回原有Entry内容,request=POST时,提交新Entry内容
    entry = Entry.objects.get(id=entry_id)  # 找到指定的entry
    city = entry.city
    
    #检查用户匹配
    if city.owner != request.user:
        raise Http404
    
    if request.method != 'POST':#初次请求,使用当前条目填充表单
        form = EntryForm(instance=entry)
    else:#处理POST提交的数据
        form = EntryForm(instance=entry, data=request.POST)
        if form.is_valid():  # Django自动检查提交数据的合法性
            form.save()
            return redirect('city_infos:city',city_id=city.id)  # 页面重定向
    context = {'entry':entry,'city': city, 'form': form}  # 程序不进入if块,或者没有通过有效性验证,都执行该行代码
    return render(request, 'city_infos/edit_entry.html', context)

9、修改C:\D\Python\Python310\study\snap_gram\city_infos路径下的views.py文件,修改new_city函数。将新主题关联到用户。

@login_required
def new_city(request):
    '''Add new City'''
    if request.method != 'POST':#未提交数据时,创建一个新表单,此时request.method=='GET'
        form = CityForm()
    else:#提交数据时
        form = CityForm(data=request.POST)#data是用户刚刚POST的数据,如此则form包含用户提交的数据
        if form.is_valid():#Django自动检查提交数据的合法性
            new_city = form.save(commit=False) #commit=False表示先不写库
            new_city.owner = request.user
            new_city.save() #改完了owner属性,然后写库
            return redirect('city_infos:cities')#页面重定向
    context = {'form':form}#程序不进入if块,或者没有通过有效性验证,都执行该行代码
    return render(request,'city_infos/new_city.html',context)

10、修改C:\D\Python\Python310\study\snap_gram\city_infos路径下的views.py文件,修改new_entry函数。确保新增条目隶属的city,隶属于当前用户。

@login_required
def new_entry(request,city_id):
    '''Add new Entry to specific city'''
    city = City.objects.get(id=city_id)#找到指定的city
    #核实用户
    if city.owner != request.user:
        raise Http404

    if request.method != 'POST':#未提交数据时,创建一个新表单,此时request.method=='GET'
        form = EntryForm()
    else:
        form = EntryForm(data=request.POST)  # data是用户刚刚POST的数据,如此则form包含用户提交的数据
        if form.is_valid():  # Django自动检查提交数据的合法性
            #commit=False的作用:让Django创建一个新条目,赋值给new_entry,但是不保存到数据
            new_entry = form.save(commit=False)
            #通过设定city,将新条目与指定city关联
            new_entry.city = city
            #再将新条目,保存到数据
            new_entry.save()
            return redirect('city_infos:city',city_id=city_id)  # 页面重定向
    context = {'city':city,'form':form}#程序不进入if块,或者没有通过有效性验证,都执行该行代码
    return render(request, 'city_infos/new_entry.html', context)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值