Calling api without knowing ip address in django - django

I have a post request
http://localhost:8000/api/orders/shipment
what i want to do is i dont want to pass domain/ip address and access the api something like Django admin console give "172.18.0.1 - - [08/Sep/2017 14:30:29] "POST /adminorder/order/import/ HTTP/1.1" 200 "
I searched in the django documentation get_absolute_url() method is there to define custom urls, I am not getting how to use this in this scenario.

I believe it's impossible to use a relative url in requests, but you can get around this by creating a function which prepends the relevant domain to your url. (Make sure to import your settings file!)
from django.conf import settings
development_url = "http://localhost:8000/"
production_url = "http://myapisite.com/"
def create_url(relative_url):
# If you are on your development server. This is assuming your development always has DEBUG = True, and your production is always DEBUG = False
if settings.DEBUG:
return development_url + relative_url
# Production
return production_url + relative_url
Therefore print(create_url("api/test/anothertest")) will return http://localhost:8000/api/test/anothertest.
And this is how you would use it:
url = create_url("api/orders/shipment/")
data = requests.post(url=url, data=content, headers = headers)

Related

How sites framework works?

I am trying to develop a ModelManager with an operation similar to the Sites Framework. Depending on a user's field, the ModelManager returns a queryset. I tried to imitate the operation of the Sites Framework but I do not understand how the SITE_ID is obtained dynamically with this function:
def get_queryset(self):
return super(CurrentSiteManager, self).get_queryset().filter(
**{self._get_field_name() + '__id': settings.SITE_ID})
It seems to be static :/.
I capture the user's field through a Middleware and assign it to request.field. How can I retrieve that field in the ModelManager and perform the query?
I think you are missing the dynamic way to get the current site instance.
From the documentation example:
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")
# ...
You should use the get_current_site method to get the current site.
It should be noted that it's not working if you actually define the current site in the settings like SITE_ID=1.
It looks up the current site based on request.get_host() if the SITE_ID setting is not defined.
You should read this part of the documentation actually explaining how django can get the current site in a dynamic fashion:
shortcuts.get_current_site(request)
A function that checks if django.contrib.sites is installed and returns either the current Site object or a RequestSite object based on the request. It looks up the current site based on request.get_host() if the SITE_ID setting is not defined.
Both a domain and a port may be returned by request.get_host() when the Host header has a port explicitly specified, e.g. example.com:80. In such cases, if the lookup fails because the host does not match a record in the database, the port is stripped and the lookup is retried with the domain part only. This does not apply to RequestSite which will always use the unmodified host.
And here is the code of the get_current actually called by get_current_site:
def get_current(self, request=None):
"""
Return the current Site based on the SITE_ID in the project's settings.
If SITE_ID isn't defined, return the site with domain matching
request.get_host(). The ``Site`` object is cached the first time it's
retrieved from the database.
"""
from django.conf import settings
if getattr(settings, 'SITE_ID', ''):
site_id = settings.SITE_ID
return self._get_site_by_id(site_id)
elif request:
return self._get_site_by_request(request)
raise ImproperlyConfigured(
"You're using the Django \"sites framework\" without having "
"set the SITE_ID setting. Create a site in your database and "
"set the SITE_ID setting or pass a request to "
"Site.objects.get_current() to fix this error."
)

Allow users to download files without revealing link and without buffering

I am hosting some video files in rackspace cloud files, and each user is allowed to download the files that are assigned to them.
Because of the file sizes it is not feasible to buffer the object in the webserver(webfaction)
I tried a redirect to the file, with Content-Disposition set to attachment, but to no avail.
What kind of options do I have, if any?
Ideally the file download would pop as coming from my domain after clicking a link that points to something like example.com/video/42/download/ so I can handle authentication ect. but im not sure how to structure my view for that to happen.
You are probably best served by using an HttpResponseRedirect unless there is something I am misunderstanding...?
# urls.py
from django.http import HttpResponseRedirect
url(r'^applications/(?P<id>\d+)/image\.png$', 'core.views.serve_image', name='image'),
This will serve a view at http://localhost/application/12345/image.png.
# core/views.py
def serve_application_image(request, id):
# redirect to temp_url
application = Application.objects.get(id=id)
return HttpResponseRedirect(application.image.temp_url)
And this will redirect users that hit that URL to the Rackspace URL. It can work for embedding videos, images, etc, in html <img> tags and such. Browser clients will be able to see the redirected URL (at rackcdn.com).
I have configured my apps to serve a temp_url property that expires after 15 minutes. The temporary URL is created for the CDN at Rackspace.com and their documentation may be out of the scope for this question so I'll leave it off for now... but the code I use to sub-class ImageField to serve image attributes with the .temp_url code follows:
import hmac
from hashlib import sha1
from time import time
class ImageFieldFile_With_Temp_Url(ImageFieldFile):
#property
def temp_url(self):
container_name, file_name = (self.storage.container.name, self.name)
key = settings.CUMULUS['CUSTOM__X_ACCOUNT_META_TEMP_URL_KEY']
public_url = settings.CUMULUS['CUSTOM__X_STORAGE_URL']
method = 'GET'
expires = int(time() + settings.CUMULUS['CUSTOM__X_TEMP_URL_TIMEOUT'])
url = '%s/%s/%s' % (public_url, container_name, file_name)
base_url, object_path = url.split('/v1/')
object_path = '/v1/' + object_path
hmac_body = '%s\n%s\n%s' % (method, expires, object_path)
sig = hmac.new(key, hmac_body, sha1).hexdigest()
return '%s%s?temp_url_sig=%s&temp_url_expires=%s' % (base_url, object_path, sig, expires)
class ImageField_With_Temp_Url(models.ImageField):
attr_class = ImageFieldFile_With_Temp_Url
models.ImageField = ImageField_With_Temp_Url
Note that I am using the django-cumulus project in this approach.
Importing this function anywhere at the top of your models.py will extend ImageField with a new temp_url property (since I assign it to models.ImageField ...).

