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.
The sites framework is mainly based on this model:
-
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()
.
How you use this is up to you, but Django uses it in a couple of ways automatically via a couple of conventions.
Contoh penggunaan¶
Mengapa anda menggunakan situs? Ini adalah penjelasan terbaik melalui contoh.
Isi terkait dengan situs-situs banyak¶
The LJWorld.com and Lawrence.com sites were operated by the same news organization -- the Lawrence Journal-World newspaper in Lawrence, Kansas. LJWorld.com focused on news, while Lawrence.com focused on local entertainment. But sometimes editors wanted to publish an article on both sites.
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.
A better solution removes the content duplication: Both sites use the same
article database, and an article is associated with one or more sites. In
Django model terminology, that's represented by a
ManyToManyField
in the Article
model:
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.
It lets the site developers use the same Django view code for both sites. The view code that displays a given story checks to make sure the requested story is on the current site. It looks something like this:
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
It's fragile to hard-code the site IDs like that, in case they change. The cleaner way of accomplishing the same thing is to check the current site's domain:
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 and Lawrence.com both have email alert functionality, which lets readers sign up to get notifications when news happens. It's pretty basic: A reader signs up on a web form and immediately gets an email saying, "Thanks for your subscription."
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.
Note that an even more flexible (but more heavyweight) way of doing this would
be to use Django's template system. Assuming Lawrence.com and LJWorld.com have
different template directories (DIRS
), you could
farm out to the template system like so:
from django.core.mail import send_mail
from django.template import loader
def register_for_newsletter(request):
# Check form values, etc., and subscribe the user.
# ...
subject = loader.get_template("alerts/subject.txt").render({})
message = loader.get_template("alerts/message.txt").render({})
send_mail(subject, message, "editor@ljworld.com", [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¶
Django's get_absolute_url()
convention is nice for getting your objects'
URL without the domain name, but in some cases you might want to display the
full URL -- with http://
and the domain and everything -- for an object.
To do this, you can use the sites framework. An example:
>>> 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()
...
To avoid repetitions, add
django.contrib.sites.middleware.CurrentSiteMiddleware
to
MIDDLEWARE
. The middleware sets the site
attribute on every
request object, so you can use request.site
to get the current site.
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.