75

I'm developing a Phonegap app for my Django based app, but when trying to make Ajax calls I get this error:

XMLHttpRequest cannot load http://domain.herokuapp.com/getcsrf/?tags=jquery%2Cjavascript&tagmode=any&format=json. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. 

How can I make it so my Django app allows cross origin for some urls?

Here's my Ajax code:

get: function() {
    $.getJSON("http://domain.herokuapp.com/getcsrf/",
    {
        tags: "jquery,javascript",
        tagmode: "any",
        format: "json"
    },
    function(data) {
        $.each(data.items, function(item){
            console.log(item);
            });
    });
}
Pranava Mohan
  • 533
  • 2
  • 8
  • 18
Sascuash
  • 3,661
  • 10
  • 46
  • 65

5 Answers5

112

Django by default does not provide the headers necessary to provide cross origin. The easiest way would be to just use this Django app that handles it for you: https://github.com/adamchainz/django-cors-headers

  • Add to installed apps
  • Add to middleware
  • Then stuff like...
CORS_ALLOWED_ORIGINS = [
    "http://read.only.com",
    "http://change.allowed.com",
]

to support allowing all, just use the setting... CORS_ALLOW_ALL_ORIGINS = True and then do any filtering of the request in middleware or in the view.

stormlifter
  • 3,781
  • 3
  • 17
  • 20
  • 2
    Ok, already installed it, but doesn't seem to change, maybe because I want to allow 3 urls (any tip or best practise using django-cors-heades?) – Sascuash Mar 12 '14 at 20:22
  • I updated the example to show how to add domains/urls to the whitelist. – stormlifter Mar 14 '14 at 17:34
  • Cordova/Phonegaps apps run by file:// location and does not have domain so how to list them in CORS_ORIGIN_WHITELIST =() ? – Ajeet Lakhani Jun 09 '15 at 11:23
  • `CORS_ORIGIN_ALLOW_ALL = True` and then do any filtering of the request in middleware or in the view. – stormlifter Jun 11 '15 at 15:45
  • 7
    For people using Django 1.10 or later, use this: https://github.com/zestedesavoir/django-cors-middleware. The original link doesn't support 1.10. – Guilherme Santos Aug 20 '16 at 22:27
  • Thank you so much Guilherme Santos, for the link to new repository. – akki Sep 27 '16 at 11:21
  • The original repo seems to support Django 2, unlike the other one – dtasev Mar 30 '18 at 14:20
  • When using django-cors-headers it may be preferable to add 'null' (string) to CORS_ORIGIN_WHITELIST. i.e. CORS_ORIGIN_WHITELIST = ('null',...) which may resolve the issue and avoids disabling CORS completely. From the docs: "The value 'null' can also appear in this list, and will match the Origin: null header that is used in "privacy-sensitive contexts", such as when the client is running from a file:// domain." – pythonjsgeo Apr 09 '18 at 05:20
  • 3
    The setting was renamed to `CORS_ALLOW_ALL_ORIGINS = True` – taras Nov 13 '20 at 17:49
  • 1
    Good answer, but does not mention that you need to add the cors headers app and middleware in your django project settings, I've added a more detailed answer since the edit queue is full: https://stackoverflow.com/a/67844932/10307728 – orangecaterpillar Jun 04 '21 at 23:16
32

For single views you can manually add headers:

@require_GET
def api_getto(request):
    response = JsonResponse(
        # your stuff here
    )
    response["Access-Control-Allow-Origin"] = "*"
    response["Access-Control-Allow-Methods"] = "GET, OPTIONS"
    response["Access-Control-Max-Age"] = "1000"
    response["Access-Control-Allow-Headers"] = "X-Requested-With, Content-Type"
    return response
13

You can use "django-cors-headers". Simply install it using pip:

    pip install django-cors-headers

Add 'corsheaders' to your installed apps:

    INSTALLED_APPS = [
        ...
        'corsheaders',
        ...
    ]

Add middleware:

    MIDDLEWARE = [
        ...,
        'corsheaders.middleware.CorsMiddleware',
        'django.middleware.common.CommonMiddleware',
        ...,
    ]

Then add this to your "settings.py":

    CORS_ALLOWED_ORIGINS = [
        'http://siteyouwantto.allow.com',
        'http://anothersite.allow.com',
    ]

