Profile Page and Avatars (Profil Sayfası ve Avatarlar)
- Bu bölümde belirli bir kullanıcı için profil sayfasını oluşturmayı ve kullanıcıya avatar ekleme işlemini göreceğiz.
myapp/routes.py
modülündedef user(username)
adında bir method açıyoruz.
xxxxxxxxxx
route('/user/<username>') .
def user(username):
'''Kullanıcı detay sayfasını render eder'''
user = User.query.filter_by(username=username).first_or_404()
posts = [
{'author':user, 'body':"Deneme yayını 1"},
{'author':user, 'body':"Deneme yayını 2"},
{'author':user, 'body':"Deneme yayını 3"},
]
return render_template('user.html', title='Profil', user=user, posts=posts)
- Diğer URL'lerden farklı olarak en sonda
< >
işaretleri kullanılarak ve içine de username parametresi alan bir URL belirledik. Bu demek oluyor ki URL sonuna gelecek username ile her kullanıcı ismine özel profil sayfası görüntülenecek. Örneğin/user/adnan
dediğimizdeadnan
kullanıcısına ait profil sayfasını göreceğiz. def user(username)
methoduna dikkat ederseniz, method parametresi ile URL parametresi aynı string olarak belirlenmelidir.def user(kullanici)
dediğimizde hata ile karşılaşacağız. Stringlerin aynı olmasına dikkat edelim..first_or_404()
methodufirst()
methodunda farklı olarak, eğer kullanıcı yoksa404
hatası dönecek.- posts değişkeni ile de gösterim amaçlı geçici obje oluşturduk.
templates/user.html
dosyasını oluşturalım.
xxxxxxxxxx
{% extends 'base.html' %} {% block content%}
<h3>Hoşgeldin {{user.username }}</h3>
<hr>
<ul>
{%for post in posts %}
<li>
<p>
<b>{{post.author.username}} </b>:
<i>{{post.body}}</i>
</p>
</li>
{%endfor%}
</ul>
{% endblock %}
base.html
'e de aşağıdaki satırı ekleyelim.
xxxxxxxxxx
<td><a href="{{url_for('user', username=current_user.username)}}">Profil</a></td>
<td><a href="{{url_for('logout')}}">Çıkış Yap</a></td>
- Burada
url_for
methodunun ek olarak username parametresi aldığını görüyorsunuz. Mevcut kullanıcıyı (current_user.username
)url_for
methoduna verdik.
Avatar
- Profil sayfasını biraz daha güzelleştirmek için kullanıcılara avatar ekleyelim.
- Gravatar - Globally Recognized Avatars sitesinin sağladığı avatar oluşturma servisini kullanacağız. Büyük boyutlu resimler yüklemek yerine şimdilik bunu kullanalım.
- https://www.gravatar.com\/avatar/<hash> URL'ine kullanıcı e-mailini md5 ile hash'leyip vereceğiz. Örnek kullanım:
xxxxxxxxxx
>>> from hashlib import md5
>>> 'https://www.gravatar.com/avatar/'+md5(b'adnan@kaya.com').hexdigest()
'https://www.gravatar.com/avatar/b560759d7ebe1fe931ac633979bf4805'
s
parametresi ilesize
,d
parametresi ile avatar kaydı yapmamış kullanıcılara random avatar üretir.myapp/models.py
'daUser
modeline aşağıdaki methodu ekliyoruz.
xxxxxxxxxx
from hashlib import md5
#...
class User(UserMixin, db.Model):
#...
def avatar(self, size):
'''kullanıcı için avatar üretir'''
digest = md5(self.email.lower().encode('utf-8')).hexdigest()
return 'https://www.gravatar.com/avatar/{}?d=identicon&s={}'.format(
digest, size)
user.html
'i aşağıdaki gibi düzenleyelim.
xxxxxxxxxx
{% extends 'base.html' %}
{% block content%}
<table>
<tr valign="top">
<td><img src="{{ user.avatar(128) }}" /></td>
<td><h3>Hoşgeldin {{user.username }}</h3></td>
</tr>
</table>
<hr>
<ul>
{%for post in posts %}
<li>
<p>
<b>{{post.author.username}} </b>:
<i>{{post.body}}</i>
</p>
</li>
{%endfor%}
</ul>
{% endblock %}
Sub Templates
- Jinja2'nun bize sunduğu
include
sayesinde bir template'i başka bir template içerisine dahil edebiliriz. _post.html
adında bir sub template oluşturalım.
xxxxxxxxxx
<table>
<tr>
<td><img src="{{post.author.avatar(36)}}"/></td>
<td>{{post.author.username}} </td>
<td>{{post.body}}</td>
</tr>
</table>
user.html
'e bu template'i dahil edelim.
xxxxxxxxxx
{% extends 'base.html' %} {% block content%}
<table>
<tr valign="top">
<td>
<img src="{{ user.avatar(128) }}" />
</td>
<td>
<h3>Hoşgeldin {{user.username }}</h3>
</td>
</tr>
</table>
<hr>
{%for post in posts %}
{% include '_post.html' %}
{%endfor%}
{% endblock %}
'Hakkımda' bilgisi ve 'Son görülme tarihi' bilgisi ekleme
- Kullanıcı profillerine
about_me
velast_seen
ekleyelim. myapp/models.py
modülünü aşağıdaki gibi düzenleyelim.
xxxxxxxxxx
class User(UserMixin, db.Model):
#...
about_me = db.Column(db.String(280))
last_seen = db.Column(db.DateTime, default=datetime.utcnow)
- Şimdi modelimizin tablolarının oluşması için
migration
yapalım.
xxxxxxxxxx
(env) kayace@kayace-K53SV ~/flask/blog $ export FLASK_APP=main.py
(env) kayace@kayace-K53SV ~/flask/blog $ flask db migrate -m "about me and last seen have been added"
INFO [alembic.runtime.migration] Context impl SQLiteImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.autogenerate.compare] Detected added column 'user.about_me'
INFO [alembic.autogenerate.compare] Detected added column 'user.last_seen'
Generating /home/kayace/flask/blog/migrations/versions/207c92b4950a_about_me_and
_last_seen_have_been_added.py ... done
upgrade
komutunu unutmuyoruz.
xxxxxxxxxx
(env) kayace@kayace-K53SV ~/flask/blog $ flask db upgrade
INFO [alembic.runtime.migration] Context impl SQLiteImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.runtime.migration] Running upgrade 9d8ba8bdcb4e -> 207c92b4950a, about me and last seen have been added
Last seen (Son görülme) için
myapp/routes.py
modülünde düzenleme yapalım.
xxxxxxxxxx
from datetime import datetime
before_request .
def before_request():
if current_user.is_authenticated:
current_user.last_seen = datetime.utcnow()
db.session.commit()
@app.before_request
decorator Flask'ın bize sunduğu özelliktir. Gösterim fonksiyonları( template'leri render eden methodlar ) çalışmadan öncebefore_request
çalıştırılacak.before_request
methodumuz kullanıcının log-in olup olmadığına bakıyor.- Lokal zaman bilgisi yerine UTC zaman bilgisi kullanıyoruz yeniden.
current_user
referansını çağırdığımız zaman Flask-Login user loader callback fonksiyonunu çağırır. Bu fonksiyon mevcutuser
objesini database session'a ekler. Yani db.session.add uygulanır. Burada ikinci kez db.session.add yazmamıza gerek yok.- Profil sayfalarını yeniden görüntülediğinizde son görülme tarihini göreceksiniz.
- Bir kaç kullanıcı açıp onların profillerine girip son görülme tarihlerini görebilirsiniz.
Profil Sayfası Düzenleme Formu (Editing Profile)
- Profil sayfasını düzenlemek için bir adet form ekleyelim.
myapp/forms.py
modülünde:
xxxxxxxxxx
from wtforms import StringField, TextAreaField, SubmitField
from wtforms.validators import DataRequired, Length
# ...
class EditProfileForm(FlaskForm):
'''Kullanıcı profil düzenleme formu'''
username = StringField('Kullanıcı Adı', validators=[DataRequired()])
about_me = TextAreaField('Hakkımda', validators=[Length(min=0, max=280)])
submit = SubmitField('Submit')
- Burada
TextAreaField
kullandık. Hakkımda yazısı uzun olabilir. validators
kısmında daLength
kullandık. Kullanıcı minimum ve maksimum belirlenen karakter sayısı girebilir.
Şimdi profil düzenleme form template'ini oluşturalım.
templates/edit_profile.html
xxxxxxxxxx
{%extends 'base.html'%} {% block content %}
<h3>Profili Düzenle</h3>
<form action="" method="POST">
{{form.hidden_tag()}}
<table>
<tr>
<th>{{form.username.label}}</th>
<td>{{form.username(size=24)}}</td>
<td>
{% for error in form.username.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</td>
</tr>
<tr>
<th>{{form.about_me.label}}</th>
<td>{{form.about_me(cols=50, rows=4)}}</td>
<td>
{% for error in form.about_me.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</td>
</tr>
</table>
<p>{{form.submit()}}</p>
</form>
{% endblock %}
Ve son olarak gösterim fonksiyonunu (view function) yazlım.
myapp/routes.py
xxxxxxxxxx
from app.forms import EditProfileForm
#...
route('/edit_profile', methods=['GET', 'POST']) .
def edit_profile():
'''Kullanıcı bilgileri düzenleme sayfasını render eder'''
form = EditProfileForm()
if form.validate_on_submit():
current_user.username = form.username.data
current_user.about_me = form.about_me.data
db.session.commit()
flash("Değişiklikler kaydedildi.")
return redirect(url_for('edit_profile'))
elif request.method == 'GET':
form.username.data = current_user.username
form.about_me.data = current_user.about_me
return render_template('edit_profile.html', title='Edit Profile', form=form)
- Eğer kullanıcı formu submit etmişse (yani form bilgilerini doldurup kaydet, submit butonuna basmışsa) ; formdan alınan username ve about_me bilgilerini sisteme giriş yapmış kullanıcının(current_user) username ve about_me alanlarına atama yapıyoruz.
- Değişiklikler sonrası
edit_profile
sayfasınaflash
ile bilgi mesajı bırakıyoruz. - Eğer kullanıcı formu submit etmemişse; form alanlarına mevcut kullanıcının(current_user) username ve about_me bilgilerini dolduruyoruz(yerleştiriyoruz). Böylece kullanıcı profil düzenle dediği zaman varsa eski bilgileri form alanlarında görülecek.
Son olarak profil düzenleme sayfasına gitmek için bir link ekleyelim.
templates/user.html
içerisine aşağıdaki satırı ekliyoruz.
xxxxxxxxxx
{% extends 'base.html' %}
{% block content%}
{% if user == current_user%}
<a href="{{url_for('edit_profile')}}">Edit Profile</a>
{%endif%}
<hr />
...
- Burada
{% if user == current_user%}
kontrolü ileuser
, sisteme giriş yapmışcurrent_user
olmalı. Yani kullanıcı sadece kendi profilini düzenleyebilmeli!
Submit sonrası ...
Yorumlar