# Dokumentasi Django 5.2.8

# 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` 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()`.

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 hardcode 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 `https://` 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:

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()
        ...

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 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()`.

A `RequestSite` object has a similar interface to a normal `Site` object, except its `__init__()` method takes an `HttpRequest` object. It's able to deduce the `domain` and `name` by looking at the request's domain. It has `save()` and `delete()` methods to match the interface of `Site`, but the methods raise `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.