Can you have multiple generic subviews of a content element in Kotti? - python

You can add a 'view' for a content type in kotti by doing something along these lines:
from kotti_mysite.views import poll_view
config.add_view(
poll_view,
context=Poll,
name='view',
permission='view',
renderer='kotti_mysite:templates/poll.pt',
)
(more details: http://kotti.readthedocs.org/en/latest/first_steps/tut-2.html)
You can also have multiple views, and use the 'set default view', but sometimes it's convenient to have several similar views with very similar urls.
For example, in plone, its trivial to have a url structure like this:
/blah/item/ <--- Normal view
/blah/item/json <--- Json version of item
/blah/item/pdf <--- PDF download of item
You can... sort of, do a similar thing in kotti by screwing with the view you create and rendering different content based on get/post params, but it's messy, and frankly, rather rubbish.
The only solution I've found is to have a custom content type 'JsonView' that has a json renderer, and add it as a child of the parent object, and it's renderer looks for the parent content, and renders that.
However, doing this requires you to manually create a 'JsonView' child for every instance of the type you want, which is also rather cumbersome.
Is there a better way of doing this?
--
Nb. Specifically note that having a custom view /blah/item/json isn't any use at all; any type of item, in any parent folder should be able to render in the way described above; using a single static route isn't the right solution.

You can register a json view for all your content like this:
from kotti.interfaces import IContent
config.add_view(
my_json_view,
context=IContent,
name='json',
permission='view',
renderer='json',
)
This way, when you open /blah/json, where /blah points to some content, it will call your my_json_view view.
SQLAlchemy's new class object inspection system might help you write a useful generic json view that works for more than one content type. Alternatively, you can register your view for specific content types only (by use of a more specific context argument in config.add_view).
Using renderer='json' you tell Pyramid that you want to use its json renderer.

Related

flask_admin change inline_models behaviour

I want to change some existing Python code that uses flask_admin. One of the views uses inline_models with the (ClassName, Options) declaration pattern. The inlined class has, amongst others, a text field.
I want to change the flask_admin default behaviour in the following ways:
I want to make the text field read-only. I.e. still display it, but prevent the user from changing existing content.
I do not want to allow users to delete instances of the inlined class, i.e. I want to get rid of the "Delete?" checkbox next to every entry.
I want to override the default "Add Item" button behaviour with some custom JavaScript.
I did some Googling around but anything that looked potentially promising also looked very non-trivial. I'm hoping for some reasonably straight forward way to achieve this.
Your help would be much appreciated.
Yeesh. It looks like we're out in poorly-documented territory, here. It's hard to know if I'm improving on what you've already found, but I'll hope you're looking for something easier than writing a custom administrative view template.
Following the calls, it looks like the options dictionary eventually gets passed to the constructor of InlineBaseFormAdmin where the various form_* keys are extracted and applied (not sure all are respected, but I see at least form_base_class, form_columns, form_excluded_columns, form_args, form_extra_fields, form_rules, form_label, form_column_labels, form_widget_args). I think you can accomplish what you need via form_widget_args, but you can probably also get there via form_rules or by overriding InlineBaseFormAdmin's get_form or postprocess_form methods:
class SomeModelView(MyBaseModelView):
...
inline_models = [(db.SomeOtherModel, {
"form_widget_args": {
"uneditable_field_name": {"readonly": True}
}
})]
...
The delete option can be controlled by providing your own inline form model to override display_row_controls:
from flask_admin.contrib.sqla.form import InlineModelConverter
from flask_admin.contrib.sqla.fields import InlineModelFormList
class CrouchingTigerHiddenModelFormList(InlineModelFormList):
def display_row_controls(self, field): return False
class MyInlineModelConverter(InlineModelConverter):
inline_field_list_type = CustomInlineModelFormList
#adding to above example
class SomeModelView(MyBaseModelView):
...
inline_model_form_converter = MyInlineModelConverter
inline_models = [(db.SomeOtherModel, {
"form_widget_args": {
"uneditable_field_name": {"readonly": True}
}
})]
...
NOTE: The widget args, such as readonly, are getting passed on to wtforms as render_kw, but at a blush the WTForms docs aren't clear that these get expressed as attributes in the resulting HTML input element (so any HTML input element attributes are valid here).
It looks like form.js controls this behavior, so you should be able to monkey-patch its addInlineField method to execute your own code before or after the model addition. You could override the create and/or edit templates for this--but if you're using flask-admin 1.5.0+, this might be as simple as adding extra_js = ["your-custom.js"] to the view class (caution: it looks like this script gets included on every page for this view).

Exposing global data and functions in Pyramid and Jinja 2 templating

I have a base template for when a user is logged in, and on that base template, I need to add user specific options in a drop down menu. This drop down menu with options must be constant across all handlers, i.e., any time the base template is invoked (extended) with a child template.
Other than performing the necessary DB query, assigning the query results to a variable, and passing that variable to every handler (there are many), how can I consolidate this into one query and one variable, which gets passed directly to the base template? I am using jinja2 templates as well.
I would hate to do something so cumbersome in exchange for something far more simple and maintainable.
Any ideas? Thanks.
EDIT
So I still haven't found anything that's exactly what I'm looking for; however, I decided to at least make some headway in the interim. So, I made a custom decorator that takes a view's returned dict() and appends the appropriate data to it. For example:
def get_base_data(func):
def wrapper(request):
d = func(request)
user_id = request.user.id # used in query
contact_group_data = ContactGroups.query.filter(...criteria...).all()
d['contact_group_data'] = contact_group_data
return d
return wrapper
Now, I can at least decorate each method very concisely and simply by putting:
#view_config(...)
#get_base_data
def my_handler(request):
pass # rest of code...
This is one of most inobvious things in Pyramid and took a while to find for me, too.
You can modify the global template context in BeforeRender event.
http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/hooks.html#using-the-before-render-event
Alternatively, you could use class based views, inherit all your views from one base view class which has get_base_data(), then the class instance is passed to the template context to all your views and then you could extract the data with {{ view.get_base_data }}.
http://ruslanspivak.com/2012/03/02/class-based-views-in-pyramid/
I vouch for the latter approach as it is more beautiful, predictable and easier to maintain engineering wise.

How to know on what page number flowable was placed during rendering a pdf with reportlab

How to determine on what page(need a page number) will be each flowable after rendering to pdf. I was thinking to add a custom id attribute to flowable, so i will know what flowable is it. But how can i determine on what page it will be placed?
What is the best way to achieve this?
At what point do you need this information? It becomes available as the document is constructed, so you can get it after rendering by overriding methods such as afterPage, afterDrawPage, and afterFlowable. You can then get the page number from the DocTemplate class (I believe there's a class variable called something like _currentPage, but you'll need to check the ReportLab code since I don't think it's documented).
I ended with following solution. Addeda an custom id flo_id to every flowable. And override method handle_flowable in BaseDocTemplate, where was checking and saving id,
class SignDocTemplate(BaseDocTemplate):
blocks_to_pages = {}
def handle_flowable(self, flowables):
f = flowables[0]
BaseDocTemplate.handle_flowable(self, flowables)
if hasattr(f,'flo_id'):
if self.blocks_to_pages.has_key(self.canv._pageNumber):
self.blocks_to_pages[self.canv._pageNumber].append(f.flo_id)
else:
self.blocks_to_pages[self.canv._pageNumber]= [f.flo_id,]
And after building a doc it will be available at document instance in blocks_to_pages variable.

Meaning of the map function in couchdb-pythons ViewField

I'm using the couchdb.mapping in one of my projects. I have a class called SupportCase derived from Document that contains all the fields I want.
My database (called admin) contains multiple document types. I have a type field in all the documents which I use to distinguish between them. I have many documents of type "case" which I want to get at using a view. I have design document called support with a view inside it called cases. If I request the results of this view using db.view("support/cases), I get back a list of Rows which have what I want.
However, I want to somehow have this wrapped by the SupportCase class so that I can call a single function and get back a list of all the SupportCases in the system. I created a ViewField property
#ViewField.define('cases')
def all(self, doc):
if doc.get("type","") == "case":
yield doc["_id"], doc
Now, if I call SupportCase.all(db), I get back all the cases.
What I don't understand is whether this view is precomputed and stored in the database or done on demand similar to db.query. If it's the latter, it's going to be slow and I want to use a precomputed view. How do I do that?
I think what you need is:
#classmethod
def all(cls):
result = cls.view(db, "support/all", include_docs=True)
return result.rows
Document class has a classmethod view which wraps the rows by class on which it is called. So the following returns you a ViewResult with rows of type SupportCase and taking .rows of that gives a list of support cases.
SupportCase.view(db, viewname, include_docs=True)
And I don't think you need to get into the ViewField magic. But let me explain how it works. Consider the following example from the CouchDB-python documentation.
class Person(Document):
#ViewField.define('people')
def by_name(doc):
yield doc['name'], doc
I think this is equivalent to:
class Person(Document):
#classmethod
def by_name(cls, db, **kw):
return cls.view(db, **kw)
With the original function attached to People.by_name.map_fun.
The map function is in some ways analogous to an index in a relational database. It is not done again every time, and when new documents are added the way it is updated does not require everything to be redone (it's a kind of tree structure).
This has a pretty good summary
ViewField uses a pre-defined view so, once built, will be fast. It definitely doesn't use a temporary view.

How do I submit a form given only the HTML source?

I would like to be able to submit a form in an HTML source (string). In other words I need at least the ability to generate POST parameters from a string containing HTML source of the form. This is needed in unit tests for a Django project. I would like a solution that possibly;
Uses only standard Python library and Django.
Allows parameter generation from a specific form if there is more than one form present.
Allows me to change the values before submission.
A solution that returns a (Django) form instance from a given form class is best. Because it would allow me to use validation. Ideally it would consume the source (which is a string), a form class, and optionally a form name and return the instance as it was before rendering.
NOTE: I am aware this is not an easy task, and probably the gains would hardly justify the effort needed. But I am just curious about how this can be done, in a practical and reliable way. If possible.
You should re-read the documentation about Django's testing framework, specifically the part about testing views (and forms) with the test client.
The test client acts as a simple web browser, and lets you make GET and POST requests to your Django views. You can read the response HTML or get the same Context object the template received. Your Context object should contain the actual forms.Form instance you're looking for.
As an example, if your view at the URL /form/ passes the context {'myform': forms.Form()} to the template, you could get to it this way:
from django.test.client import Client
c = Client()
# request the web page:
response = c.get('/form/')
# get the Form object:
form = response.context['myform']
form_data = form.cleaned_data
my_form_data = {} # put your filled-out data in here...
form_data.update(my_form_data)
# submit the form back to the web page:
new_form = forms.Form(form_data)
if new_form.is_valid():
c.post('/form/', new_form.cleaned_data)
Hopefully that accomplishes what you want, without having to mess with parsing HTML.
Edit: After I re-read the Django docs about Forms, it turns out that forms are immutable. That's okay, though, just create a new Form instance and submit that; I've changed my code example to match this.
Since the Django test framework does this, I'm not sure what you're asking.
Do you want to test a Django app that has a form?
In which case, you need to do an initial GET
followed by the resulting POST
Do you want to write (and test) a Django app that submits a form to another site?
Here's how we test Django apps with forms.
class Test_HTML_Change_User( django.test.TestCase ):
fixtures = [ 'auth.json', 'someApp.json' ]
def test_chg_user_1( self ):
self.client.login( username='this', password='this' )
response= self.client.get( "/support/html/user/2/change/" )
self.assertEquals( 200, response.status_code )
self.assertTemplateUsed( response, "someApp/user.html")
def test_chg_user( self ):
self.client.login( username='this', password='this' )
# The truly fussy would redo the test_chg_user_1 test here
response= self.client.post(
"/support/html/user/2/change/",
{'web_services': 'P',
'username':'olduser',
'first_name':'asdf',
'last_name':'asdf',
'email':'asdf#asdf.com',
'password1':'passw0rd',
'password2':'passw0rd',} )
self.assertRedirects(response, "/support/html/user/2/" )
response= self.client.get( "/support/html/user/2/" )
self.assertContains( response, "<h2>Users: Details for", status_code=200 )
self.assertContains( response, "olduser" )
self.assertTemplateUsed( response, "someApp/user_detail.html")
Note - we don't parse the HTML in detail. If it has the right template and has the right response string, it has to be right.
It is simple... and hard at the same time.
Disclaimer: I don't know much about Python and nothing at all about Django... So I give general, language agnostic advices...
If one of the above advices doesn't work for you, you might want to do it manually:
Load the page with an HTML parser, list the forms.
If the method attribute is POST (case insensitive), get the action attribute to get the URL of the request (can be relative).
In the form, get all input and select tags. The name (or id if no name) attributes are the keys of the request parameters. The value attributes (empty if absent) are the corresponding values.
For select, the value is the one of the selected option or the displayed text is no value attribute.
These names and values must be URL encoded in GET requests, but not in POST ones.
HTH.
Check out mechanize or it's wrapper twill. I think it's ClientForm module will work for you.

Categories