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

在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)

最近更新

  1. TCP协议是安全的吗?

    2024-03-29 04:48:06       19 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-29 04:48:06       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-29 04:48:06       20 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-29 04:48:06       20 阅读

热门阅读

  1. vue表单rules校验是动态的

    2024-03-29 04:48:06       22 阅读
  2. postcss安装和使用

    2024-03-29 04:48:06       20 阅读
  3. 蓝桥杯2019年第十三届省赛真题-数列求值

    2024-03-29 04:48:06       24 阅读
  4. 网络安全渗透测试工具

    2024-03-29 04:48:06       24 阅读
  5. 题目 2894: 肿瘤检测

    2024-03-29 04:48:06       22 阅读
  6. 【深度学习】球衣号码识别 re-id追踪

    2024-03-29 04:48:06       20 阅读
  7. SpringBoot与Prometheus监控整合

    2024-03-29 04:48:06       21 阅读