I am looking into adding RSS feeds to one of my Django apps and I would like to be able to have them be authenticated.
I want to use the new syndication framework in Django 1.2. I've read the docs on how to do this and have the basic feeds setup.
I am new to authenticating feeds, so I am not sure what the best approach to take is or what my options really are.
Each user has a unique sub domain and I would like the URL structure to look something like this: http://mysubdomain.mysite.com/myapp/rss/ if possible.
I don't want the feeds to be publicly available, is it possible to use the users username and password for the authentication? Have you found that most feed readers support this? If it's not possible to authenticate for each user, should I try to use a uuid to give them a unique url or is that not secure enough?
As you can probably tell I am not sure what direction to take with this, so any advice on the best way to do this would be very much appreciated.
Thanks
This is an old thread, but I recently encountered the same question. I solved it by overloading the __call__ method of the Feed object:
from django.http import HttpResponse
class ArticleFeed(Feed):
"snip [standard definitions of title, link, methods...]"
def __call__(self,request,*args,**kwargs):
if not request.user.is_authenticated():
return HttpResponse(status=401)
else:
return super().__call__(request,*args,**kwargs)
Have you tried wrapping the syndication view django.contrib.syndication.views.feed into a view that requires login? RSS feeds should normally be fetched over HTTP, so this should work!
# Import Django's standard feed view.
from django.contrib.auth.decorators import login_required
from django.django.contrib.syndication.views import feed
# Wrap it in a new feed view that requires authentication!
private_feed = login_required(feed)
Caveat: I've never tried this!
Edit!
To be safe with RSS readers that don't support redirection, return a HTTP 401 status code with the following:
authentication_url = '/accounts/login'
def feed_safe_login_required ( view ):
def _ ( request, *args, **kwargs ):
if not request.user.is_authenticated:
return HttpResponseNotAuthorized, authentication_url
return _
feed = feed_safe_login_required(django.contrib.syndication.views.feed)
Where HttpResponseNotAuthorized is as defined in this django snippet.
Related
Im kind of new to Django Rest Framework. I know it is possible to post data using the Browsable API, I just don't know how. I have this simple view:
class ProcessBill(APIView):
def post(self, request):
bill_data = request.data
print(bill_data)
return Response("just a test", status=status.HTTP_200_OK)
When I go to the url that points to this view, I get the rest_framework browsable api view with the response from the server method not allowed which is understandable cause I am not setting a def get() method. But ... how can I POST the data? I was expecting a form of some kind somewhere.
EDIT
This is a screenshot of how the browsable API looks for me, it is in spanish. The view is the same I wrote above but in spanish. As you can see ... no form for POST data :/ .
Since you are new I will recommend you to use Generic views, it will save you lot of time and make your life easier:
class ProcessBillListCreateApiView(generics.ListCreateAPIView):
model = ProcessBill
queryset = ProcessBill.objects.all()
serializer_class = ProcessBillSerializer
def create(self, request, *args, **kwargs):
bill_data = request.data
print(bill_data)
return bill_data
I will recommend to go also through DRF Tutorial to the different way to implement your endpoint and some advanced feature like Generic views, Permessions, etc.
Most likely the user has read-only permission. If this is the case make sure the user is properly authenticated or remove the configuration from the projects settings.py if it is not necessary as shown below.
```#'DEFAULT_PERMISSION_CLASSES': [
# 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
#],```
Read more on permissions here.
I have a website using Django. Each post is an object called Article. I want to retrieve the post's HTML after saving it so I wrote the following post_save hook:
#receiver(models.signals.post_save, sender=Article)
def _send_article_mentions(sender, instance, **kwargs):
import requests
from django.contrib.sites.models import Site
from urlparse import urljoin
from ParallelTransport.settings import ARTICLES_URL
SITE_URL = 'http://'+Site.objects.get_current().domain
article_url = urljoin( SITE_URL, instance.get_absolute_url() )
import time
time.sleep(20)
r = requests.get(article_url)
error_file = open(ARTICLES_URL+'/'+'error.txt','w')
error_file.write('file started1\n')
m = r.status_code
error_file.write(str(m))
error_file.close()
It basically waits for 20s (added as a test) then tries to retrieve the HTML of the post using its URL, and writes the request status code to a file for debugging.
The problem is I always get status = 404 on the first save, it does work on 2nd and subsequent saves. I thought the way Django works would be, in order:
save instance to database using save(). At this point the post would get a URL
send post_save signal
But then I should be able to retrieve the HTML in post_save. Am I understanding post_save incorrectly?
Added notes:
Putting this code in save() method does not work. Nor should it. The post is added to database at the end of the save() method and so should not have any URL until save() ends.
This is on a production site, not on the development server.
I want to use the links in the HTML to send 'pingbacks' or actually webmention. But all my pingbacks are being rejected because the post does not have a URL yet. This is the bare minimum code that does not work.
Although this is a completely wrong approach(*), the problem is probably in database transactions. Current thread saves the article but within this uncommited transaction you are trying to get these data through another thread (through web server). In that case, this behaviour is fully correct. Either you need to commit before retrieving through another thread or get the HTML by another way.
(*) should be done asynchronously on the background (Celery or other more lightweight async queue app) or you can call the view directly if you want to get the HTML (depending on your view, you may have to forge the request; if too complicated, you can create a helper function that cherrypicks minimal code to render the template). If you only need to call a 3rd party API after you save something, you want to do it asynchronously. If you don't do it, the success of your "save() code" will depend on the availability of your connection or the 3rd party service and you will need to deal with transactions on place where you won't to deal with transactions ;)
Have you tried overriding the object's save method, calling super, waiting and then trying to retrieve the HTML?
Also are you using the development server? It may have issues handling the second request while the first one is still going. Maybe try it on a proper server?
I had similar problem caused probably by the same issue (Asked differently, https://plus.google.com/u/0/106729891586898564412/posts/Aoq3X1g4MvX).
I did not solve it in a proper way, but you can try playing with the database cache, or (seen it in another django database problem) close all of the database connections and requery.
Edit 2:
I have created a simple example (using Django 1.5.5) to test whether this works as intended. As far as I can tell, it does. pre_save fires before a database commit and post_save fires after.
Example detailed:
Two example models.
Article is used for triggering signals.
ArticleUrl is used to log responses from Article.get_absolute_url().
# models.py
from django.db import models
from django.core.urlresolvers import reverse
class Article(models.Model):
name = models.CharField(max_length=150)
def get_absolute_url(self):
"""
Either return the actual url or a string containing '404' if reverse
fails (Article is not saved).
"""
try:
return reverse('article:article-detail', kwargs={'pk': self.pk})
except:
return '404'
class ArticleUrl(models.Model):
article_name = models.CharField(max_length=150)
url = models.CharField(max_length=300)
def __unicode__(self):
return self.article_name + ': ' + self.url
Example views.py and urls.py were omitted as they are simple. I can add them if needed.
# views.py, url.py
Creating pre_save and post_save signals for Article:
# signals.py
from django.db.models import signals
from django.dispatch import receiver
from article.models import Article, ArticleUrl
#receiver(signals.pre_save, sender=Article)
def _log_url_pre(sender, instance, **kwargs):
article = instance
article_url = ArticleUrl(
article_name = 'pre ' + article.name,
url = article.get_absolute_url()
)
article_url.save()
#receiver(signals.post_save, sender=Article)
def _log_url_post(sender, instance, **kwargs):
article = instance
article_url = ArticleUrl(
article_name = 'post ' + article.name,
url = article.get_absolute_url()
)
article_url.save()
Importing my signals.py so Django can use it:
# __init__.py
import signals
After defining the above I went ahead and created a new Article in Django shell (python.exe manage.py shell).
>>> from article.models import *
>>> a = Article(name='abcdd')
>>> a.save()
>>> ArticleUrl.objects.all()
[<ArticleUrl: pre abcdd: 404>, <ArticleUrl: post abcdd: /article/article/8>]
The above example does seem to show that pre_save did indeed not return a url, but post_save did. Both appear to be behaving as intended.
You should check whether your code either deviates from the above example or interferes with program execution in some way.
Edit 1:
Having said that (below), according to What Happens When You Save, the post_save signal should run after a database save.
Could there be other parts of your app/site somehow interfering with this?
Original post:
According to the Django documentation, the post_save signal is sent at the end of save(), not after it.
As far as I understand, Django Signals are synchronous (in-process) so they would stall the actual save(). It won't fully complete until the signals are done.
This isn't always applicable, but have you considered a custom signal you could call after save()?
I have an iPhone application from which I would like to call a post service passing parameters in its request, doing so caused a server error 500.
I have read Django documentation here and I still haven't figure out how to get a csrf_token and how to add it to the AFNetworking AFHTTPRequestOperationManager POST method.
On the server side I've added django.middleware.csrf.CsrfViewMiddleware in the MIDDLEWARE_CLASSES section, but it doesn't seem to do the trick.
My view looks like this; I am not doing much, just hoping to pass.
from django.core.context_processors import csrf
from django.shortcuts import render_to_response
def foo(request):
c={}
c.update(csrf(request))
if request.method == 'POST':
return HttpResponseRedirect("Post received");
The Django CSRF Middleware uses cookies and forms and whatnot to send a code to the page, then make sure the correct page is the one sending information back. In both cases, you must do a GET request to the server, and if you have the middleware installed correctly, it will put the CSRF token into a cookie for you.
Check out the documentation for more info on this.
Now, I noticed you're using a library that uses NSURLConnection, so that should handle cookies for you. I got this bundle of code (untested) that lets you pull the cookie name that you specify in your settings file (again, check out the documentation link above) then put that in your POST.
NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL: networkServerAddress];
for (NSHTTPCookie *cookie in cookies)
{
// get the right cookie
}
Of course, if you're only making POSTs and never GETs first, you don't have a CSRF token to send!
And that's why we have the #csrf_exempt tag. (Docs here) This is the way to go 99% of the time, since most apps you won't do a GET before you do a POST. (in webpages you have to do a GET first). Note that this is intended only when an app is sending only POSTs and there's no session to speak of. You really need to think about your own security when using this, and how you verify that a given app/user really is who they claim to be. And how you disable people from hitting this URL from a webbrowser.
TLDR: Probably use #csrf_exempt on the view, but be careful.
So I want to serve a couple of mp3s from a folder in /home/username/music. I didn't think this would be such a big deal but I am a bit confused on how to do it using generic views and my own url.
urls.py
url(r'^song/(?P<song_id>\d+)/download/$', song_download, name='song_download'),
The example I am following is found in the generic view section of the Django documentations:
http://docs.djangoproject.com/en/dev/topics/generic-views/ (It's all the way at the bottom)
I am not 100% sure on how to tailor this to my needs. Here is my views.py
def song_download(request, song_id):
song = Song.objects.get(id=song_id)
response = object_detail(
request,
object_id = song_id,
mimetype = "audio/mpeg",
)
response['Content-Disposition'= "attachment; filename=%s - %s.mp3" % (song.artist, song.title)
return response
I am actually at a loss of how to convey that I want it to spit out my mp3 instead of what it does now which is to output a .mp3 with all of the current pages html contained. Should my template be my mp3? Do I need to setup apache to serve the files or is Django able to retrieve the mp3 from the filesystem(proper permissions of course) and serve that? If it do need to configure Apache how do I tell Django that?
Thanks in advance. These files are all on the HD so I don't need to "generate" anything on the spot and I'd like to prevent revealing the location of these files if at all possible. A simple /song/1234/download would be fantastic.
Why do you want to do this with a generic view? It's very easy to do this without generic views:
from django.http import HttpResponse
def song_download(request, song_id):
song = Song.objects.get(id=song_id)
fsock = open('/path/to/file.mp3', 'rb')
response = HttpResponse(fsock, content_type='audio/mpeg')
response['Content-Disposition'] = "attachment; filename=%s - %s.mp3" % \
(song.artist, song.title)
return response
I'm not sure if it's possible to make this work somehow with a generic view. But either way, using one is redundant here. With no template to render, the context that is automatically provided by the generic view is useless.
To wrap my comment to Tomasz Zielinski into a real answer:
For several reasons it is indeed better to let apache/nginx/etc do the work of sending files.
Most servers have mechanisms to help in that usecase: Apache and lighttpd have xsendfile, nginx has X-Accel-Redirect.
The idea is that you can use all the features of django like nice urls, authentification methods, etc, but let the server do the work of serving files. What your django view has to do, is to return a response with a special header. The server will then replace the response with the actual file.
Example for apache:
def song_download(request):
path = '/path/to/file.mp3'
response = HttpResponse()
response['X-Sendfile'] = smart_str(path)
response['Content-Type'] = "audio/mpeg"
response['Content-Length'] = os.stat(path).st_size
return response
install mode_xsendfile
add XSendFileOn on and (depending on the version) XSendFileAllowAbove on or XSendFilePath the/path/to/serve/from to your apache configuration.
This way you don't reveale the file location, and keep all the url management in django.
Serving static files with Django is a bad idea, use Apache, nginx etc.
https://docs.djangoproject.com/en/dev/howto/static-files/deployment/
To answer the original question how to use a generic view, you could do the following:
from django.views.generic import DetailView
from django.http.response import FileResponse
class DownloadSong(DetailView):
model = Song
def get(self, request, *args, **kwargs):
super().get(request, *args, **kwargs)
song = self.object
return FileResponse(open(song, 'rb'),
as_attachment=True,
filename=f'{song.artist} - {song.title}.mp3')
Docs:
Detailview: https://docs.djangoproject.com/en/3.2/ref/class-based-views/generic-display/#detailview
FileResponse: https://docs.djangoproject.com/en/3.2/ref/request-response/#fileresponse-objects
If your Django version does not have the FileResponse object, use the HttpResponse as shown in the other answers.
I need to check user authorization in every view of one of my Django apps (I don't use Django's built in auth system) and redirect user to a "login please" page, if authorization has failed.
Code looks like this:
try:
admin_from_session = request.session['admin'];
admin = Administrator.objects.get(login = admin_from_session.login, password = admin_from_session.password, enabled=True);
except KeyError, Administrator.DoesNotExist:
return HttpResponseRedirect('/controlpanel/login')
Question is: how can I run this code at the beginning of every view, without repeating it every time?
If I would write my program on PHP, i would put this code in separate file and write something like this at the beginning of every page that requires authorization:
include("redirect_if_not_logged_in.inc.php");
The solutions I found was:
inclusion tags - doesn't do,
because I can't redirect anywhere
from there
custom function -
also doesn't do, because of the same
reason.
The task seems trivial, but I can't find a solution. I would be very grateful for any help.
Look at the source code for django.contrib.auth decorators. They do exactly what you want, but for the built-in Django authentication system (see the documentation). It shouldn't be hard to do something similar for your authentication system.
BTW, why don't you use the built-in auth? You can use it with custom authentication backends...
I found the answer I was looking for. Function decorators allow to run a peace of code at the beginning of a function.
You must define a decorator function
def login_please_decorator(view_func):
"""
Redirect if admin was not logged in
"""
def _decorated(request, *args, **kwargs):
#Check authorization
try:
admin_from_session = request.session['admin'];
admin = Administrator.objects.get(login = admin_from_session.login, password = admin_from_session.password, enabled=True);
return view_func(request,*args, **kwargs);
except KeyError, Administrator.DoesNotExist:
return HttpResponseRedirect('/cp/login?ret=' + request.path);
return _decorated
And decorate a view using this function name:
#login_please_decorator
def some view(request):
# do something ...
# ...
Ludwik Trammer, bugspy.net, thank you for your help.
Function decorators comes to mind
Take a look at the User authentication page here http://docs.djangoproject.com/en/dev/topics/auth/
Read on to "The login_required decorator".
from django.contrib.auth.decorators import login_required
#login_required
def my_view(request):
...
You can setup where the user is to be redirected if not authenticated via the setting "settings.LOGIN_URL".
At the page there is also an example for a special authentication template you can style to anything you like!