I have the following function in many views of many of my apps. Like the following:
def json_response(data):
return HttpResponse(
simplejson.dumps(data),
content_type = 'application/json; charset=utf8'
)
How would I include this on all of my apps' views.py? Define it in a single app and just import from it?
from main.global import simplejson
Also, is there a github page of a well organized django project that I can look at?
If you are using django 1.3, a class based view can be used to abstract this function. You would simply extend your view from a base view that would return json of whatever is passed in. You would save a file with this class at some common location (as described in the answer linked in the comment by Ignacio).
In fact, this is one of the example types in the documentation for class based views:
from django import http
from django.utils import simplejson as json
class JSONResponseMixin(object):
def render_to_response(self, context):
"Returns a JSON response containing 'context' as payload"
return self.get_json_response(self.convert_context_to_json(context))
def get_json_response(self, content, **httpresponse_kwargs):
"Construct an `HttpResponse` object."
return http.HttpResponse(content,
content_type='application/json',
**httpresponse_kwargs)
def convert_context_to_json(self, context):
"Convert the context dictionary into a JSON object"
# Note: This is *EXTREMELY* naive; in reality, you'll need
# to do much more complex handling to ensure that arbitrary
# objects -- such as Django model instances or querysets
# -- can be serialized as JSON.
return json.dumps(context)
This is how you would use it (also from the documentation):
class HybridDetailView(JSONResponseMixin,
SingleObjectTemplateResponseMixin, BaseDetailView):
def render_to_response(self, context):
# Look for a 'format=json' GET argument
if self.request.GET.get('format','html') == 'json':
return JSONResponseMixin.render_to_response(self, context)
else:
return SingleObjectTemplateResponseMixin.render_to_response(self, context)
Yes, you can just define it in a single view, or a utils file, or whatever you want, and just import it in all of your views. I frequently do this with ubiquitous functions.
Related
I am using DjangoRestApi and while it works like a charm with queryset (orm-based) views, I am struggling to make views that use different back-end to behave same way orm-based views are. Notably I want to add filters and have them cast and validated automatically.
Pseudo code below:
class NewsFilter(django_filters.FilterSet):
category = django_filters.NumberFilter(name='category')
limit = django_filters.NumberFilter(name='limit')
page = django_filters.NumberFilter(name='page')
class NewsView(generics.APIView):
filter_class = NewsFilter
def get(self, request):
filters = self.filter_class(??) # not sure, what to put here
payload = logic.get_business_news(**filters.data) # same
return Response(payload, status=status.HTTP_200_OK)
Any hint how to tackle problem will be appreciated.
Ultimate goal is to:
user types something into url or sends via POST, django-rest intercepts relevant values, extracts them, casts them into correct type and return as a dictionary
filters are displayed as they would if serializer was ORM based
The function signature to any single filter is like
class MyFilter(django_filters.Filter):
def filter(self,queryset,value):
[...]
The function signature to a FilterSet is:
def __init__(self, data=None, queryset=None, prefix=None, strict=None):
So, it looks like you pass in request.GET as data param and then pass in your queryset.
I am developing a web app using Django.
There are few functions like, get_token, get_url etc to fetch data from the database and also to modify the database.
Where should I put those functions? Inside views.py or models.py?
Since those functions are interacting with the database directly I am thinking of putting those in the models.py file to use those functions as an abstraction.
I would like to know the best practice.
models.py is meant to be used to define Classes (each takes up a
table in the database).
views.py contains any functions that are used
to return django rendered pages. It definitely contains any view functions and other functions that are called within the view.
Since your functions get_token() & get_url(), are processing data (and not creating, modifying or deleting tables), i'd suggest you to put them in the views.py file.
A sample way you might approach this is as below:
models.py:
class UrlTokenPair(models.Model):
url = models.models.TextField(blank=True)
token = models.TextField(blank=True)
views.py
from app_name.models import UrlTokenPair
def get_token(input_url):
if UrlTokenPair.objects.filter(url=input_url):
return UrlTokenPair.objects.get(url=input_url).token
else:
new_entry = UrlTokenPair.objects.create(url=input_url)
new_entry.token = yourAlgoForToken()
new_entry.save()
return new_entry.token
def get_url(input_token):
if UrlTokenPair.objects.filter(token=input_token):
return UrlTokenPair.objects.get(url=input_token).url
else:
new_entry = UrlTokenPair.objects.create(token=input_token)
new_entry.url = yourAlgoForUrl()
new_entry.save()
return new_entry.url
You can then call the above functions get_url and get_token in any view function in the views.py file. You can also call them in another .py file by just referring to them as:
from app_name.views import get_url, get_token
I've added row-level authorization to a Tastypie Resource as follows:
from tastypie.exceptions import ImmediateHttpResponse
from tastypie.http import HttpUnauthorized
class MyResource(ModelResources):
...
def is_authorized(self, request, object=None):
super(MyResource, self).is_authorized(request, object)
if object and (object.user != request.user):
raise ImmediateHttpResponse(response=HttpUnauthorized())
For brevity, I've left out the usual imports and only specified the imports that are relavant to the question.
My question is, is there a cleaner way to override is_authorized without having to import ImmediateHttpResponse and HttpUnauthorized? It seems to me that these are implementation details, and I should be able to simply return True or False.
The docs for tastypie 0.9.12 have a good example of this.
https://django-tastypie.readthedocs.org/en/v0.9.12/authorization.html#implementing-your-own-authorization
Here is the "read" part -- see the docs for the rest:
class UserObjectsOnlyAuthorization(Authorization):
def read_list(self, object_list, bundle):
# This assumes a ``QuerySet`` from ``ModelResource``.
return object_list.filter(user=bundle.request.user)
def read_detail(self, object_list, bundle):
# Is the requested object owned by the user?
return bundle.obj.user == bundle.request.user
# DON'T FORGET TO IMPLEMENT METHODS FOR CREATE/UPDATE/DELETE as shown in the docs.
You'll notice that UserObjectsOnlyAuthorization.read_detail() returns True/False. The read_list method will return an empty list, which is acceptable according to the docs, but you can also raise Unauthorized exception if you prefer.
Although your code is perfectly fine, but if you don't want to import the response classes then a cleaner way is to write an authorization class and use it in your Resource class
from tastypie.authorization import Authorization
class RowLevelAuthorization(Authorization):
def is_authorized(self, request, object=None):
if object and (object.user != request.user):
return False
else:
return True
class MyResource(ModelResources):
class Meta:
authorization = RowLevelAuthorization()
For the long run, you're much better off integrating django-guardian into your application with an authorization class like the following :
https://gist.github.com/airtonix/5476453
Pyramid documentation shows us how to use i18n inside views (and templates as well). But how to does one use it outside of views and templates where we have no access to current request (for example, in forms and models)?
#Michael said to pass request to models and forms. But is it right? I mean if form fields defines before __init__() method calls, the same with models. They don't see any parameters from views...
In Pylons we could simply use get_lang() and set_lang() and define preferable language in parent controller and then use ugettext() and ungettext() in any place we want without calling it from request directly every possible time (in views).
How to do that in Pyramid? Note that the language must be set from user's settings (session, cookies, db, etc).
My solution is to create the form class when it's needed with localizer as parameter. For example
forms.py
class FormFactory(object):
def __init__(self, localizer):
self.localizer = localizer
_ = self.localizer
self.required_msg = _(u'This field is required.')
self.invalid_email_msg = _(u'Invalid email address.')
self.password_not_match_msg = _(u'Password must match')
def make_contact_form(self):
_ = self.localizer
class ContactForm(Form):
email = TextField(_(u'Email address'), [
validators.Required(self.required_msg),
validators.Email(self.invalid_email_msg)
])
content = TextAreaField(_(u'Content'), [
validators.Required(self.required_msg)
])
return ContactForm
When you need to use the form
#view_config(route_name='front_pages.contact_us',
renderer='myweb:templates/front_pages/contact_us.genshi')
def contact_us(request):
"""Display contact us form or send mail
"""
_ = get_localizer(request)
factory = FormFactory(_)
ContactForm = factory.make_contact_form()
form = ContactForm(request.params)
return dict(form=form)
As you can see, we get the localizer in the view, and pass it to the FormFactory, then create a form with that factory. By doing that, all messages in the form was replaced with current locale language.
Likewise, you can do the same with model.
Have you found pyramid.18n.get_localizer yet?
http://docs.pylonsproject.org/projects/pyramid/en/1.3-branch/narr/i18n.html#using-a-localizer
Actually I had this very same problem. What I ended up doing was to see how the default locale negotiator works - it looks for a LOCALE property on the given request object. So just use a dummy to create the localizer. You may cache this value too, if you want
def my_get_localizer(locale=None):
request = Request({})
request._LOCALE_ = locale
return get_localizer(request)
Alternatively, join the irc channel #pyramid # freenode and pester the guys enough there to split the functionality of get_localizer in 2 separate documented functions (get_localizer and get_localizer_for_locale_name) for us to enjoy ;)
Also, notice that Pyramid TranslationStrings are lazy, so you can translate them as late as you want, e.g.
class MyModel(Base):
description = TranslationString("My model number ${number}")
...
def view(request):
m = MyModel()
localizer = get_localizer(request)
description = localizer.translate(m.description, mapping={'number': 1})
Sidenote: pylons' i18n was the worst can of worms I had opened in ages. The set_lang, get_lang hack was really awful, and pain in the ass as we needed to send emails to users in their native languages and then tried to restore the language back... also, it was IMPOSSIBLE to translate anything outside of a request in a pylons program, as a translator or the registry did not exist then.
You can make a localizer, and then translate a template accordingly.
When making the localizer, you can pass the lang you want (whether you have it from db or else). Hope it can help.
For the sake of clarity, I will set it as 'fr' below
from pyramid.i18n import make_localizer, TranslationStringFactory
from mako.template import Template
from mako.lookup import TemplateLookup
import os
absolute_path = os.path.dirname(os.path.realpath(__file__))
tsf = TranslationStringFactory('your_domain')
mako_lookup = TemplateLookup(directories=['/'])
template = Template(filename=template_path, lookup=mako_lookup)
localizer = make_localizer("fr", [absolute_path + '/../locale/'])
def auto_translate(*args, **kwargs):
return localizer.translate(tsf(*args, **kwargs))
# Pass _ pointer (translate function) to the context
_ = auto_translate
context.update({
"_": _
})
html = template.render(**context)
EDIT
You can also put this logic into a small function
def get_translator(lang):
"""
Useful when need to translate outside of queries (no pointer to request)
:param lang:
:return:
"""
localizer = make_localizer(lang, [absolute_path + '/../locale/'])
def auto_translate(*args, **kwargs):
return localizer.translate(tsf(*args, **kwargs))
_ = auto_translate
return _
In a Django application, I have more than a handful of views which return JSON, with an invocation similar to:
return HttpResponse(json.dumps(content), mimetype="application/json")
I want to start creating views that return either HTML or JSON depending on the Accept headers from the request. Possibly other types, too, but those are the main ones. I also want to get multiple URLs routed to this view; the file extensions ".html" and ".json" help tell clients which types they should Accept when making their request, and I want to avoid the "?format=json" antipattern.
What's the correct, blessed way to do this in Django with a minimum of boilerplate or repeated code?
(Edit: Rephrase in order to better follow SO's community guidelines.)
I think a class-based view mixin (django 1.3+) is the easiest way to do this. All your views would inherit from a base class that contains logic to respond with the appropriate content.
I think I may not be seeing your big picture here but this is what I would do:
Have a html template that you render when html is requested and keep your json.dumps(content) for when json is requested. Seems to be obvious but I thought i should mention it anyway.
Set your URLs to send you "json" or 'html'. :
(r'^some/path/(?P<url_path>.*)\.(?P<extension>html|json)$', 'some.redirect.view'),
(r'^/(?P<extension>html|json)/AppName', include(MyApp)),
# etc etc
and your view:
def myRedirectView(request, url_path, extension):
view, args, kwargs = resolve("/" + extension + "/" + urlPath)
kwargs['request'] = request
return view(*args, **kwargs)
I know this is a bit vague because I haven't fully thought it through but its where I would start.
I have addressed this by creating a generic view class, based on Django's own generic.View class, that defines a decorator 'accept_types'. This modifies the view to which it is applied so that it returns None if the indicated content-type is not in the Accept header. Then, the get() method (which is called by the generic.View dispatcher) looks like this:
def get(self, request):
self.request = request # For clarity: generic.View does this anyway
resultdata = { 'result': data, etc. }
return (
self.render_uri_list(resultdata) or
self.render_html(resultdata) or
self.error(self.error406values())
)
The actual view renderers are decorated thus:
#ContentNegotiationView.accept_types(["text/uri-list"])
def render_uri_list(self, resultdata):
resp = HttpResponse(status=200, content_type="text/uri-list")
# use resp.write(...) to assemble rendered response body
return resp
#ContentNegotiationView.accept_types(["text/html", "application/html", "default_type"])
def render_html(self, resultdata):
template = loader.get_template('rovserver_home.html')
context = RequestContext(self.request, resultdata)
return HttpResponse(template.render(context))
The (one-off) generic view class that declares the decorator looks like this:
class ContentNegotiationView(generic.View):
"""
Generic view class with content negotiation decorators and generic error value methods
Note: generic.View dispatcher assigns HTTPRequest object to self.request.
"""
#staticmethod
def accept_types(types):
"""
Decorator to use associated function to render the indicated content types
"""
def decorator(func):
def guard(self, values):
accept_header = self.request.META.get('HTTP_ACCEPT',"default_type")
accept_types = [ a.split(';')[0].strip().lower()
for a in accept_header.split(',') ]
for t in types:
if t in accept_types:
return func(self, values)
return None
return guard
return decorator
(The parameter handling in the decorator should be generalized - this code works, but is still in development as I write this. The actual code is in GitHub at https://github.com/wf4ever/ro-manager/tree/develop/src/roverlay/rovweb/rovserver, but in due course should be separated to a separate package. HTH.)