Paginated based on the alphabet (A-Z) - python

I have a simple contacts application where I want to paginate the contact list based on first name alphabet.
Here is my views.py
def contacts(request):
contact_list = Contact.objects.filter(user=request.user).order_by('first_name')
return render(request, 'contact/contact.html', {'contact_list': contact_list})
Here is my template
<ul>
{% for contact in contact_list %}
<li>{{ contact.first_name }}</li>
{% endfor %}
</ul>
Is there a default way in Django that does this? There is Django pagination but I think that only splits data across pages. What would be the easiest way to do so?

It seems a letter-wise paginator does not exist by default. Pages like https://djangosnippets.org/snippets/1364/ <<< this one show hand-made implementations.
However, it's not so hard to implement: you can base yourself on startswith keyword and:
pages = [myQuerySet.filter(myfield__istartswith=i) for i in "ABC...XYZ"] #full alphabet here
(let myQuerySet be, actually, contact_list; let myfield be, actually, first_name).

I've done this once, by adding a letter field to my model and "paginating" manually. This raised a lot of interesting situation with foreign alphabets. Found this useful: https://pypi.python.org/pypi/Unidecode
Didn't find any "smarter" way to go about it. But I'd be interested in hearing about more "plug-n-play" solution...

Related

How to iterate a queryset list in a django template

Is there a way to iterate this list of querysets in the template?
[<Director: Roman Polanski>, <Director: Alfred Hitchcock>,
<Director: Steven Spielberg>, <Director: David Lynch>]
I tried using a list syntax, but the django template language doesn't seem to accept lists, also.
Thank you all.
Django's template language does of course accept lists!
Here is what the code in your template should look like:
{% for director in director_list %}
{{ director }}
{% endfor %}
By the way: What you're having here is a queryset (that gets evaluated to a list), not a list of querysets.

How to iterate a dynamic variable in a Django template

Some slightly related questions have been asked about this, but the answers did not really help me. When I tried to implement a potential good hint suggested elsewhere (custom templates), I did not get the desired results.
In my template, I am iterating over a set of keys from a dictionary. The dictionary itself originates from submitting a Django formset.
XML Template snippet: (I am rendering to an XML file)
{% for x in range %}
<file type="{{ form-'x'-type }}" viewpath="{{ form-'x'-file }}"/>
{% endfor %}
The above obviously does not work. The iteration works. The rangevariable is a python argument corresponding to range(int(request.POST['form-TOTAL_FORM'])) passed from the view to the XML template.
At every iteration in the template, I need {{ form-0-type }}, {{ form-1-type}}, {{ form-2-type }}, etc.
How do I do that? If I really need to use a custom filter for this, how do I do this?
I hope this question (and the answers) will help many having the same problem.
Thanks.
Edit:(Dictionary posted)
<QueryDict:
{
u'form-MAX_NUM_FORMS': [u'1000'],
u'form-INITIAL_FORMS': [u'0'],
u'form-TOTAL_FORMS': [u'2'],
u'form-0-type': [u'1'],
u'form-1-type': [u'2'],
u'csrfmiddlewaretoken': [u'LpkjdDcqRCL4VPM0SAuU7efgZjgeubTN']
}>
Additional note:
In a second view, I lookup the values for the foreign keys and put the values in another dictionary, which I send to my XML template.
Snippet of the code that does this:
detailed_request = {}
for x in range(0, int(request.POST['form-TOTAL_FORMS'])):
detailed_request['form-'+str(x)+'-type'] = Upload_Type.objects.get(pk=request.POST['form-'+ str(x)+'-type'])
detailed_request['form-'+str(x)+'-file'] = request.FILES['form-'+str(x)+'-file']
The above is a working snippet. When I trace detailed_request, I have all the information I need:
{
'form-1-type': <Upload_Type: malib>,
'form-0-type': <Upload_Type: axf_file>
}
Just in case somebody has the same problem, I actually changed the way I do things.
I do not iterate the formset in the template. Instead, I implemented the solution from Paolo Bergantino here:
Dynamically adding a form to a Django formset with Ajax
Then in my views, I simply get every data I need from request.FILES
I hope that helps anybody who started with the same wrong approach.
You can access the for loop helper variables through the following variables
forloop.counter The current iteration of the loop (1-indexed)
forloop.counter0 The current iteration of the loop (0-indexed)
More at: https://docs.djangoproject.com/en/dev/ref/templates/builtins/#for
So you'd do...
{{ form }}-{{ forloop.counter }}-{{ type }}

two or more dots in a django template after the variable

