I'm trying to display a directory tree from a a treebeard model. The annotated list method suggested in the treebeard tutorial works fine, but I'd like to include id information in the data tree.
The dump_bulk() has all the info I need, but as a python and django newbie I'm strugglling to find a way to extract the information and display it in the template.
I've thought about switching to javascript, and parsing the json string, but javascript doesn't like the u prefix before the string values. Is there a simple way to avoid the u prefix?
I've also thought about writing a function based on the get_annotated_list() that does include id information. I'm assuming it should be possible to overload the get_annotated_ list so that id information is included, but I'm not too sure how to tackle that either.
Any and all suggestions to help me progress along the learning curve will be appreciated.
As you probably know, get_annotated_list() will return an array of tuples, in the form (node, info). info is just a dictionary, so you can iterate over the list, and add any additional key-pairs you like. E.g.,
for node, info in my_annotated_list:
info['foo'] = node.id
Pass this to your template, and you should be fine.
You can also use a generator. This is from a project I'm working on right now:
def annotated_menu_items(initial_header, menu_items):
headings = [initial_header]
for item, info in menu_items:
yield item, info, item.is_leaf(), headings[-1:][0]
if info['open']:
headings.append(item.title)
for close in info['close']:
headings.pop()
Here, I'm adding as extra info whether the node in question is a leaf, and pushing the title from the most recently opened node onto a stack so I can access it from deeper levels of the tree.
You say you're new to Python, so you may want to read up on generators. They you materialize the elements of a (potentially infinite) list lazily. In order to use it, you invoke the function which constructs the generator, then you can treat the generator object as an iterable. E.g.,
my_fancy_menus = annotated_menu_items("My Menu", my_annotated_list)
for menu in my_fancy_menus:
do_stuff(menu)
You can also pass generators to Django templates, where they are treated like lists.
Related
I have what I believe to be common but complicated problem to model. I've got a product configurator that has a series of buttons. Every time the user clicks on a button (corresponding to a change in the product configuration), the url will change, essentially creating a bookmarkable state to that configuration. The big caveat: I do not get to know what configuration options or values are until after app initialization.
I'm modeling this using EmberCLI. After much research, I don't think it's a wise idea to try to fold these directly into the path component, and I'm looking into using the new Ember query string additions. That should work for allowing bookmarkability, but I still have the problem of not knowing what those query parameters are until after initialization.
What I need is a way to allow my Ember app to query the server initially for a list of parameters it should accept. On the link above, the documentation uses the parameter 'filteredArticles' for a computed property. Within the associated function, they've hard-coded the value that the computed property should filter by. Is it a good idea to try to extend this somehow to be generalizable, with arguments? Can I even add query parameters on the fly? I was hoping for an assessment of the validity of this approach before I get stuck down the rabbit hole with it.
I dealt with a similar issue when generating a preview popup of a user's changes. The previewed model had a dynamic set of properties that could not be predetermined. The solution I came up with was to base64 encode a set of data and use that as the query param.
Your url would have something like this ?filter=ICLkvaDlpb0iLAogICJtc2dfa3
The query param is bound to a 2-way computed that takes in a base64 string and outputs a json obj,
JSON.parse(atob(serializedPreview));
as well as doing the reverse: take in a json obj and output a base64 string.
serializedPreview = btoa(JSON.stringify(filterParams));
You'll need some logic to prevent empty json objects from being serialized. In that case, you should just set the query param as null, and remove it from your url.
Using this pattern, you can store just about anything you want in your query params and still have the url as shareable. However, the downside is that your url's query params are obfuscated from your users, but I imagine that most users don't really read/edit query params by hand.
I'm trying to wrap my head around the difference between a "collection" and a "store" in REST. From what I've read so far,
a collection is:
"a server-managed directory of resources"
and a store is a:
"client-managed resource repository"
I found this post: How "store" REST archetype isn't creating a new resource and a new URI?
but it didn't really help me clarify the difference. I mean, I understand one is controlled by the server and the other by the client... but can someone give me a concrete example of what a store might be in a real world application?
I *think it's something like this:
GET http://myrestapplication.com/widgets/{widget_id} -- retrieves a widget from db
POST http://myrestapplication.com/widgets/{widget_id} -- creates a new widget from db
PUT http://myrestapplication.com/widgets/{widget_id},[list of updated parms & their vals] -- update widget
PUT http://myrestapplication.com/users/johndoe/mywishlist/{widget_id} -- updates john doe's profile to add a widget that already exists in the database... but links to it as his favorite one or one that he wants to buy
Is this correct?
if so, could the last PUT also be expressed as a POST somehow?
EDIT 1
I found an online link to the book i'm reading... where it makes the distinction between the two:
https://books.google.ca/books?id=4lZcsRwXo6MC&pg=PA16&lpg=PA16&dq=A+store+is+a+client-managed+resource+repository.+A+store+resource+lets+an+API+client:+put+resources+in,+get+them+back+out,+and+decide+when+to+delete+them&source=bl&ots=F4CkbFkweL&sig=H6eKZMPR_jQdeBZkBL1h6hVkK_E&hl=en&sa=X&ei=BB-vVJX6HYWvyQTByYHIAg&ved=0CB0Q6AEwAA#v=onepage&q=A%20store%20is%20a%20client-managed%20resource%20repository.%20A%20store%20resource%20lets%20an%20API%20client%3A%20put%20resources%20in%2C%20get%20them%20back%20out%2C%20and%20decide%20when%20to%20delete%20them&f=false
REST uses http verbs to manipulate resources. Full-Stop. That's it. To build some classes of browser-based application developers sometimes use local storage (a store), but that has absolutely nothing to do with REST (in fact, it's the opposite). Collections are a special consideration in REST-based API design because the REST principles place considerable constraints on how they are represented in the results of your queries -- special consideration also because there are no standards on how these things should be represented and access if you're using anything other than html as a resource type.
Edit:
REST suggests that when we ask for a resource we receive that resource and only that resource and that things referenced by that resource are returned as links, not as data. This mimics the http standard by which we return the requested page and links to other pages rather than embedding linked pages. So, our resources should return links to related resources, not the resources themselves.
So, what about collections?
Let's use as an example a college management system that has Course objects each of which contains a huge lists of Students.
When I GET the course I don't want to have the collection of students returned as an embedded list, because that could be huge and because my user might not be interested. Instead, I want to know that the course has a students collection and I want to be able to query that collection separately (when I need to) and I want to be able to page it on demand. For this to work, the course needs to link to the students collection URL (maybe with an appropriate type so that my code knows how to handle the link). Then, I want to use the given collection's url to request a paged list of resources. In this example, the collection's url could be something like: course/1/students, with the convention that I can add paging info to the search string to constrain the results with something like course/1/students?page=1&count=10. Embedding the students collection into the course resource would be a violation of REST. I would not be returning a course, I'd be returning course-and-students.
during our school project we have a task to implement a working "Login System" using python.
I have done almost everything but I keep struggling with two of the functions implemented in the program. I will try to explain as much as i can what is the purpose of the system so you will be able to understand what i am facing with :)
Basically I am using objects for 2 roles of users ( Admin and general user ), and a book objects. Each user can login to the system and them he is presented with 5 different choices: add book, remove book, list book, share books (this one checks if any other user is reading the same book), and exit. I am having extreme difficulties with removing a book and sharing a booklist.
So far I have been storing my objects inside a list and have managed to complete all the functions so they were working properly. but heres the problem: This is how i stored objects inside a nested list so each book can be associated with a desired user
books=[book1,[user1],book2,[user1,user3],book3,[user3,user2],book4,[user1,user4,user3]]
But whenever i try to delete a book i use this function and it wont work. I know this block of code is basically useless for you but I have posted it anyway so you can maybe get a better idea of what I am trying to do.
total=len(books)
a=input("\nType in the book you want to delete:\n")
if (total!=0):
for i in range(total):
if(a==books[i].title):
del(books[i])
print("Book has been deleted\n\n")
print(books)
break
The following block of code is used for a sharing book function and is actually working.
books2=[]
books3=[]
xStr=input("Enter the name of the book\n")
for i in range(len(books)):
if (i%2==1): #This will select only users asociated with a book
books2.append(books[i])
if (i%2==0): #This will select only the books
books3.append(books[i])
for i in range(len(books2)):
for j in range(len(books2[i])):
if (books3[i].title==xStr):
print("Book: ",books3[i],"is also used by:",books2[i][j-1].username)
I have also tried with dictionaries but it didn't work.
So what I would like to know is:
- which in your opinion would be the best way to store objects for this kind of a program
- which data structure should I use and how it is done basically
I hope I didn't complicate too much and sorry for my bad english :)
Thank you very much
This list is not optimal, there are better ways to go about this.
Important thing to realize is that a single object can be referred to in several lists or dictionaries. Also, objects can contain list attributes.
So you can maintain a list of all books. And a list of all users.
And a user can have a book list attribute that can then refer to books too, for example the ones he has read:
class User:
booksRead = []
or, using the constructor:
class User:
def __init__(self):
self.booksRead = []
Then to add a book to a user's list:
user.booksRead.append(book)
This is just one of many ways to organize this. If you wish to look up items in a list based on a key, use a dictionary.
You'll find better ways to organize your data as you learn more and write more code; for now, take a close look at the difference between your delete code and your sharing code . . . (hint: your sharing code knows that only every other entry is a book).
Say I request
parent/child/child/page-name
in my browser. I want to extract the parent, children as well as page name. Here are the regular expressions I am currently using. There should be no limit as to how many children there are in the url request. For the time being, the page name will always be at the end and never be omitted.
^([\w-]{1,}){1} -> Match parent (returns 'parent')
(/(?:(?!/).)*[a-z]){1,}/ -> Match children (returns /child/child/)
[\w-]{1,}(?!.*[\w-]{1,}) -> Match page name (returns 'page-name')
The more I play with this, the more I feel how clunky this solution is. This is for a small CMS I am developing in ASP Classic (:(). It is sort of like the MVC routing paths. But instead of calling controllers and functions based on the URL request. I would be travelling down the hierarchy and finding the appropriate page in the database. The database is using the nested set model and is linked by a unique page name for each child.
I have tried using the split function to split with a / delimiter however I found I was nested so many split statements together it became very unreadable.
All said, I need an efficient way to parse out the parent, children as well as page name from a string. Could someone please provide an alternative solution?
To be honest, I'm not even sure if a regular expression is the best solution to my problem.
Thank you.
You could try using:
^([\w-]+)(/.*/)([\w-]+)$
And then access the three matching groups created using Match.SubMatches. See here for more details.
EDIT
Actually, assuming that you know that [\w-] is all that is used in the names of the parts, you can use ^([\w-]+)(.*)([\w-]+)$ instead and it will handle the no-child case fine by itself as well.
I have the following for-each select;
"sc:item($myFolder,.)/descendant::item [#template='myTemplate']". According to Sitecore's own profiler this returns crawls through 16.000 items, although there are only approx 1700 items with the mentioned template.
Could this be optimized - if so, how?
The for-each is not the problem, but the XPath query used is.
The descendant axis is usually expensive because it requires the engine to do a complete deep search, without the possibility of eliminating paths. So you may want to replace this with a pattern which restricts the required search path.
Maybe using keys would help, but without deeper knowledge of the XML to be processed and the operations performed this is hard to tell.
If you can convert your xsl:for-each to a xsl:template, it should help with performance, as most XSLT processors are optimized for template matching.
"Do you have an example of this? It's a basic for-each that select a list of items based on the template, and then sort by a number field and shows the 3 top (so its basicly a top 3 list)"
Based on what you're trying to accomplish, I think you would be much better off putting this logic into a save handler and organizing your items when a content author saves an item based on the template you're looking for.
For example (and this is a very rough example), create a "Top 3" folder in your content tree. Then, write a save handler that checks the TemplateID of an item as it's being saved. If the saved item's TemplateID matches the TemplateID you're looking for, select all the items in your tree based on the TemplateID and process them with whatever sorting logic you need. As you find an item that belongs in the "Top 3" folder, move the item to the "Top 3" folder.
Then, in your rendering code, you simply have to get the "Top 3" folder and retrieve it's children. This will be MUCH faster than attempting to look through 1700 items every time the rendering is loaded.
If I need to do any particularly difficult searches in an XSLT, then I often define an XSLT helper method to perform the search, as the .Net API has much better facilities available.
In your case, I'd consider creating a .Net function to do the job, either using the Link Manager (as Mark Cassidy suggests) or using Sitecore fast queries to retrieve the items (fast queries are parsed and run as SQL queries).
To register a class as an XML Extension Method library, open web.config, locate the /configuration/sitecore/xslExtensions node and add an entry with your class' full type name and an XML namespace (the URL doesn't actually have to exist).
To use your function, register it in the namespaces at the top of your XSLT (and remember to add the namespace to the exclude-result-prefixes stylesheet attribute). You should then be able to call `namespace:YourFunction().
For more detailed information on XSLT extension methods, see the presentation component reference, page 40.
The reason the XSLT crawls through 16,000 items when you only have 1700 matches is that the 16,000 represents the number of nodes tested, not the number of nodes returned. Sitecore XSLT performance is dependent on your actual data structure, if you have a flat structure with lots of nodes (e.g. everything in one folder) all xslt processing will suffer. You might consider optimising your data structure into something deeper and more branched to aid XSLT performance. I believe Sitecore themselves recommend that you have no more than 100 items in any location (i.e. never more than 99 siblings for any item).
It can be optimised, but the easiest approach would be to reorganize your content architecture to better suit your needs and requirements.
Straight from XSLT there is no easy solution, but with a bit of coding you can fAirly easily get all your content items based on your specific template. It would look something like this:
Item myTemplate = Sitecore.Context.Database.GetItem( "id-of-your-template" );
LinkItem[] li = Sitecore.Globals.LinkDataBase.GetReferrers( myTemplate );
// li now holds a list of LinkItem for items that are based on your template
List<Item> myItems = new List<Item>();
foreach( LinkItem l in li )
myItems.Add( li.SourceItem() );
// your additional processing/filtering here
Keep in mind, this is a very non-specific example of how this can be achieved. I would need to know a lot more about your solution to come up with a better response. And I still feel, the best approach is probably still to look at your information architecture.