Get objects from current site without settings.SITE_ID - django

I'm looking for the same functionality as the CurrentSiteManager provides but without having to specify SITE_ID in settings.py as the CurrentSiteManager requires. Information about the current site should come from the request. My take on the problem would be to make a custom manager, but is there something I'm missing? What would be a good way of doing this? It seems quite trivial that the CurrentSiteManager should provide this functionality. Would it make sense to submit a feature request?

You write:
Information about the current site should come from the request.
There is a big assumption here, which is that the manager will always have a request context available.
This isn't an assumption that Django can make: any generic model manager must work outside of a request context because there are all sorts of cases where a request context isn't available - e.g., management commands, migrations, tasks, etc. Even if you are in the context of a request, your manager has no knowledge of this unless you explicitly pass it to any method on the manager (i.e., you need those methods to accept a request argument). This is why CurrentSiteManager requires a SITE_ID:
The CurrentSiteManager is only usable when the SITE_ID setting is defined in your settings.
If you do want to filter objects within a request context, then Django provides the CurrentSiteMiddleware to add the current site to all requests. Within your views you can then filter objects on this site.
There are examples of projects that have implemented a custom CurrentSiteManager that does what you're asking for - the one that comes to mind is Mezzanine which you may be able to borrow from (note that it involves messing around with thread locals, and still requires a fallback to a SITE_ID setting).

Related

How does viewset aligns with rest methods