If you also want to allow some domains to make "POST" requests, add this to your "settings.py" and don't forget to add it in "CORS_ALLOWED_ORIGINS".

    CSRF_TRUSTED_ORIGINS = [
        'http://siteyouwantto.allow.com',
    ]

I hope this resolves your issue :)

Pranava Mohan
  • 533
  • 2
  • 8
  • 18
  • You'll also need to add the cors headers app and middleware in your settings, see [the README](https://github.com/adamchainz/django-cors-headers#configuration) or [my answer](https://stackoverflow.com/a/67844932/10307728) – orangecaterpillar Jun 04 '21 at 23:18
  • @orangecaterpillar you are right ! I will edit my answer :) – Pranava Mohan Jun 05 '21 at 05:13
6

You can use django-cors-headers as others have suggested, as of writing this you'll need to follow all the steps below.

To use django-cors-headers in your project, follow the guide in the Setup and Configuration sections of the cors headers project's README, or read it below (I've copied from the README for convenience).


SETUP

Install from pip:

python -m pip install django-cors-headers

and then add it to your installed apps:

INSTALLED_APPS = [
    ...
    'corsheaders',
    ...
]

Make sure you add the trailing comma or you might get a ModuleNotFoundError (see this blog post).

You will also need to add a middleware class to listen in on responses:

MIDDLEWARE = [
    ...,
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    ...,
]

CorsMiddleware should be placed as high as possible, especially before any middleware that can generate responses such as Django's CommonMiddleware or Whitenoise's WhiteNoiseMiddleware. If it is not before, it will not be able to add the CORS headers to these responses.

Also if you are using CORS_REPLACE_HTTPS_REFERER it should be placed before Django's CsrfViewMiddleware.


CONFIGURATION

Configure the middleware's behaviour in your Django settings. You must set at least one of three following settings:

`CORS_ALLOWED_ORIGINS`
`CORS_ALLOWED_ORIGIN_REGEXES`
`CORS_ALLOW_ALL_ORIGINS`

CORS_ALLOWED_ORIGINS

A list of origins that are authorized to make cross-site HTTP requests. Defaults to [].

An Origin is defined by the CORS RFC Section 3.2 as a URI scheme + hostname + port, or one of the special values 'null' or 'file://'. Default ports (HTTPS = 443, HTTP = 80) are optional here.

The special value null is sent by the browser in "privacy-sensitive contexts", such as when the client is running from a file:// domain. The special value file:// is sent accidentally by some versions of Chrome on Android as per this bug.

Example:

CORS_ALLOWED_ORIGINS = [
    "https://example.com",
    "https://sub.example.com",
    "http://localhost:8080",
    "http://127.0.0.1:9000"
]

Previously this setting was called CORS_ORIGIN_WHITELIST, which still works as an alias, with the new name taking precedence.

CORS_ALLOWED_ORIGIN_REGEXES

A list of strings representing regexes that match Origins that are authorized to make cross-site HTTP requests. Defaults to []. Useful when CORS_ALLOWED_ORIGINS is impractical, such as when you have a large number of subdomains.

Example:

CORS_ALLOWED_ORIGIN_REGEXES = [
    r"^https://\w+\.example\.com$",
]

Previously this setting was called CORS_ORIGIN_REGEX_WHITELIST, which still works as an alias, with the new name taking precedence.

CORS_ALLOW_ALL_ORIGINS

If True, all origins will be allowed. Other settings restricting allowed origins will be ignored. Defaults to False.

Setting this to True can be dangerous, as it allows any website to make cross-origin requests to yours. Generally you'll want to restrict the list of allowed origins with CORS_ALLOWED_ORIGINS or CORS_ALLOWED_ORIGIN_REGEXES.

Previously this setting was called CORS_ORIGIN_ALLOW_ALL, which still works as an alias, with the new name taking precedence.

  • Note that it appears that there is a missing/broken link in this clause: "Make sure you add the trailing comma or you might get a ModuleNotFoundError (see this blog post)." – DaveL17 Aug 08 '21 at 17:27
1

In my case I was posting a file more than 1 mb and I was getting this error because of nginx configration (default max size 1 mb) So......

For me path of nginx.conf was /etc/nginx/nginx.conf.

In my case I just added client_max_body_size in http block and it worked for me

http {
    ...
    client_max_body_size 200M;
}    

Make sure to restart nginx after changing this config

Zohab Ali
  • 8,426
  • 4
  • 55
  • 63