# dokumentasi Django 2.2.9.dev20191202104323

# 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` dan `name` 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 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

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:

1. Menambahkan `'django.contrib.sites'` ke pengaturan `INSTALLED_APPS` anda.

2. Menentukan pengaturan `SITE_ID`:

       SITE_ID = 1

3. 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 menentukan `Site` nya, dan `FlatpageFallbackMiddleware` memeriksa situs saat ini dalam mengambil flatpage untuk dimunculkan.
- Dalam `syndication framework`, cetakan untuk `title` dan `description` otomatis mempunyai akses ke variabel `{{site}}`, yaitu obyek which is the `Site` mewakili situs saat ini. Juga, kaitan untuk menyediakan barang URL akan menggunakan `domain` dari obyek `Site` saat ini jika anda tidak menentukan ranah berkualitas-sepenuhnya.
- Dalam `authentication framework`, `django.contrib.auth.views.LoginView` melewatkan nama `Site` sat ini ke cetakan sebagai `{{ site_name }}`.
- Tampilan jalan pintas (`django.contrib.contenttypes.views.shortcut`) menggunakan ranah dari obyek `Site` 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 atribut `domain` dan `name`) tetapi mendapatkan datanya dari obyek `HttpRequest` Django daripada dari sebuah basisdata.

  `__init__`(request)

    Setel atribut `name` dan `domain` ke nilai dari `get_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 obyek `Site` object saat ini atau obyek `RequestSite` berdasarkan pada permintaan. Itu mencari situs saat ini berdasarkan pada `request.get_host()` jika pengaturan `SITE_ID` tidak ditentukan.

  Kedua ranah dan port mungkin dikembalikan oleh `request.get_host()` ketika kepala Host mempunyai port dengan jelas ditentukan, misalnya `example.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 pada `RequestSite` yang akan selalu menggunakan hos tidak berubah.