作者: zifanwang 发布于2020-05-16
编写userprofile/models.py:
from django.contrib.auth.models import User
from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver
class Profile(models.Model):
# 与User模型构成一对一的关系
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
phone = models.CharField(max_length=20, blank=True)
avatar = models.ImageField(upload_to='avatar/%Y%m%d/', blank=True)
bio = models.TextField(max_length=500, blank=True)
def __str__(self):
return 'user{}'.format(self.user.username)
# 信号接受函数,每当新建User实例时自动调用
@receiver(post_save, sender=User)
def create_user_profile(sender,instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
# 信号更新函数,每当更新User实例时自动调用
@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
每个Profile模型对应唯一的一个User模型,形成了对User的外接扩展,因此你可以在Profile添加任何想要的字段。 这种方法的好处是不需要对User进行任何改动,从而拥有完全自定义的数据表。 模型本身没有什么新的知识,比较神奇的是用到的信号机制。 接下来重建数据库, 安装pillow 在命令行输入:
pip install Pillow
然后迁移数据
C:\mysite>python manage.py makemigrations
System check identified some issues:
WARNINGS:
article.ArticlePost.created: (fields.W161) Fixed default value provided.
HINT: It seems you set a fixed date / time / datetime value as default for this field. This may not be what you want. If you want to have the current date as default, use `django.utils.timezone.now`
Migrations for 'article':
article\migrations\0004_auto_20200516_1827.py
- Alter field created on articlepost
Migrations for 'userprofile':
userprofile\migrations\0001_initial.py
- Create model Profile
C:\mysite>
C:\mysite>python manage.py migrate
System check identified some issues:
WARNINGS:
article.ArticlePost.created: (fields.W161) Fixed default value provided.
HINT: It seems you set a fixed date / time / datetime value as default for this field. This may not be what you want. If you want to have the current date as default, use `django.utils.timezone.now`
Operations to perform:
Apply all migrations: admin, article, auth, contenttypes, sessions, userprofile
Running migrations:
Applying article.0004_auto_20200516_1827... OK
Applying userprofile.0001_initial... OK
C:\mysite>
成功迁移数据库了。 在虚拟环境中输入python manage.py shell:
C:\mysite>python manage.py shell
Python 3.8.2 (tags/v3.8.2:7b3ab59, Feb 25 2020, 23:03:10) [MSC v.1916 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().delete()
(11, {'admin.LogEntry': 6, 'auth.User_groups': 0, 'auth.User_user_permissions': 0, 'article.ArticlePost': 4, 'userprofile.Profile': 0, 'auth.User': 1})
>>>
接下来为Profile模型新建一个表单类userprofile/forms.py去编辑它的内容:
from .models import Profile
...
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('phone', 'avatar', 'bio')
接下来在userprofile/views.py中填写处理用户信息的函数profile_edit:
from .froms import ProfileForm
from .models import Profile
...
# 编辑用户信息
@login_required(login_url='/userprofile/login/')
def profile_edit(request, id):
user = User.objects.get(id=id)
# user_id是OneToOneField自动生成的字段
profile = Profile.objects.get(user_id=id)
if request.method == 'POST':
# 验证修改数据者是否为本人
if request.user != user:
return HttpResponse("你没有权限修改次用户信息")
profile_form = ProfileForm(data=request.POST)
if profile_form.is_valid():
# 取得清洗后的合法数据
profile_cleaned_data = profile_form.cleaned_data
profile.phone = profile_cleaned_data['phone']
profile.bio = profile_cleaned_data['bio']
profile.save()
return redirect("userprofile:edit", id=id)
else:
return HttpResponse("注册表单输入有误,请重新输入")
elif request.method == "GET":
profile_form = ProfileForm()
context = {'profile_form': profile_form, 'profile': profile, 'user': user}
return render(request, 'userprofile/edit.html', context)
else:
return HttpResponse("请使用GET或POST请求数据")
接下来在templates/userprofile中新建模板文件edit.html并写入:
{% extends "base.html" %}
{% load static %}
{% block title %}
User
{% endblock title %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-12">
<br>
<div class="col-md-4">Username {{ user.username }}</div>
<br>
<form method="post" action=".">
{% csrf_token %}
<div class="form-group col-md-4">
<label for="phone">phone</label>
<input type="text" class="form-control" id="phone" name="phone" value="{{ profile.phone }}">
</div>
<div class="form-group col-md-4">
<label for="bio">bio</label>
<textarea type="text" class="form-control" id="bio" name="bio" rows="12">{{ profile.bio }}</textarea>
</div>
<button type="submit" class="btn btn-primary">submit</button>
</form>
</div>
</div>
</div>
{% endblock content %}
下一步配置userprofile/urls.py:
path('edit/<int:id>/', views.profile_edit, name='edit'),
接下来给人个信息添加一个入口 修改templates/header.html:
...
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="{% url "userprofile:edit" user.id %}">User</a>
<a class="dropdown-item" href="{% url "userprofile:logout" %}">Exit</a>
<a class="dropdown-item" href="#" onclick="user_delete()">Delete</a>
</div>
...
接下来修改article/views.py视图,前面为了简单就把所有文章的作者全部绑定为用户id为1的用户, 还没有对用户登陆状态进行检查:
...
from django.contrib.auth.decorators import login_required
...
@login_required(login_url='/userprofile/login')
def article_create(request):
...
new_article = article_post_form.save(commit=False)
new_article.author = User.objects.get(id=request.user.id)
new_article.save()
...
运行服务器(python manage.py runserver):
点击用户信息后就可以编辑和查看了。
在admin中将User profile合并为一张完整的表格:修改userprofile/admin.py:
from django.contrib import admin
from userprofile.models import Profile
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.models import User
class ProfileInline(admin.StackedInline):
model = Profile
can_delete = False
verbose_name_plural = 'UserProfile'
# 将Profile关联到User中
class UserAdmin(BaseUserAdmin):
inlines = (ProfileInline, )
# 重新注册User
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
打开admin中的User表(http://127.0.0.1:8000/admin/auth/user/),点进一个用户就可以看见Profile的数据已经堆叠在底部了。