django multiple domains, single app

I am trying to set my Django app work with multiple domains (while serving slightly different content)
I wrote this middleware:
class MultiSiteMiddleware(object):
def process_request(self, request):
host = request.get_host()
host_part = host.split(':')[0].split('.com')[0].split('.')
host = host_part[len(host_part)-1] + '.com'
site = Site.objects.get(domain=host)
settings.SITE_ID = site.id
settings.CURRENT_HOST = host
Site.objects.clear_cache()
return
In views I use this:
def get_site(request):
current_site = get_current_site(request)
return current_site.name
def view(request, pk):
site = get_site(request)
if site == 'site1':
# serve content1
...
elif site == 'site2'
# serve content2
...
But now there are 404 errors (I sometimes find them in logs, don't see them while browsing my site manually) where they aren't supposed to be, like my site sometimes is serving content for wrong domains, can they happen because of some flaw in the above middleware and view code or I should look somewhere else?
I had a similar requirement and decided not to use the django sites framework. My middleware looks like
class MultiSiteMiddleware(object):
def process_request(self, request):
try:
domain = request.get_host().split(":")[0]
request.site = Site.objects.get(domain=domain)
except Site.DoesNotExist:
return http.HttpResponseNotFound()
then my views have access to request.site
If you're seeing 404's for sites that aren't yours in your logs it would seem like somebody has pointed their domain at your servers IP address, you could use apache/nginx to filter these out before they hit your app, but your middleware should catch them (though possibly by raising an uncaught 500 error instead of a 404)
Serve multiple domain from one website (django1.8 python3+)
The goal is, obviously, to serve multiple domains, from one Django instance. That means, we use the same models, the same database, the same logic, the same views, the same templates, but to serve different things.
Searching the interwebs, I came to the idea of using the sites framework. The sites framework was designed to do exactly that thing. In fact, the sites framework has been used to do exactly that. But I haven't been able to know on which version of Django it was, and actually, I came to the idea the sites framework was just a vestigial module. Basically, it is just a table, with SITE_ID and SITE_URL, that you can easily access with a function. But I've been unable to find how, from that, you can do a multi-domain website.
So my idea has been, how to modify the url resolver. The idea behind all these is easy : www.domain1.com/bar is resolved to /domain1/bar, and www.domain2.foo is resolved to /domain2/foo. This solves the problem because, if you want to serve multiple domains, you just have to serve multiple folders.
In Django, to achieve this, you have to modify two things :
* the way Django routes requests
* the way django write urls
The way Django routes requests
Django routes requests with middlewares. That's it. So we just have to write a middleware that re-route requests.
To make it easier, middlewares can have a process_request method that process requests (WOW), before requests are handled. So let's write a DomainNameMiddleware
#!python
#app/middleware.py
class DomaineNameMiddleware:
"""
change the request path to add the domain_name at the first
"""
def process_request(self, request):
#first, we split the domain name, and take the part before the extension
request_domain = request.META['HTTP_HOST'].split('.')[-2]
request.path_info = "/%s/%s" % (request_domain, request.path.split('/')[1:])
The way Django writes URL
When I'm talking about django writing url, i'm principally thinking of the {% url %} template tag, the get_absolute_url methods, the resolve and resolve_lazy functions, and those basic Django thing. If we rewrite the way Django handle url, we have to tell Django to write url that way.
But basically it's pretty easy, thanks to Django.
You can easily rewrite basic Django function by just rewriting them, typically in init.py files of modules you added as apps. So :
#!python
#anyapp/__init__.py
from django.core import urlresolvers
old_reverse = urlresolvers.reverse
def new_reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None):
"""
return an url with the first folder as a domain name in .com
"""
TLD = 'com'
old_reverse_url = old_reverse(viewname, urlconf, args, kwargs, current_app)
# admin will add itself everytime you reload an admin page, so we have to delete it
if current_app == 'admin':
return '/%s' % old_reverse_url[len('admin'):].replace('adminadmin', 'admin')
return '//%s.%s/%s' % (app, TLD, path)
How to use it ?
I use it with base urls.py as dispatchedr.
#!python
#urls.py
from django.conf.urls import include, url
from domain1 import urls as domain1_urls
from domain2 import urls as domain2_urls
urlpatterns = [
url(r'^domain1/', include(domain1_urls, namespace='domain1')),
url(r'^domain2/', include(domain2_urls, namespace='domain2)),
]
Django's Sites framework has built-in middleware to accomplish this.
Simply enable the Sites framework and add this to your MIDDLEWARE:
'django.contrib.sites.middleware.CurrentSiteMiddleware'
This automatically passes a request object to Site.objects.get_current() on every request. It solves your problem by giving you access to request.site on every request.
For reference, the code as of 1.11 is:
from django.utils.deprecation import MiddlewareMixin
from .shortcuts import get_current_site
class CurrentSiteMiddleware(MiddlewareMixin):
"""
Middleware that sets `site` attribute to request object.
"""
def process_request(self, request):
request.site = get_current_site(request)
I will suggest you to use django-multisite .It will fulfill your requirement.
Try using the "sites" framework in django to get the domain name. You already know this I guess.
Take a look here: https://docs.djangoproject.com/en/1.7/ref/contrib/sites/#getting-the-current-domain-for-full-urls
See this:
>>> Site.objects.get_current().domain
'example.com'
Without the https://www or http://www.. Probably your domains will end in .org or some country .pe .ru etc not just .com.
There might be a case when people don't point to your domain but to your IP address for some reason, maybe development of testing so you should always raise an exception with Site.DoesNotExist

Django Login/Session Not Sticking Over HTTPS

I'm working on a Django site hosted on an Apache server with mod_wsgi.
The site is only on https as we have Apache redirect any http requests to https.
The project I'm working on is called Skittle.
I have a custom user model called SkittleUser which inherits from AbstractBaseUser and is set as the AUTH_USER_MODEL in our settings.py file.
os.environ['HTTPS'] = "on" is set in the wsgi.py file.
SESSION_COOKIE_SECURE = True and CSRF_COOKIE_SECURE = True are both set in settings.py
The issue that we are having right now is that logging in as a user is unreliable.
When you go to the login page, some times it works while other times it doesn't.
Then while browsing the site, you will suddenly lose your session and be kicked down to an anonymous user.
We are currently running our test site here if anybody wants to take a look:
https://skittle.newlinetechnicalinnovations.com/discover/
Our production site is at www.dnaskittle.com but does not yet incorporate user logins as the feature doesn't work.
A test user:
email: test#dnaskittle.com
password: asdf
If the login does not work, you will see in the top right "Welcome, Login" in which case, just try clicking on Login again and use the same credentials.
It may take 5-6 times of doing that process before you will actually get logged in.
You will know it works when you see "Welcome Tester, Logout, My Genomes"
After you are logged in, it may stick for a while, but browsing around to other pages will eventually kick you back off.
There is no consistent amount of pages that you can go through before this happens, and it doesn't happen on any specific page.
Any insights on this would be greatly appreciated.
Also of note, going to the Django admin page (which is not our code, but base django code) has the same issue.
I've gotten this issue sorted out now.
Users can not login while on HTTPS using while using the listed setup.
What I did:
In settings.py add:
SESSION_SAVE_EVERY_REQUEST = True
SESSION_COOKIE_NAME = 'DNASkittle'
I also wiped the current django_sessions database in case that was causing issues with old lingering data.
I did not setup extra middleware or SSLRedirect, and everything is working all ship shape.
It's little longer and complex the SSL system. to handle the session/login properly with https you can set a configuration with the session_cookies.
settings.py:
ENABLE_SSL=False #in the debug mode in the production passed it to True
MIDDLEWARE_CLASSES = (
'commerce.SSLMiddleware.SSLRedirect', #)
# the session here is to use in your views when a user is connected
SESSION_COKIE_NAME='sessionid'
#the module to store sessions data
SESSION_ENGINE='django.contrib.sessions.backends.db'
#age of cookie in seconds (default: 2 weeks)
SESSION_COOKIE_AGE=7776000 # the number of seconds in 90 days
#whether a user's session cookie expires when the web browser is closed
SESSION_EXPIRE_AT_BROWSER_CLOSE=False
#whether the session cookie should be secure (https:// only)
SESSION_COOKIE_SECURE=False
SSLMiddleware is a file you going to define in your project like.
SSLMiddleware.py:
from django.conf import settings
from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect
SSL='SSL'
class SSLRedirect:
def process_view(self,request,view_func,view_args,view_kwargs):
if SSL in view_kwargs:
secure =view_kwargs[SSL]
del view_kwargs[SSL]
else:
secure=False
if not secure == self._is_secure(request):
return self._redirect(request,secure)
def _is_secure(self,request):
if request.is_secure():
return True
if 'HTTP_X_FORWARD_SSL' in request.META:
return request.META['HTTP_X_FORWARD_SSL'] == 'on'
return False
def _redirect(self,request,secure):
protocol = secure and "https" or "http"
newurl ="%s://%s%s" % (protocol, request, request.get_full_path())
if settings.DEBUG and request.method=="POST":
raise RuntimeError, \
return HttpResponsePermanentRedirect(newurl)
Now in your urls which should handle your logins or connection add the line
urls.py:
from project import settings
urlpatterns += patterns('django.contrib.auth.views',
(r'^login/$','login',{'template_name':'registration/login.html','SSL':settings.ENABLE_SSL},'login'),
Try to adapt this to your code. and don't forget to turn ENABLE_SSL to True
For users login with HTTPS, you have to enable SSL and use code that matches your case to use it. For the user session you can use this:
First check if you have in settings.py:
INSTALLED_APPS= ('django.contrib.sessions',)
and use the request.sessions in your file.py:
request.session['id']='the_id_to_store_in_browser' or 'other_thing'
Here you use request.session like a special SessionStore class which is similar to python dictionary.
In your views.py for example before rendering a template or redirecting test the cookie with the code:
if :
# whatever you want
if request.session.test_cookie_worked():
request.session.delete_test_cookie()
return HttpResponseRedirect(up-to-you)
else:
# whatever you want
request.session.set_test_cookie()
return what-you-want
with this code, the user session will stick a wide, depending on your SESSION_COOKIE_AGE period.

Django URL Detail

I have to assign to work on one Django project. I need to know about the URL say, http://....
Since with ‘urls.py’ we indeed have ‘raw’ information. How I come to know about the complete URL name; mean with
http+domain+parameters
Amit.
Look at this snippet :
http://djangosnippets.org/snippets/1197/
I modified it like this :
from django.contrib.sites.models import RequestSite
from django.contrib.sites.models import Site
def site_info(request):
site_info = {'protocol': request.is_secure() and 'https' or 'http'}
if Site._meta.installed:
site_info['domain'] = Site.objects.get_current().domain
site_info['name'] = Site.objects.get_current().name
else:
site_info['domain'] = RequestSite(request).domain
site_info['name'] = RequestSite(request).name
site_info['root'] = site_info['protocol'] + '://' + site_info['domain']
return {'site_info':site_info}
The if/else is because of different versions of Django Site API
This snippet is actually a context processor, so you have to paste it in a file called context_processors.py in your application, then add to your settings :
TEMPLATE_CONTEXT_PROCESSORS = DEFAULT_SETTINGS.TEMPLATE_CONTEXT_PROCESSORS + (
'name-of-your-app.context_processors.site_info',
)
The + is here to take care that we d'ont override the possible default context processor set up by django, now or in the future, we just add this one to the tuple.
Finally, make sure that you use RequestContext in your views when returning the response, and not just Context. This explained here in the docs.
It's just a matter of using :
def some_view(request):
# ...
return render_to_response('my_template.html',
my_data_dictionary,
context_instance=RequestContext(request))
HTTPS status would be handled differently by different web servers.
For my Nginx reverse proxy to Apache+WSGI setup, I explicitly set a header that apache (django) can check to see if the connection is secure.
This info would not be available in the URL but in your view request object.
django uses request.is_secure() to determine if the connection is secure. How it does so depends on the backend.
http://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.is_secure
For example, for mod_python, it's the following code:
def is_secure(self):
try:
return self._req.is_https()
except AttributeError:
# mod_python < 3.2.10 doesn't have req.is_https().
return self._req.subprocess_env.get('HTTPS', '').lower() in ('on', '1')
If you are using a proxy, you will probably find it useful that HTTP Headers are available in HttpRequest.META
http://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.META
Update: if you want to log every secure request, use the above example with a middleware
class LogHttpsMiddleware(object):
def process_request(self, request):
if request.is_secure():
protocol = 'https'
else:
protocol = 'http'
print "%s://www.mydomain.com%s" % (protocol, request.path)
Add LogHttpsMiddleware to your settings.py MIDDLEWARE_CLASSES