I am relatively new to DRF, but found viewsets an amazing abstraction technique for writing RESTful API. I am having a hard time correlating Viewsets with REST methods though. Let's say I have a viewset for Userprofiles and somebody new creates a profile on client.
Should this send a PUT or a POST ?
Which url should this request go to, http://user or http://user/new_id ?
If I want this profile only accessible to the user or admin(all CRUD operations), then where should I handle the code for making it inaccessible to others ?
Should I create a new permission ? If yes, should I handle rest methods in has_permission/has_object_permission ?
I have gone through the tutorial, and know how permissions/mixins works, but I am not able to connect these dots here.
1/ In general, POST is for creating new, PUT is for updating. See the docs on the SimpleRouter to show how the various types of Http methods align with various actions in your Django backend.
2/ You'll find that different situations call for different routing methods. If yours is standard, you may want to use a SimpleRouter like the example above. In that case, creating a new user would be a POST request to /user/ and updating a user would be a PUT request to /user/{{user_id}}/.
3/ To limit access to various API methods, you want to use Permissions. It's possible that you could use one of DRF's Custom Permissions. I've found that in general, if you want only the user to access his/her own profile, it's easier to either use conditional logic within a view (i.e., return a DRF PermissionDenied exception in the view logic if the request.user.pk is not the pk of that REST url. More often than not, I've used the UserPassesTestMixin from Django Braces, that works pretty well to filter user permissions.
4/ I guess the Django Braces mixin above answers this question. You should include a test_func method if you're using Django Braces that returns True if you want to grant the user access, and False otherwise.
Hope this helps! I agree that these are difficult parts of DRF and perhaps some of these could more effectively get incorporated into the source. Good luck!

Django equivalent to Rails application_controller

In Rails, I used the application_controller to control things like user sessions, and create objects to populate parts of the site like the menu.
How should this be done in Django, since there is no kind of "application view"? Do you have to use custom filters and partial templates to be included, for instance in the base template to do this?
I have also been looking at class-based views, but am unsure if that is it.
There are several ways to accomplish this:
Template Tags
Context Processors
Class Based Views
Middleware
It just depends on what you're needing to do. request.user is always present in the request object, even if it's an anonymous user, so you don't have to do anything special to access that object from within a template or server-side code.
Inclusion tags are as close as you'll get to render partial in Rails.
Signals and Class-Based views are close to what you'd find in controller filters.
One of the books I found most helpful when learning Django (I went to Django from Rails) was Practical Django Projects. The Definitive Guide to Django is also available for free.

How to make form data a part of the application state? (Alternative approach to managing state in an Ember Application?)

I am currently looking for a feasible approach to store form data globally in my Ember Application. The state of the form must get reflected in the URL. I have not yet seen an Ember example managing this kind of state, since routes always revolved around certain entities/models that get displayed by an Application.
Soo.. what is my Usecase?
When the user enters my app, he may modify some settings of my app in a form (e.g. location and time). I would like to have this information as part of the application state. Why? The state of the settings could be shared by the user with others users easily, as he could share the current URL of the application.
This is my current idea for an implementation:
I could store the current settings in a global location, e.g. in my router.
This enables me to access the stored settings in the methods serialize and deserialize of my main route (and potential other routes).
What's your opinion on my current idea for a solution approach? Is there maybe a appropriate Ember feature i have missed?

Access session / request information outside of views in Django

I need to store a special cookies that is coming from some non-django applications. I can do this in views
request.session[special_cookies'] = special_cookies
But in the non-views py files, I need to access this special cookies.
According to docs, I can do this
>>> from django.contrib.sessions.backends.db import SessionStore
>>> import datetime
>>> s = SessionStore(session_key='2b1189a188b44ad18c35e113ac6ceead')
>>> s['last_login'] = datetime.datetime(2005, 8, 20, 13, 35, 10)
>>> s['last_login']
datetime.datetime(2005, 8, 20, 13, 35, 0)
>>> s.save()
If I don't supply the session key, Django will generate one for me.
I am concerned about the effect of getting many new session keys. (I don't think this is good when you have multiple users, right...?)
I want a user to have this special cookies binded to a user's session. However, I do not want to save this in a user profile, because for security reason. This cookie is generated when we login (our application will send in this special cookies). We want to send this cookie back and forth throughout the browsing session.
How should I go about solving this?
Thank you very much!
#views.py
request.session['special_cookies'] = library.get_special(user, pwd)
#library.py
def get_special_cookies(user, pwd):
res = get_special_cookies("http://foobar.com/api/get_special_cookies", user, pwd)
#foobar.py (also non-views)
def do_this(user, special_cookies)
I am pretty sure this is fine....
#views_2.py
def dummy_views(request):
foobar.do_this(request.user, request.session['special_cookies'])
But there are instances where I don't want to get my special cookies through views / calling get_sepcial_cookies. I want it to last throughout. Or am I overthinking..?
In order to explain why you are in a dangerous path, we have to remember why server side sessions where invented in the first place:
HTTP is a stateless protocol. A stateless protocol does not require the server to retain information or status about each user for the duration of multiple requests. For example, when a web server is required to customize the content of a web page for a user, the web application may have to track the user's progress from page to page. A common solution is the use of HTTP cookies. Other methods include server side sessions, hidden variables (when the current page contains a form), and URL-rewriting using URI-encoded parameters.
Django is a very mature framework; if some goal seems hard to accomplish in Django, probably you are taking the wrong approach to the problem. Even if you can store server side session information directly at the session backend, it seems like bad design for me, because session data is not relevant outside requests.
IMHO, if you need to share authentication/authorization data among applications, you should really consider something like OAuth, otherwise you will end up with something insecure, fragile, ugly and hard to support.
(sorry if I sound condescending, English is not my native idiom).
[update]
Hi Paulo. Thank you very much. I believe my team doesn't want to introduce OAuth or any sort of extra layer of authetication mechaicism. But are you against inserting this special cookies into HttpResponse.COOKIES?
A few remarks if you you really want to go this way:
you will be constrained by the "same domain" restriction (the other application should reside in the same TLD)
you should use some sort of signing to avoid tampering with the cookies
Is that a better solution than request.session?
There are some mechanisms to deal with this kind of problem at a higher level. For example:
if you want to make a variable present at every template context based on the value of some cookie, you can write a custom context processor.
if you want to reroute views depending on the presence of a cookie, you should write a custom middleware.
I can't provide a more specific solution without further details about your goals, but using these hooks you can avoid repeating code to test for the external cookie in every view - note however that everything concerning cookies is tied to the request/response context and makes no sense outside it.

How to alter django settings based on current request?

I'm running multiple sites from a single django instance, and expect the framework to eventually serve several hundred sites from one or several installations.
I need to patch some django settings based on the current request. I've written some middleware to monkey patch the settings, but I need these settings to be patched before the middleware gets invoked because other apps aren't taking the monkey-patched changes (i.e. apps get run then middleware gets run so the apps don't use the monkey-patched settings).
I should also add this is mainly for the benefit of third-party apps that I haven't written, so I don't want to go round adding decorators or anything like that because that would mess up my upgrade path.
So:
How can I get access to the current request in an app's init.py file?
Will an app's init.py get called once per request or only once? If it's only once, how else could I do this so I can manipulate the settings once per request?
Is it safe to do this kind of monkey patching? I know it makes code a bit more opaque, but I don't want to use different wsgi files per site because I want to allow users to edit some of these settings and have my monkey patching come from the database.
Is there a better solution that would allow certain settings to be stored in the database?
This module - django-tupperware does what you are asking about: https://bitbucket.org/jiaaro/django-tupperware/
Give it a try.
Never ever ever change settings on the fly. You cannot predict how the application may one day be deployed, and in most of them the project will fail in.. interesting ways.
If you really want to have hundreds of sites which will be dynamically reconfigured all the time, you might try to Djangos django/conf/__init__.py which is used to supply the settings to the rest of the framework. You might be able to alter it in a way it depends on the request and it's Host field. Or you'll get many interesting failures at the very least.
My solution to this problem is to give each request, ALL the settings and update them on the fly with a middleware, how do i do this?
Is rather simple:
This is the middleware that does it all
from django.conf import settings
class DumpObject: pass
class Settings(object):
def process_request(self,request):
request.settings = DumpObject()
for setting in dir(settings):
if not setting.startswith('__'):
setattr(request.settings, setting, getattr(settings,setting))
The DumpObject is just there so i can use the object.property notation, it could have been a dictionary, but i wanted to keep some similarity in the syntax.
This assumes that none of your settings name starts with __ which is a fair assumption.
So if i want to override a particular setting, i don't keep a settings file i do it in this middleware. like this:
class Settings(object):
def process_request(self,request):
request.settings = DumpObject()
for setting in dir(settings):
if not setting.startswith('__'):
setattr(request.settings, setting, getattr(settings,setting))
if 'mydomain' in str(request.host): #this is thanks to django-hosts project
request.settings.GOOGLE_ANALYTICS_ID = '89298393-238'
Of course this doesnt take into account the problem of accessing the settings the old way
from django.conf import settings
settings.GOOGLE_ANALYTICS_ID = 'the value in settings.py'
But it really doesn't matter because you will probably only want to change the settings on the context of having a request object, available.