User Profiles:
create app profiles:
create a user profile app
[root@localhost Twittme]# python3 ./manage.py startapp profiles
define the model in /profiles/models.py ```python from django.db import models from django.conf import settings
User = settings.AUTH_USER_MODEL
class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) # A OneToOneField is essentially the same as a ForeignKey location = models.CharField(max_length=220, null=True, blank=True) # allow null and blank bio = models.TextField(blank=True, null=True)
- register the app in /Twittme/settings.py```pythonINSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles',# third-party'rest_framework','corsheaders',# internal'accounts','profiles','tweets',]
because we have new models created, make migrations and migrate
[root@localhost Twittme]# python3 ./manage.py makemigrationsMigrations for 'profiles':profiles/migrations/0001_initial.py- Create model Profile[root@localhost Twittme]# python3 ./manage.py migrateOperations to perform:Apply all migrations: admin, auth, contenttypes, profiles, sessions, tweetsRunning migrations:Applying profiles.0001_initial... OK
use another url file to handle the path:
create /profiles/urls.py ```python from django.urls import path
from .views import profile_detail_view
urlpatterns = [
path(‘
- because we are creating a profile handler remove tweets_profile_view in /tweets/views.py```python# def tweets_profile_view(request, username, *args, **kwargs):# return render(request, "tweets/profile.html", context={"profile_username": username})
- modify /Twittme/urls.py
```python
from tweets.views import (
tweets_list_view,
tweets_detail_view,
tweets_profile_view,
)
urlpatterns = [
path(‘admin/‘, admin.site.urls),
path(‘api/tweets/‘, include(‘tweets.api.urls’)),
path(‘’, tweets_list_view),
path(‘login/‘, login_view),
path(‘logout/‘, logout_view),
path(‘register/‘, register_view),
path(‘
# path('profile/<str:username>', tweets_profile_view),re_path(r'profiles?/', include('profiles.urls')), # redirect to /profiles/urls.py
]
- create directory /templates/profiles- move /templates/tweets/profile.html into /templates/profiles- modify and rename it into detail.html```html{% extends 'base.html' %}{% block content %}<!--<div id='tweetme-2'data-username="{{ profile_username }}"data-can-tweet="false"></div>--><div id='tweetme-2'data-username="{{ username }}"data-can-tweet="false"></div>{% endblock content %}
to test, runserver and access
http://localhost/profiles/[username]
if that user exists, it will be a tweet list of those tweets sent by that user
if that user does not exist, it will show an empty tweet list.
Handling Profile Does Not Exist:
This case is to handle the last situation “if the user that send request about the profile does not exist”
import 404:
- import Http404 in /profiles/views.py ```python from django.shortcuts import render from django.http import Http404
from .models import Profile
def profile_detail_view(request, username, args, *kwargs):
# get the profile for passed usernameqs = Profile.objects.filter(user__username=username)if not qs.exists(): # if user don't exist, return 404raise Http404profile_obj = qs.first() # pick up profile objectscontext = {"username": username,"profile": profile_obj,}# return render(request, "profiles/detail.html", {"username": username})return render(request, "profiles/detail.html", context)
to test, runserver and try to access a profile with a user that does not exist<br />successfully get status 404.<br /><a name="oDgUG"></a>### Signals to Create Profile Objects:There are some built in signals that can be sent when a specific actions is done, such as creating new users. <br />We will apply signals to create profile for new created news.- add signal post_save and function user_did_save() in /profiles/models.py```python# ...from django.db.models.signals import post_save # newUser = settings.AUTH_USER_MODEL# ...def user_did_save(sender, instance, created, *args, **kwargs): # newProfile.objects.get_or_create(user=instance)if created:Profile.objects.get_or_create(user=instance)post_save.connect(user_did_save, sender=User) # new
- runserver, click save for every users in http://localhost/admin/ to make sure profiles are created.

