Bagaimana cara memformat tanggal di Jinja2?

183

Menggunakan Jinja2, bagaimana cara memformat bidang tanggal? Saya tahu dengan Python saya bisa melakukan ini:

print(car.date_of_manufacture.strftime('%Y-%m-%d'))

Tapi bagaimana cara memformat tanggal di Jinja2?

Ambrosio
sumber

Jawaban:

327

Ada dua cara untuk melakukannya. Pendekatan langsung adalah dengan memanggil (dan mencetak) metode strftime () dalam template Anda, misalnya

{{ car.date_of_manufacture.strftime('%Y-%m-%d') }}

Lain, pendekatan yang jauh lebih baik adalah dengan mendefinisikan filter Anda sendiri, misalnya:

from flask import Flask
import babel

app = Flask(__name__)

@app.template_filter()
def format_datetime(value, format='medium'):
    if format == 'full':
        format="EEEE, d. MMMM y 'at' HH:mm"
    elif format == 'medium':
        format="EE dd.MM.y HH:mm"
    return babel.dates.format_datetime(value, format)

(Filter ini didasarkan pada babel karena alasan mengenai i18n, tetapi Anda juga dapat menggunakan strftime). Keuntungan dari filter ini adalah, Anda dapat menulis

{{ car.date_of_manufacture|datetime }}
{{ car.date_of_manufacture|datetime('full') }}

yang terlihat lebih bagus dan lebih mudah dikelola. Filter umum lainnya juga adalah filter "timedelta", yang mengevaluasi ke sesuatu seperti "ditulis 8 menit yang lalu". Anda dapat menggunakannya babel.dates.format_timedeltauntuk itu, dan mendaftarkannya sebagai filter yang mirip dengan contoh waktu yang diberikan di sini.

tux21b
sumber
2
Apakah Anda benar-benar mencobanya? menyebutnya secara langsung menghasilkan: 'objek time.struct_time' tidak memiliki atribut 'strftime'
Karl P
7
Menurut pertanyaan Anda, Anda berbicara tentang sesuatu yang berbeda. Awal, utas ini adalah tentang memformat datetimeobjek dari modul python datetime, tetapi Anda mencoba memformat struct_timeobjek dari timemodul tingkat rendah . struct_timeobjek tidak memiliki strftime()metode, walaupun mungkin ada strftime()metode global dalam paket waktu. Tetapi saya menyarankan Anda untuk menggunakan paket tingkat tinggi (platform independen) datetimesebagai gantinya.
tux21b
2
Saya pikir maksud Andababel.dates.format_datetime(value, format)
johnboiles
2
mendefinisikan filter baru, sama sekali tidak lebih baik. Lebih banyak kode untuk ditulis = lebih banyak kode yang harus dipelihara = lebih banyak kode untuk diuraikan, bit-cache (jika digunakan) dan ditafsirkan. Salah satu keuntungan besar menggunakan Jinja2 adalah kemampuan menulis kode python kecil di dalam template. Beberapa keuntungan kinerja, dibandingkan dengan sistem template Django, berasal dari itu.
StefanNch
4
@StefanNch "mendefinisikan filter baru, sama sekali tidak lebih baik". Itu bisa: jika filter dipanggil berkali-kali di templat, ini menghindari pengulangan format string, dan dapat menghasilkan kode yang lebih sedikit. Dan yang lebih penting, kode yang kurang diulang , dengan menambahkan abstrasi.
jacquev6
21

Inilah filter yang akhirnya saya gunakan untuk strftime di Jinja2 dan Flask

@app.template_filter('strftime')
def _jinja2_filter_datetime(date, fmt=None):
    date = dateutil.parser.parse(date)
    native = date.replace(tzinfo=None)
    format='%b %d, %Y'
    return native.strftime(format) 

Dan kemudian Anda menggunakan filter seperti ini:

{{car.date_of_manufacture|strftime}}
Raj
sumber
2
Kenapa begitu dateutildan native?
gwg
15

Jika Anda berurusan dengan objek waktu level yang lebih rendah (saya sering hanya menggunakan bilangan bulat), dan tidak ingin menulis filter khusus untuk alasan apa pun, pendekatan yang saya gunakan adalah meneruskan fungsi strftime ke template sebagai variabel, di mana itu bisa disebut di mana Anda membutuhkannya.

Sebagai contoh:

import time
context={
    'now':int(time.time()),
    'strftime':time.strftime }  # Note there are no brackets () after strftime
                                # This means we are passing in a function, 
                                # not the result of a function.

self.response.write(jinja2.render_template('sometemplate.html', **context))

Yang kemudian dapat digunakan dalam sometemplate.html:

<html>
    <body>
        <p>The time is {{ strftime('%H:%M%:%S',now) }}, and 5 seconds ago it was {{ strftime('%H:%M%:%S',now-5) }}.
    </body>
</html>
Olly FG
sumber
7

Anda dapat menggunakannya seperti ini di template tanpa filter

{{ car.date_of_manufacture.strftime('%Y-%m-%d') }}
Zaytsev Dmitry
sumber
0

dalam labu, dengan babel, saya suka melakukan ini:

@app.template_filter('dt')
def _jinja2_filter_datetime(date, fmt=None):
    if fmt:
        return date.strftime(fmt)
    else:
        return date.strftime(gettext('%%m/%%d/%%Y'))

digunakan dalam templat dengan {{mydatetimeobject|dt}}

jadi tidak dengan babel Anda dapat menentukan berbagai format Anda di messages.po seperti ini misalnya:

#: app/views.py:36
#, python-format
msgid "%%m/%%d/%%Y"
msgstr "%%d/%%m/%%Y"
euri10
sumber