I have the following middleware class:
class CommonContextMiddleware:
def process_template_response(self, request, response):
# Get the context and top videos
context = response.context_data
...
# Add most_recent and most_viewed to the context...
context['most_recent'] = top_videos['most_recent'][:3]
context['most_viewed'] = top_videos['most_viewed'][:3]
# ...then continue rendering
return response
However, no matter what I put in the function, it's never being called. I presumed that this method would be called for every single template response generated, am I wrong?
Thanks in advance.
I assume when you're talking about "template response", you are actually returning a TemplateResponse from your Django view?
This isn't really the best place for this sort of thing. If you just want to add variables into every template context, the best place to do it is in a context processor.
Related
What is the best way to get DRF API view data into another Django view?
Currently I am just calling the view through requests module:
response = requests.get('my_api_view')
but is there a cleaner way?
I can also just instantiate the API view class in another view, but this will give me unserialized objects.
Not sure what you mean by getting unserialized objects. You can do the following if you're using function-based views:
def view(request):
# some stuff done
return Response(<result>)
def another_view(request)
return view(request)
If you're views are class based then you can do the following:
class AClassBasedView(SomeMixin, SomeOtherMixin):
def get(self, request):
# do something with the request
return Response(<some result>)
class AnotherClassBasedView(SomeMixin, SomeOtherMixin):
def compute_context(self, request, username):
#some stuff here here
return AnotherClassBasedView.as_view()(request)
Both of these will return a <class 'rest_framework.response.Response'> object which can be passed further.
I'm not sure what exactly you want to achieve but wanting to call a view from another view maybe a sign of bad architecture. It could mean that you have a business logic implemented in the second view which you want to access in the first. Usually the rule of thumb is to move such a common logic somewhere else so it could be used by different views.
Again I don't know what you want to achieve but this is a possibilty.
Sorry if this is a noob question I am still learning. I have passed a variable from python code to a jinja2 HTML template to set up a URL, like this:
Delete
When this link is pressed it should run a query that deletes the entity with that ID. But when the link is pressed it goes to /delete/1827424298 for example, which results in a 404 error as the request handler doesn't exist.
I need to pass that ID back into my python code so it can run a method to delete the entity with that same ID. How do I go about doing this? Using webapp2 if that is important.
class DeleteRequestHandler(webapp2.RequestHandler):
def get():
template = template_env.get_template('myrequests.html')
context = {
'results': results.key.id()
}
self.response.out.write(template.render(context))
EDIT: I've added my delete handler - it is incomplete as I have yet to add the query to delete the entity. My thinking behind it so far is I can grab the results.key.id() from the jinja2 template and put it into results but I am not sure if this would work.
So I think what you're confused about is how to set up a route handler with a dynamic part to the URL. It's a shame that this is completely skipped over in the webapp2 tutorial, as it's a fundamental part of writing any web application. However, it is covered well in the guide to routing, which you should read.
At its simplest, it's just a matter of putting a regex in the route:
app = webapp2.WSGIApplication([
...
(r'/delete/(\d+)', MyDeleteHandler),
])
which will now route any URL of the form /delete/<number>/ to your deletion handler.
The ID that you pass in the URL will be the first positional argument to the handler method:
class MyDeleteHandler:
def get(self, item_id):
key = ndb.Key(MyModel, item_id) # or whatever
I have written what I hope to be a re-usable Django app, but I have a bit of a conundrum on how to make the post form handling flexible. The simplified version of my view code looks like:
def do_form(request, entity_id, template_name, success_url):
form = MyForm(request.POST or None)
if request.method =='POST':
if form.is_valid():
#do some business logic
return HttpResponseRedirect(finished_url)
return render_to_response(template_name,
{'form': form},
context_instance=RequestContext(request))
I have followed the advice in James Bennets book "Practical Django Projects" and so you can now configure the template and the success url in the url conf, so for example my url conf could look like this:
urlpatterns = patterns('myapp.views',
url(r'^do/(?P<entity_id>\d+)/$',
view = 'do_form',
name = 'do_form_view',
kwargs={'template_name':'form.html',
'success_url':'/finish/'},),
url(r'^finish/$',
view = 'finish',
name = 'finish_view')
)
This is all very well and good but when I have come to use this in my real world application I find myself in a situation that this form sits in the middle of some workflow, and I want the success url to be something like /continue/<workflow_id>/ , and the problem is that you can only have a hardcoded url in the url conf, and the workflow_id will vary every time I hit the do_form code.
Can any one suggest a way to get around this?
You can achieve that by changing the following..
in do_form() in views.py
change the return HttpResponseRedirect to
return HttpResponseRedirect('/continue/%s' %(workflowid))
And in urls.py, you can have
url(r'^continue/(?P<workflowid>\d+)/$',
view = 'continue',
name = 'continue_view')
and for the continue() view in views.py
def continue(request, workflowid=None):
...
This way.. whenever you access the url /continue/ without a number, workflowid will be equal to None. Every other time when you do have a workflowid attached for e.g. like /continue/23/ , then inside your continue() view you can access that id through the variable workflowid.
When you pass a hypothethical "flexible" success_url to a view, that view MUST supply the desired identifier. So if you mismatch the URL and the view, we can't avoid having a "breach of contract" between the two.
Therefore if we are to have flexible URLs, some kind of contract shall have to be enforced, and there will be no loss of generality if we do this through a special syntax for URLs:
'finished_url': '/finish/<workflow_id>/'
Then, of course, the view shall have to instantiate the variable through a string replacement to honor its side of the contract: instead of
return HttpResponseRedirect(finished_url)
you will have
return HttpResponseRedirect(finished_url.replace('<workflow_id>', WorkflowID))
This should keep things reasonably simple.
When reusing code, you will have to keep in mind that <workflow_id> is whatever that app uses to call workflow id, and that's why I use a complicated string such as workflow_id instead of id or maybe $1.
EDIT: I was going to add the code for the next step (intercepting workflow ID in argument of finish), but I see that keithxm23 beat me to the punch :-)
You can do it the same way people have been "overriding" Django's function-based generic views for years: simply wrap the view in another view:
def custom_do_form(request, entity_id, template_name, success_url):
template_name = some_method_to_get_template()
return do_form(request, entity_id, template_name, success_url)
I have a site whose URLs look like
http://www.example.com/NY-2010/
http://www.example.com/NY-2010/location/
http://www.example.com/NY-2010/something-else/
http://www.example.com/Washington-2009/
http://www.example.com/Washington-2009/location/
http://www.example.com/Washington-2009/something-else/
and so on. There are various pages (like location) for various editions (like NY). I use URLconfs like
url(r'^(?P<edition>[\d]+\-[\w]+)/$', views.home),
url(r'^(?P<edition>[\d]+\-[\w]+)/location/$', views.location),
In each of the views I have to fetch the current edition. The fact is, if the edition name is wrong, I want to redirect to the latest edition. So I do something like
def home(request, edition):
try:
event = Edition.objects.get(name=edition)
except ObjectDoesNotExist:
return redirect(home, edition=Edition.latest())
# If event was found I go on here
def location(request, edition):
try:
event = Edition.objects.get(name=edition)
except ObjectDoesNotExist:
return redirect(home, edition=Edition.latest())
# If event was found I go on here
and so on. Of course there is some duplication that I'd like to minimize. I can think of two ways:
use get_objects_or_404() and customize the 404 view, or
abstract the common part in a function.
The problem with both ways is that they do not allow me to do a proper redirect, that is, the URL will remain the same even if the view was changed. Is there a better way to handle these redirects?
EDIT It seems my question is not clear. In particular it is not clear what I mean by abstract the common part in a function. So, what I could do is the following
def get_edition_or_current(edition):
try:
event = Edition.objects.get(name=edition)
except ObjectDoesNotExist:
event = Edition.latest()
return event
def home(request, edition):
event = get_edition_or_current(edition)
# I go on with a valid event here
def location(request, edition):
event = get_edition_or_current(edition)
# I go on with a valid event here
In this way I can display the view for a proper event, but I cannot change the URL. To change the URL, the view must return a redirect. I cannot set the return value for the view from inside get_edition_or_current.
So, how does Django implements get_object_or_404? Well, it is simple, it raises an Http404 exception, and catches it later. But of course this only works for Http404 exceptions, because Django is instructed to catch them.
I think the simplest way to do this would be to create new utility function called get_object_or_redirect in the same vein as get_object_or_404. You could probably even copy the contents of get_object_or_404 from django.shortcuts as a starting point for your implementation, or just extract out what you have above.
EDIT: as noted in the comments, a redirect cannot be done via raising an "exception," so this really can't work the same as get_object_or_404.
After some more thought, I have found a solution. It is enough to
use get_object_or_404
customize the 404 view, but not directly set it to the desired view. Rather, set it to a view which will send a redirect to the correct view.
Example
handler404 = views.error404
# Inside views
def error404(request):
return redirect(...)
Using Marius Gedminas's excellent blog post, I have created a custom traverser for a folder in my site.
This allows me to show: http://foo.com/folder/random_id
Instead of: http://foo.com/folder/object.html?id=random_id
The configuration side works great, I can catch the random_ids and search through my messages for the correct one, ready to display.
My problem is that I'm unsure how to then display the data via my usual page templates - at the TODO point in his original code ;)
if name == 'mycalendar':
mycalendar = ... # TODO: do something to get the appropriate object
return mycalendar
Usually I'd use something similar to:
class Test(BrowserPage):
template = ViewPageTemplateFile('atest.pt')
def __call__(self):
return self.template()
But I can't work out how to do this correctly in the context of the custom traversal.
UPDATE: To be clear I want to avoid adding anything else to the url (No: http://foo.com/folder/random_id/read).
I don't need the view to be available via any other address (No: http://foo.com/folder/read)
The ZCML for the view I'd like to use is:
<browser:page
for="foo.interfaces.IFooFolderContainer"
name="read"
template="read.pt"
permission="zope.ManageContent"
/>
I'm guessing (on further advice), something along the lines of:
return getMultiAdapter((mycalendar, self.request), IPageTemplate, name=u'read')
Or even a default view for the object type (a dict in this case) that's being returned:
<browser:page
for="dict"
name="read"
template="read.pt"
permission="zope.ManageContent"
/>
It would be easier to answer your question if you showed what your custom traverser is doing.
Essentially, you want something like this:
def publishTraverse(self, request, name):
if name in self.context:
return MyMessageView(self.context[name], request)
# fall back to views such as index.html
view = queryMultiAdapter((self.context, request), name=name)
if view is not None:
return view
# give up and return a 404 Not Found error page
raise NotFound(self.context, name, request)
where MyMessageView can be something as simple as
class MyMessageView(BrowserPage):
__call__ = ViewPageTemplateFile('read.pt')
Disclaimer: I'm not sure if the view you instantiate directly will be protected by a security wrapper; make sure your functional tests ensure anonymous users can't view messages if that's what you want.
If you end up at a proper object with your custom traverser, you can just tack on the template name and user "context" in that template. So http://foo.com/folder/random_id/my_template and in the template do the normal <h1 tal:content="context/title" /> stuff.
IIUC, what you want is to render the 'read' view when somebody requests /folder/random_id. If that's the case, all you need to do is make your traversal return an object (IFolderContent, maybe) representing a random_id and specify the 'view' page as the defaultView for IFolderContent.
The defaultView is needed because there's no view specified for the random_id object in your URL.