- to double check, modify /profiles/admin.py ```python from django.contrib import admin
from .models import Profile
admin.site.register(Profile)
reboot the server, access admin page<br />and we have a profile list, and each profile is corresponding to a user. <br /><br />- remove the first objects.get_or_create() cause we already have profiles for current users in /profiles/models.py```python# ...def user_did_save(sender, instance, created, *args, **kwargs):# Profile.objects.get_or_create(user=instance)if created:Profile.objects.get_or_create(user=instance)post_save.connect(user_did_save, sender=User)
User = settings.AUTH_USER_MODEL
…
def user_did_save(sender, instance, created, args, *kwargs): # new Profile.objects.get_or_create(user=instance) if created: Profile.objects.get_or_create(user=instance)
post_save.connect(user_did_save, sender=User) # new
to test, create another user<br /><br />and see "Profiles" in admin site<br />a profile which the user is the newly created one is created. <br /><br /><a name="etg56"></a>### Save 2 Models in 1 Form and 1 View:- create /profiles/forms.py```pythonfrom django import formsfrom django.contrib.auth import get_user_modelfrom .models import ProfileUser = get_user_model()class ProfileForm(forms.ModelForm):first_name = forms.CharField(required=False)last_name = forms.CharField(required=False)email_address = forms.CharField(required=False)class Meta:model = Profilefields = ['location', 'bio']
and in admin site user page, we have a “personal info”
- add profile_update_view in /profiles/views.py ```python from django.shortcuts import render from django.http import Http404
from .models import Profile from .forms import ProfileForm # new
def profile_update_view(request, args, *kwargs): # new if not request.user.is_authenticated: # is_authenticated() return redirect(“/login?next=/profile/update”) user = request.user my_profile = request.user.profile form = ProfileForm(request.POST or None, instance=my_profile) if form.is_valid(): profile_obj = form.save(commit=False) first_name = form.cleaned_data.get(‘first_name’) last_name = form.cleaned_data.get(‘last_name’) email_address = form.cleaned_data.get(‘email_address’) user.first_name = first_name user.last_name = last_name user.email_address = email_address user.save() profile_obj.save() context = { “form”: form, “btn_label”: “Save”, “title”: “Update Profile” } return render(request, “profiles/form.html”, context)
…
- create rendered HTML file /templates/profiles/form.html```html{% extends "base.html" %}{% block content %}<div class='col-10 col-md-4 mx-auto'><h1>{{ title }}</h1>{% if description %}<p>{{ description }}</p>{% endif %}{% include "components/form.html" with form=form btn_label=btn_label %}</div>{% endblock content %}
- add a path in /profiles/urls.py ```python from django.urls import path
from .views import profile_detail_view, profile_update_view # new
urlpatterns = [
path(‘edit’, profile_update_view), # new
path(‘
to test, runserver<br />access [http://localhost/profile/edit](http://localhost/profile/edit/)<br /><br />we have a update profile here.- we separate 3 forms for different uses in /profiles/forms.py```pythonfrom django import formsfrom django.contrib.auth import get_user_modelfrom .models import ProfileUser = get_user_model()# class ProfileForm(forms.ModelForm):# first_name = forms.CharField(required=False)# last_name = forms.CharField(required=False)# email_address = forms.CharField(required=False)# class Meta:# model = Profile# fields = ['location', 'bio']# newclass UserProfileForm(forms.ModelForm):location = forms.CharField(required=False)bio = forms.CharField(required=False)class Meta:model = Userfields = ['first_name', 'last_name', 'email']# newclass ProfileForm(forms.ModelForm):first_name = forms.CharField(required=False)last_name = forms.CharField(required=False)email = forms.CharField(required=False)class Meta:model = Profilefields = ['location', 'bio']# newclass ProfileBasicForm(forms.Form):first_name = forms.CharField(required=False)last_name = forms.CharField(required=False)email_address = forms.CharField(required=False)location = forms.CharField(required=False)bio = forms.CharField(required=False)
- changed name in and /profiles/views.py
to test, reboot the server and access http://localhost/profile/editdef profile_update_view(request, *args, **kwargs):if not request.user.is_authenticated: # is_authenticated()return redirect("/login?next=/profile/update")user = request.useruser_data = { # new"first_name": user.first_name,"last_name": user.last_name,"email": user.email}my_profile = request.user.profile# form = ProfileForm(request.POST or None, instance=my_profile)form = ProfileForm(request.POST or None,instance=my_profile, initial=user_data) # fill in hse data if existsif form.is_valid():profile_obj = form.save(commit=False)first_name = form.cleaned_data.get('first_name')last_name = form.cleaned_data.get('last_name')# email_address = form.cleaned_data.get('email_address')email = form.cleaned_data.get('email') # to fit changed nameuser.first_name = first_nameuser.last_name = last_name# user.email_address = email_addressuser.email = email # to fit changed nameuser.save()profile_obj.save()context = {"form": form,"btn_label": "Save","title": "Update Profile"}return render(request, "profiles/form.html", context)
we have a prepared first and last name
fill in something
save, and check admin site:
the edit step is successful.