In a django template, is it possible to have two (or more) dots after a variable? For example, say I have a list of objects that I first want to use a list-index lookup for and then once I have the object, I want to call its method for getting the absolute url, should that work?
For example:
{% for entry in myList %}
{{ entry.0.get_absolute_url }}
{% endfor %}
So the 0 is asking for the first item in the list which is an object, then I want to get the absolute url. It doesn't work when I try it but it doesn't return an error either. Is there a better way to accomplish what I'm trying to do?
To clarify it, what's strange is that:
This works:
{{ singleObject.get_absolute_url }}
In that case if I just try {{ singleObject }}, I get the unicode value of that object so something like: John Smith
This doesn't work:
{% for object in objectList %}
{{ object.get_absolute_url }}
{% endfor %}
But in this case, if I put in {{ object }}, I no longer get the unicode value. I get: [<Name: John Smith>] (name being the name of the model)
Basically, the method works when it's outside of a loop. Could there be any reason for that?
more than one dot absolutely works.
based on your comment, there is no entry.0 because entry IS the first item in the list cause you are already looping through `myList'
just use entry.get_absolute_url instead
but if you only want to print out the url for the first entry, forgo the for loop and just use myList.0.get_absolute_url
UPDATE:
there's a tip from 'the pragmatic programmer' that says:
``select’’ Isn’t Broken
It is rare to find a bug in the OS or the
compiler, or even a third-party product or library. The bug is most
likely in the application.
i think you assumed that django templates were behaving weird, when the truth is you were not building your list correctly. don't be afraid to show some of your actual code, by abstracting the problem for us, you removed the part that included the problem
I got it. I had brackets around each item in my list like so:
objectList = [['John Smith'], ['Jim Jones'], ['Bill White']]
Silly me! Thanks so much for your all your input
What you are doing is perfectly acceptable in Django templates. There is no better way to accomplish what you're trying to do.

use two variables in django template if tag

Hi all not sure how to explain this clearly but here goes....
I need to use two variables like so:
{% for client in clients %}
{% if user.client.username %}
I need {% if user.username %} but the value of username is in client.username from the loop.
is there a way to do this?
If I understand correctly, user is a dict, and you want to lookup the value indexed by client in each iteration of the loop - eg, user[client].username in Python.
This (deliberately) isn't possible in Django templates - the language is limited, to force you to do pre-processing in code.
Instead, you should zip your two lists/dicts together before passing them to the template.
Are you trying to do something if the value of client.username is equal to the value of user.client.username? If so, you want:
{% if client.username == user.client.username %} # Works in Django 1.2 and above
{% ifequal client.username user.client.username %} # Works everywhere

Google appengine string replacement in template file

I'm using google appengine (python, of course :) ) and I'd like to do a string.replace on a string from the template file.
{% for item in items %}
<p>{{ item.code.replace( '_', ' ' ) }}</p>
{% endfor %}
But that isn't working. So we cannot execute anything other than basic checks in the app engine templates. Is that Correct ?
Another related problem is I'm trying to shorten a string and make it available to the template.
Each furniture object has a name and a longer description field. In this view I'm rendering, I want only the first 50 characters of the description field.
So I tried something like
items = db.GqlQuery( 'select * from furniture' )
# edit: if you change the above line to
# items = db.GqlQuery( 'select * from furniture' ).fetch( 1000 )
# the .fetch() command makes the addition of dynamic properties work!
for item in items :
item.shortdescr = item.description[ 0:50 ]
# pass data off to template for rendering
self.response.out.write(
template.render( 'furnitureAll.html', { 'items' : items } )
)
Template goes
{% for item in items %}
<p>{{ item.name }}</p>
<p>{{ item.shortdescr }}</p>
<!-- items.shortdescr does not exist here,
probably because I did not .put() it previously. -->
{% endfor %}
Since that didn't work, I tried changing the Gql Query to shorten the string instead. But I'm quickly realizing Gql isn't like SQL. I'm trying to write queries like
select name,LEFT( description, 50 ) from furniture
With little success
I have little experience with Google AppEngine, but my understanding is that it is very closely related to Django. Your templates do not actually contain Python code, even if some of the structures you use in them look like it.
Both of your questions should be solved using template filters. If it was Django, I would use something like this for your second question:
{{ item.description|truncatewords:10 }}
For your first question (string replace), there may be no built-in filter you can use for that. You will need to write your own. Something like this;
from google.appengine.ext.webapp.template import create_template_register
register = create_template_register()
#register.filter
def replace_underscores(strng):
return strng.replace('_', ' ')
Then, in your template, you can do this:
{{ item.code|replace_underscores }}
Apart from the argument-less .fetch() call in your code, which I believe can't possibly work (you ALWAYS have to pass fetch an argument -- the max number of entities you're willing to fetch!), I can't reproduce your problem -- assigning a new attribute (including one obtained by processing existing ones) to each item just works fine in my tests.
Can you please reproduce your observed problem in as tiny as compass as possible and edit your question to include all relevant files pls? Seems to be the only way we could help you with your weird observed bug!
BTW, select name,LEFT( description, 50 ) or whatever OF COURSE won't work in GQL -- GQL, very very explicitly, ONLY supports select * to get whole entities, or select __key__ to get just the entities' keys -- that's all; NO selectivity of columns in the select, much less any OPERATIONS on them!-)

Categories