Kerangka kerja "sites"¶
Django datang dengan sebuah pilihan kerangka kerja "sites". Itu adalah pengait untuk obyek-obyek terkait dan kegunaannya untuk situs jaringan tertentu, dan itu adalah tempat menahan untuk nama ranah dan nama-nama "verbose" dari situs-situs anda ditenagai-Django.
Gunakan itu jika pemasangan Django tunggal anda mentenagai lebih dari satu situs dan anda butuh membedakan diantara situs-situs tersebut dalam beberapa cara.
Kerangka kerja situs utamanya berdasarkan pada model sederhana:
-
class
models.
Site
¶ Sebuah model untuk menyimpan atribut
domain
danname
dari situs jaringan.-
domain
¶ Nama ranah memenuhi syarat sepenuhnya terkait dengan situs jaringan. Sebagai contoh,
www.example.com
.
-
name
¶ Nama "verbose" dibaca-manusia untuk situ sjaringan.
-
Pengaturan SITE_ID
menentukan ID basisdata dari obyek Site
terkait dengan berkas pengaturan tertentu itu. Jika pengaturan dihilangkan, fungsi get_current_site()
akan mencoba untuk mendapatkan situs saat ini dengan membandingkan domain
dengan nama rumah dari metode request.get_host()
.
Bagaimana anda menggunakannya terserah anda, tetapi Django menggunakan itu dalam sepasang cara otomatis melalui kebiasanaan sederhana.
Contoh penggunaan¶
Mengapa anda menggunakan situs? Ini adalah penjelasan terbaik melalui contoh.
Isi terkait dengan situs-situs banyak¶
Situs-situs ditenagai-Django LJWorld.com dan Lawrence.com dikendalikan oleh organisasi berita yang sama -- surat kabar Lawrence Journal-World di Lawrence, Kansas. LJWorld.com fokus pada berita, selagi Lawrence.com fokus pada hiburan lokal. Tetapi terkadang penyunting ingin menerbitkan sebuah artikel pada kedua situs.
Cara pemecahan tidak dibuat-buat dari memecahkan masalah yaitu membutuhkan pembuat situs untuk menerbitkan cerita sama dua kali: sekali untuk LJWorld.com dan kembali untuk Lawrence.com. Tetapi itu tidak efesien untuk pembuat situs, dan itu berulang untuk menyimpan banyak salinan dari cerita sama dalam basisdata.
Pemecahan terbaik adalah sederhana: Kedua situs menggunakanbasisdata artikel yang sama, dan sebuah artikel berhubungan dengan satu atau lebih situs. Dalam istilah model Django, yaitu diwakili oleh sebuah ManyToManyField
dalam model Article
:
from django.contrib.sites.models import Site
from django.db import models
class Article(models.Model):
headline = models.CharField(max_length=200)
# ...
sites = models.ManyToManyField(Site)
Ini menyelesaikan beberapa hal cukup baik:
Itu membiarkan pembuat situs menyunting semua isi -- pada kedua situs -- dalam antarmuka tunggal (admin Django).
Itu berarti cerita sams tidak harus menerbitkan kedua kali di basisdata; itu hanya mempunyai rekaman tunggal di basisdata.
Itu membiarkan pengembang situs menggunakan kode tampilan Django sama untuk kedua situs. Kode tampilan yang memperlihatkan cerita yang diberikan cukup memeriksa untuk memastikan cerita diminta pada situs saat ini. Itu terlihat sesuatu seperti ini:
from django.contrib.sites.shortcuts import get_current_site def article_detail(request, article_id): try: a = Article.objects.get(id=article_id, sites__id=get_current_site(request).id) except Article.DoesNotExist: raise Http404("Article does not exist on this site") # ...
Isi terkait dengan situs tunggal¶
Demikian pula, anda dapat menghubungkan sebuah model ke model Site
dalam sebuah hubungan many-to-one, menggunakan ForeignKey
.
Sebagai contoh, jika sebuah artikel hanya diizinkan pada situs tunggal, anda akan menggunakan model seperti ini:
from django.contrib.sites.models import Site
from django.db import models
class Article(models.Model):
headline = models.CharField(max_length=200)
# ...
site = models.ForeignKey(Site, on_delete=models.CASCADE)
Ini mempunyai keuntungan sama seperti digambarkan di bagian terakhir.
Mengaitkan kedalam situs saat ini dari tampilan¶
Anda dapat menggunakan kerangka kerja situs di tampilan Django anda untuk melakukan hal-hal tertentu berdasarkan pada situs dimana tampilan sedang dipanggil. Sebagai contoh:
from django.conf import settings
def my_view(request):
if settings.SITE_ID == 3:
# Do something.
pass
else:
# Do something else.
pass
Tentu saja, itu adalah kode-keras buruk ID situs seperti itu. pengkodean-keras semacam ini adalah terbaik untuk diperbaiki yang anda butuh diselesaikan cepat. Cara terbersih dari memenuhi hal sama adalah memeriksa ranah situs saat ini:
from django.contrib.sites.shortcuts import get_current_site
def my_view(request):
current_site = get_current_site(request)
if current_site.domain == 'foo.com':
# Do something
pass
else:
# Do something else.
pass
Ini juga mempunyai keuntungan dari pemeriksaan jika kerangka kerja situs dipasang, dan mengembalikan contoh RequestSite
jika itu tidak.
Jika anda tidak mempunyai akses ke obyek diminta, anda dapat menggunakan metode get_current()
dari pengelola model Site
. Anda harus kemudian memastikan bahwa berkas pengaturan anda mengandung pengaturan SITE_ID
. Contoh ini adalah setara pada satu sebelumnya:
from django.contrib.sites.models import Site
def my_function_without_request():
current_site = Site.objects.get_current()
if current_site.domain == 'foo.com':
# Do something
pass
else:
# Do something else.
pass
Mendapatkan ranah saat ini untuk ditampilkan¶
LJWorld.com dan Lawrence.com keduanya memiliki kegunakan peringatan surel, yang membuat pembaca masuk untuk mendapatkan pemberitahuan ketika berita terjadi. itu adalah dasar: Seorang pembaca masuk pada formulir Jaringan dan segera mendapatkan sebuah surel berkata, "Terima kasih untuk langganan anda."
Itu sangat tidak efesien dan berulang untuk menerapkan kode pengolahan daftar ini dua kali, jadi situs menggunakan kode sama dibelakang layar. Tetapi pemberitahuan "thank you for signing up" butuh berbeda untuk setiap situs. Dengan menggunakan obyek Site
, kami dapat meringkaskan pemberitahuan "thank you" untuk menggunakan nilai dari name
dan domain
situs saat ini.
Disini adalah contoh dari apa tampilan penanganan formulir kelihatannya:
from django.contrib.sites.shortcuts import get_current_site
from django.core.mail import send_mail
def register_for_newsletter(request):
# Check form values, etc., and subscribe the user.
# ...
current_site = get_current_site(request)
send_mail(
'Thanks for subscribing to %s alerts' % current_site.name,
'Thanks for your subscription. We appreciate it.\n\n-The %s team.' % (
current_site.name,
),
'editor@%s' % current_site.domain,
[user.email],
)
# ...
Pada Lawrence.com, surel ini mempunyai baris judul "peringatan Terima kasih untuk berlanggakan di lawrence.co." Pada LJWorld.com, surel mempunyai judul "peringatan Terima kasih untuk berlangganan di LJWorld.com." Sama seperti badan pesan surel.
Catat bahwa bahkan lebih elastis (tetapi lebih kelas berat) cara melakukan ini akan menggunakan sistem cetakan Django. Menganggap Lawrence.com dan LJWorld.com mempunyai direktori cetakan berbeda (DIRS
), anda cukup bertani sistem cetakan seperti itu:
from django.core.mail import send_mail
from django.template import Context, loader
def register_for_newsletter(request):
# Check form values, etc., and subscribe the user.
# ...
subject = loader.get_template('alerts/subject.txt').render(Context({}))
message = loader.get_template('alerts/message.txt').render(Context({}))
send_mail(subject, message, '[email protected]', [user.email])
# ...
Dalam kasus ini, anda harus membuat berkas cetakan subject.txt
dan message.txt
untuk kedua direktori cetakan LJWorld.com and Lawrence.com. Itu memberikan anda lebih keluwesan, tetapi itu juga lebih rumit.
itu adalah ide bagus membuka obyek Site
sebanyak mungkin untuk memindahkan kerumitan dan perulangan yang tidak diperlukan.
Mendapatkan ranah saat ini untuk URL penuh¶
Kaidah get_absolute_url()
Django baik untuk mendapatkan URL obyek anda tanpa nama ranah, tetapi dalam beberapa kasus anda mungkin ingin menampilkan URL penuh -- dengan http://
dan ranah dan semuanya -- untuk sebuah obyek. Untuk melakukan ini, anda dapat menggunakan kerangka kerja situs. Contoh sederhana:
>>> from django.contrib.sites.models import Site
>>> obj = MyModel.objects.get(id=3)
>>> obj.get_absolute_url()
'/mymodel/objects/3/'
>>> Site.objects.get_current().domain
'example.com'
>>> 'https://%s%s' % (Site.objects.get_current().domain, obj.get_absolute_url())
'https://example.com/mymodel/objects/3/'
Mengadakan kerangka situs¶
Untuk mengadakan kerangka situs ini, ikuti langkah-langkah ini:
Menambahkan
'django.contrib.sites'
ke pengaturanINSTALLED_APPS
anda.Menentukan pengaturan
SITE_ID
:SITE_ID = 1
Menjalankan
migrate
.
django.contrib.sites
mendaftarkan penangan sinyal post_migrate
yang membuat situs awalan bernama example.com
dengan ranah example.com
. Situs ini akan juga dibuat setelah Django basisdata percobaan. Untuk mensetel nama benar dan ranah untuk proyek anda, anda dapat menggunakan data migration.
Untuk melayani situs berbeda dalam produksi, anda aakn membuat berkas pengaturan dengan setiap SITE_ID
(mungkin mengimpor dari berkas pengaturan umum untuk menghindari penggandaan pengaturan berbagi) dan kemudian menentukan DJANGO_SETTINGS_MODULE
sesuai untuk setiap situs.
Men cache obyek Site
saat ini¶
Ketika situs saat ini disimpan dalam basisdata, setiap panggilan pada Site.objects.get_current()
dapat menghasilkan sebuah permintaan basisdata. Tetapi Django sedikit lebih pintar pada permintaan pertama, situs saat ini disimpan sementara, dan panggilan selanjutnya apapun mengembalikan data disimpan sementara daripada mengenai basisdata.
Jika untuk alasan apapun anda ingin memaksa permintaan basisdata, anda dapat memberitahu Django untuk membersihkan cache menggunakan Site.objects.clear_cache()
:
# First call; current site fetched from database.
current_site = Site.objects.get_current()
# ...
# Second call; current site fetched from cache.
current_site = Site.objects.get_current()
# ...
# Force a database query for the third call.
Site.objects.clear_cache()
current_site = Site.objects.get_current()
CurrentSiteManager
¶
-
class
managers.
CurrentSiteManager
¶
Jika Site
memainkan sebuah peran kunci dalam apliaksi anda, pertimbangkan menggunakan CurrentSiteManager
membantu dalam model anda. Itu adalah sebuah model manager yang otomatis menyaring permintaannya untuk menyertakan obyek apapun berkaitan dengan Site
saat ini.
SITE_ID
wajib
CurrentSiteManager
hanya berguna ketika pengaturan SITE_ID
ditentukan dalam pengaturan anda.
Gunakan CurrentSiteManager
dengan menambahkan itu ke model anda dengan tegas. Sebagai contoh:
from django.contrib.sites.models import Site
from django.contrib.sites.managers import CurrentSiteManager
from django.db import models
class Photo(models.Model):
photo = models.FileField(upload_to='photos')
photographer_name = models.CharField(max_length=100)
pub_date = models.DateField()
site = models.ForeignKey(Site, on_delete=models.CASCADE)
objects = models.Manager()
on_site = CurrentSiteManager()
Dengan model ini, Photo.objects.all()
akan mengembalikan semua obyek Photo
dalam basisdata, tetapi Photo.on_site.all()
akan mengembalikan hanya obyek Photo
berkaitan dengan situs saat ini, menurut pada pengaturan SITE_ID
.
Taruh di jalan lain, dua pernyataan ini adalah sama:
Photo.objects.filter(site=settings.SITE_ID)
Photo.on_site.all()
Bagaimana CurrentSiteManager
mengetahui bidang mana dari Photo
adalah the Site
? Secara awalan, CurrentSiteManager
mencari salah satu ForeignKey
dipanggil site
atau ManyToManyField
dipanggil sites
untuk menyaring. Jika anda menggunakan sebuah bidang bernama sesuatu selain dari site
atau sites` untuk mencirikan obyek Site
mana terkait, kemudian butuh secara tegas melewatkan nama bidang penyesuaian sebagai parameter pada CurrentSiteManager
di model anda. Model berikut, yang mempunyai bidang disebut publish_on
, mempertunjukkan ini:
from django.contrib.sites.models import Site
from django.contrib.sites.managers import CurrentSiteManager
from django.db import models
class Photo(models.Model):
photo = models.FileField(upload_to='photos')
photographer_name = models.CharField(max_length=100)
pub_date = models.DateField()
publish_on = models.ForeignKey(Site, on_delete=models.CASCADE)
objects = models.Manager()
on_site = CurrentSiteManager('publish_on')
Jika anda berusaha menggunakan CurrentSiteManager
dan melewatkan sebuah bidang nama yang tidak ada, Django akan memunculkan sebuah ValueError
.
Akhirnya, catat bahwa anda mungkin ingin menjaga Manager
biasa (bukan-situs-khusus) pada model anda, bahkan jika anda menggunakan CurrentSiteManager
. Seperti dijelaskan dalam manager documentation, jika anda menentukan pengelola secara manual, kemudian Django tidak akan membuat pengeloa objects = models.Manager()
otomatis untuk anda. Juga catat bahwa bagian tertentu dari Django -- yaitu, situs admin Django dan tampilan umum -- gunakan pengelola mana saja ditentukan pertama dalam model, jadi jika anda ingin situs admin memiliki akses ke semua obyek (bukan hanya satu situs-khusus), taruh objects = models.Manager()
dalam model anda, sebelum anda menentukan CurrentSiteManager
.
Situs middleware¶
Jika anda sering menggunakan pola ini:
from django.contrib.sites.models import Site
def my_view(request):
site = Site.objects.get_current()
...
ada cara sederhana untuk menghindari perulangan. tambah django.contrib.sites.middleware.CurrentSiteMiddleware
pada MIDDLEWARE
. Middleware menyetel atribut site
pada setiap permintaan obyek, jadi anda dapat menggunakan request.site
untuk mendapatkan situs saat ini.
Bagaimana Django menggunakan kerangka situs¶
Meskipun itu tidak diwajibkan bahwa anda menggunakan kerangka kerja situs, itu sangat dianjurkan, karena Django mengambil keuntungan dari itu dalam sedikit tempat. bahkan jika pemasangan Django anda menenagai hanya situs tunggal, anda harus mengambil dua detik untuk membuat obyek situs dengan domain
dan name
, dan menunjuk ke ID dalam pengaturan SITE_ID
anda.
Ini adalah bagaimana Django menggunakan kerangka situs:
- Dalam
redirects framework
, setiap obyek pengalihan berkaitan dengan situs stertentu. Ketika Django mencari untuk pengalihan, itu menghitung situs saat ini. - Dalam
flatpages framework
, setiap flatpage dihubungkan dengan situs tertentu. Ketika sebuah flatpage dibuat, anda menentukanSite
nya, danFlatpageFallbackMiddleware
memeriksa situs saat ini dalam mengambil flatpage untuk dimunculkan. - Dalam
syndication framework
, cetakan untuktitle
dandescription
otomatis mempunyai akses ke variabel{{site}}
, yaitu obyek which is theSite
mewakili situs saat ini. Juga, kaitan untuk menyediakan barang URL akan menggunakandomain
dari obyekSite
saat ini jika anda tidak menentukan ranah berkualitas-sepenuhnya. - Dalam
authentication framework
,django.contrib.auth.views.LoginView
melewatkan namaSite
sat ini ke cetakan sebagai{{ site_name }}
. - Tampilan jalan pintas (
django.contrib.contenttypes.views.shortcut
) menggunakan ranah dari obyekSite
saat ini ketika menghitung sebuah URL obyek. - Dalam kerangka kerja admin, tautan "lihat pada situs" menggunakan
Site
saat ini untuk bekerja ranah untuk situs yang itu akan alihkan.
Obyek RequestSite
¶
Beberapa aplikasi django.contrib mengambil keuntungan dari kerangka kerja situs tetapi dirancang dengan cara yang tidak membutuhkan kerangka kerja situs untuk dipasang dalam basisdata anda. (Beberapa orang tidak ingin, atau hanya tidak dapat memasang tabel tambahan basisdata yang kerangka kera situs butuhkan.) Untuk kasus-kasus itu, kerangka kerja menyediakan sebuah kelas django.contrib.sites.requests.RequestSite
,yang dapat digunakan sebagai sebuah fallback ketika dukungan-basisdata kerangka kerja situs tidak tersedia.
-
class
requests.
RequestSite
¶ Sebuah kelas yang berbagi antarmuka utama dari
Site
(yaitu, itu memiliki atributdomain
danname
) tetapi mendapatkan datanya dari obyekHttpRequest
Django daripada dari sebuah basisdata.-
__init__
(request)¶ Setel atribut
name
dandomain
ke nilai dariget_host()
.
-
Sebuah obyek RequestSite
mempunyai antarmuka mirip pada obyek Site
biasa, kecuali metode __init__()
nya mengambil sebuah obyek HttpRequest
. Itu dapat menyimpulkan domain
dan name
dengan mencari domain permintaan. Itu mempunyai metode save()
dan delete()
untuk mencocokkan antarmuka dari Site
, tetapi metode-metode memunculkan NotImplementedError
.
Jalan pintas get_current_site
¶
Akhirnya, untuk menghindari kode fallback berulang, kerangka kerja menyediakan sebuah fungsi django.contrib.sites.shortcuts.get_current_site()
-
shortcuts.
get_current_site
(request)¶ Sebuah fungsi yang memeriksa jika
django.contrib.sites
dipasang dan mengembalikan salah satu obyekSite
object saat ini atau obyekRequestSite
berdasarkan pada permintaan. Itu mencari situs saat ini berdasarkan padarequest.get_host()
jika pengaturanSITE_ID
tidak ditentukan.Kedua ranah dan port mungkin dikembalikan oleh
request.get_host()
ketika kepala Host mempunyai port dengan jelas ditentukan, misalnyaexample.com:80
. Dalam kasus tersebut, jika pencarian gagal karena host tidak cocok dengan sebuah rekaman dalam basisdata, port dihilangkan dan pencarian dicoba kembali dengan hanya bagian ranah. Ini tidak berlaku padaRequestSite
yang akan selalu menggunakan hos tidak berubah.