From my template:
July
URL Pattern:
url(r'^ocal/$', views.calendar, name = "othermonth"),
View:
def calendar(request, year, month):
my_year = int(year)
my_month = int(month)
my_calendar_from_month = datetime(my_year, my_month, 1)
my_calendar_to_month = datetime(my_year, my_month, monthrange(my_year, my_month)[1])
my_tickets = Event.objects.filter(on_sale__gte=my_calendar_from_month).filter(on_sale__lte=my_calendar_to_month)
my_previous_year = my_year
my_previous_month = my_month - 1
if my_previous_month == 0:
my_previous_year = my_year - 1
my_previous_month = 12
my_next_year = my_year
my_next_month = my_month + 1
if my_next_month == 13:
my_next_year = my_year + 1
my_next_month = 1
my_year_after_this = my_year + 1
my_year_before_this = my_year - 1
cal = TicketCalendar(my_tickets).formatmonth(year, month)
return render_to_response('calendar.html', {'events_list': my_tickets,
'calendar': mark_safe(cal),
'month': my_month,
'month_name': named_month(my_month),
'year': my_year,
'previous_month': my_previous_month,
'previous_month_name': named_month(my_previous_month),
'previous_year': my_previous_year,
'next_month': my_next_month,
'next_month_name': named_month(my_next_month),
'next_year': my_next_year,
'year_before_this': my_year_before_this,
'year_after_this': my_year_after_this,
}, context_instance=RequestContext(request))
Error:
Reverse for 'othermonth' with arguments '(2013, 7)' and keyword arguments '{}' not found.
I've searched through stackoverflow and the django documentation but I can't seem to figure out why I'm getting this NoReverseMatch error. I'm sure its a very simple oversight on my part because I'm staring at code from a previous project which is almost identical to this and that works fine. Any help would be appreciated, thanks.
UPDATE: I tried removing the parameters that I was trying to send with the URL and that fixed the NoReverseMatch however the view that is called requires those arguments so the link fails.
How do you plan for those arguments to be embedded in your URL? There's nothing capturing them, and no way for the reverse lookup to construct it. You need a URL pattern that accepts these parameters. Something like:
url(r'^ocal/(?P<year>\d{4})/(?P<month>(0|1)?\d)/$', views.calendar, name = "othermonth_bymonth"),
Using keyword rather than positional arguments here is optional, but I think it makes things easier - and allows setting default values that can trigger behavior like showing a calendar for the current day when nothing's specified.
Also, your mytickets queryset can also be constructed thus:
mytickets = Event.objects.filter(on_sale__year=year, onsale__month=month)
Which I think is a little cleaner to read.
Actually, upon a closer look - Django's built in date based views can do a lot of this for you. If you haven't already looked into them, I recommend doing so:
https://docs.djangoproject.com/en/dev/ref/class-based-views/generic-date-based/
For this particular view, all you'd need to do is subclass MonthArchiveView to create your TicketCalendar instance and add it to your context.
Edit: OK, you're still getting problems. This is how I would go about solving this:
views.py
class TicketMonthArchiveView(MonthArchiveView):
allow_empty = True # show months even in which no tickets exist
allow_future = True # show future months
model = Event
def get_context_data(self, **kwargs):
base_context = super(TicketMonthArchiveView, self).get_context_data(**kwargs)
my_tickets = kwargs['object_list']
base_context['calendar'] = mark_safe(TicketCalendar(my_tickets).formatmonth(self.get_year(), self.get_month()))
# the above could be a little off because I don't know exactly how your formatmonth method works
return base_context
urls.py
from somewhere.views import TicketMonthArchiveView
# other patterns, plus:
url(r'^ocal/(?P<year>\d{4})/(?P<month>(0|1)?\d)/$', TicketMonthArchiveView.as_view(), name='calendar_by_month'),
template event_archive_month.html
{{ next_month|date:'%f' }}
Obviously there's a lot more you could do here with the year and day views, but this should demonstrate the general concepts.
Large context volumes caused this behavior for me as well, despite having the correct syntax.
I had this, on Django 1.5:
urls.py
url(r'(?P<CLASSID>[A-Z0-9_]+)/$', 'psclassdefn.views.psclassdefn_detail', name="psclassdefn_detail"),
template.html
{% for inst in li_inst %}
<li><a href={% url 'psclassdefn.views.psclassdefn_detail' CLASSID=inst.CLASSID %}></a></li>
{% endfor %}
I kept on getting NoReverseMatch even though the syntax seemed OK and I could reverse into a no-argument url.
Now, li_inst was a huge list of about 1000 rows fetched from the db and passed to the context variable. Just to test, I trimmed the list by removing all but 10 or so rows. And it worked, without any syntax changes.
Maybe the templating system intentionally throttles the context size? I can filter the list if needed, just didn't expect this error to come from it.
Related
I built a small survey application which randomly assigns participants to one of 9 paths by randomly selecting the last part of the URL and appending it onto a button link. I then use e.g. {% if 'surveyone' in request.path %} etc. in my template tags to display the right content to the user.
This works fine on my local machine but I have since discovered Multi-threaded processing and using constant lists such as the below SURVEY_URLS has caused issues when the project is uploaded to the server. I want to instead store this in my database.
Question(s)
How do I add/store the below SURVEY_URLS list of strings in my MySQL database?
How do I remove particular URL strings from the same database? (as below)
The below is my existing code which has all the functionality I need and works fine on my machine. I just need to make it work correctly when dealing with multiple concurrent users.
Thanks
views.py
SURVEY_URLS = ['/surveyone/', '/surveytwo/', '/surveythree/', '/surveyfour/', '/surveyfive/', '/surveysix/', '/surveyseven/', '/surveyeight/', '/surveynine/']
def begin(request):
total_path_counter = TotalCounter.objects.get_or_create(total_max_counter__gte=0)[0]
if total_path_counter.total_max_counter < 100:
survey_url = random.choice(SURVEY_URLS)
if survey_url == '/surveyone/':
survey_path_counter = SurveyCounter.objects.get_or_create(survey_wizard_type = 'survey_wizard_one')[0]
if survey_path_counter.survey_wizard_count > 9:
SURVEY_URLS.remove('/surveyone/')
elif survey_url == '/surveytwo/':
survey_path_counter = SurveyCounter.objects.get_or_create(survey_wizard_type = 'survey_wizard_two')[0]
if survey_path_counter.survey_wizard_count > 9:
SURVEY_URLS.remove('/surveytwo/')
....
....
elif survey_url == '/surveynine/':
survey_path_counter = SurveyCounter.objects.get_or_create(survey_wizard_type = 'survey_wizard_nine')[0]
if survey_path_counter.survey_wizard_count > 9:
SURVEY_URLS.remove('/surveynine/')
return render(request, 'Begin.html', {'survey_url': survey_url})
else:
return render(request, 'surveyfull.html')
Begin.html
<a class="btn btn-success" href="/experiment{{survey_url}}">Begin Instruction Tasks</a>
Well, I suppose you can make a new model something like this:
class Survey(model.Model):
name = models.Charfield(max_length=50) # surveyone goes here
...
than in the view you can pull the random like this:
survey_count = Survey.objects.all().count()
random_survey_index = random.randint(0, survey_count - 1)
get the instance name by random_survey_index and append it to your url
Not sure how effective this approach is, but should work.
Using django 1.7 and python 2.7, in a views I have:
page = 0
sex = [u'\u0632\u0646'] #sex = زن
url = "/result/%s/%d" % (sex, page)
return HttpResponseRedirect(url)
Which needs to return:
/result/زن/0
However the resulting url turns out to be:
/result/[u'\u0632\u0646']/0
Which is not what envisage in the pattern:
`url(r'^result/(?P<sex>\w+)/(?P<page>\d+)','userprofile.views.profile_search_result')`,
I also tried
return HttpResponseRedirect( iri_to_uri(url))
but does not solve the problem.
I got really confused and appreciate your help to fix this.
Since sex is a list, you simply need to use the actual element you want:
url = "/result/%s/%d" % (sex[0], page)
Although note that to construct URLs in Django, you should really use the reverse function:
from django.core.urlresolvers import reverse
...
url = reverse('userprofile.views.profile_search_result', kwargs={'sex': sex[0], 'page': page})
url should also be an unicode string for that to work:
page = 0
sex = u'\u0632\u0646' #sex=زن
url = u"/result/%s/%d" % (sex, page)
return HttpResponseRedirect(url)
I have two models Team, Player. Player has a foriegn-key to teams.
Now i want to have a view and have defined my urls.py like this
url(r'^team/(?P<team_id>)/player/(?P<player_id>)/$', 'djangocricket.Cricket.views.player'),
if i define my view like
def player(request, team_id, player_id):
template = get_template('player.html')
loggedinuser = request.user
team = Team.objects.get(id=team_id)
player = Player.objects.get(id=player_id)
page_vars = Context({
'loggedinuser': loggedinuser,
'team': team,
'player': player,
})
output = template.render(page_vars)
return HttpResponse(output)
it gives me this error.
url() takes at least 2 arguments (1 given)
help is much appreciated.
//mouse
The problem is in your urls.py statement. You need to add the view to call when this url is requested. url requires these two arguments.
url(r'^team/(<team_id>\w+)/player/(<player_id>\w+)', 'views.player'),
Also, as Béres Botond noted, I also thought the patterns looked incorrect. As he stated, add ?P to the beginning of each pattern, just inside the parentheses.
In your url conf you also need to tell it what view that pattern points to. Furthermore the parameters in your pattern are not correctly defined. Should be something like this:
url(r'^team/(?P<team_id>\w+)/player/(?P<player_id>\w+)/$', 'myproject.myapp.views.player'),
For more details check out the urlconf docs: https://docs.djangoproject.com/en/1.3/topics/http/urls/
Here is my url :
url(r'^test/$|test/(\d+)', views.test_page)
So with the django runserver fired I can enter 127.0.0.1:8000/test/ or
the same url followed with a "page" number.
Here is a simplified version of my view :
def test_page(request, pagenumber):
paginator = Paginator(Test.objects.all(), 5)
page = 1
if pagenumber:
page = pagenumber
posts = paginator.page(page)
That works but is kinda inefficient. So I modified it to :
def test_page(request, page=1):
paginator = Paginator(Test.objects.all(), 5)
posts = paginator.page(page)
Which is nicer, works when I specify a page number in the url but when
I just enter 127.0.0.1:8000/test/ it doesn't. I got a :
Exception Type: TypeError
Exception Value: int() argument must be a string or a number,
not 'NoneType'
Exception Location: /usr/lib/python2.7/site-packages/django/core/
paginator.py in validate_number, line 23
why doesn't the attribute page take the default value 1 when I don't
specify any page number ?
For things like page numbers, it's better to use GET parameters, ie the form /test/?page=1. You do this directly in the view via request.GET.get('page'), so the urlconf is just r'^test/$.
Do a check to see if the function parameter page is None in the code. If it is set the value to be 1. Instead of relying on the function to default it.
I have never seen a url entry written that way.
Could you try something like:
To pass a named argument I think you have to specify that arguments name in your urls.py , it doesn't look like you're doing that now.
(?P<page>\d+)/$ this is the way django recommends to pass defualt arguments. https://docs.djangoproject.com/en/dev/topics/http/urls/#notes-on-capturing-text-in-urls
I would try this:
def test_page(request, **kwargs):
page = kwargs.get('pagenumber', 1)
paginator = Paginator(Test.objects.all(), 5)
posts = paginator.page(page)
No shell around so I couldn't test this code.
Please do not try to assign a default value to the argument "page" which you are passing in the function call. Just keep it as:
def test_page(request, page):
Please do try it, and write the url as:
url(r'^test/(?P<page>\d+)/$', views.test_page)
I'm trying to figure out how to show something like "Showing 1-10 of 52" using django pagination in my templates.
I accomplished the pagination itself but nothing comes to my mind about this requirement.
Any ideas?
As the documentation shows, Paginator objects have a count attribute which shows the total number of objects across all pages (in the queryset or list they're paginating) and Page objects have start_index() and end_index() methods.
So, assuming you pass the page to the template context:
Showing {{ page.start_index }}-{{ page.end_index }} of {{ page.paginator.count }}
You'll need to do something moderately more complex behind the scenes. And please note that while I am a python dev, i've been using werkzeug and jinja2 for a long time now and so my django syntax is a little rusty. Also this was dry-coded (as in I just typed it here in the browser) and should be tested to make sure that it works as intended.
Generally I'll create a pagination object, and pass it in a query object that isn't filtered by pages, you can also tell it how many per page and what page you're on.
So something vaguely similar to:
Paginator(query, objects_per_page, current_page_number)
And then pass the resulting paginator object into the template.
Inside the paginator's init you'd want to do something similar to:
def __init__(self, query, objects_per_page, current_page_number):
self.total = query.count()
self.per_page = objects_per_page
self.current_page_number = current_page_number
self.lower_limit = objects_per_page * current_page_number
self.upper_limit = objects_per_page * (current_page_number + 1)
if self.upper_limit > self.total:
self.upper_limit = self.total
self.objects = query[self.lower_limit - 1:self.upper_limit - 1]
Then in the template you'd do something like
Showing {{paginator.lower_limit}}-{{paginator.upper_limit}} of {{paginator.total}}
And later when you are ready to iterate over the objects you could just iterate over paginator.objects.
I hope that gives you a general idea of how you can cleanly do this.
The django Paginator object has a num_pages property. In your view, you can just pass the correct data to your template and show it there.
So as an (rough) example:
view
current_page = ## input param
items_per_page = 10
paginator = Paginator(result, items_per_page)
...
return render_to_response('template.html',
{
'num_pages': paginator.num_pages,
'start_count': items_per_page * current_page + 1,
'end_count': (items_per_page * current_page + 1) + len(paginator(current_page).object_list)
'items_per_page': items_per_page
}
template
showing {{start_count} - {{end_count}} of {{num_pages}}
(I wrote this code without the benefit of a compiler, so test it)
paginator = Paginator(query, settings.SEARCH_DATA_PER_PAGE)
For number of Pages :
num_of_pages = paginator.num_pages
For total number of items across all pages :
num_of_objects = paginator.count
You can calculate number of items per page from this data.
totalPages = math.ceil(float(totalRecords)/recordsPerPage)
or
paginatorInstance.num_pages # this is there by default
Wasn't that hard, was it?