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