I am working on a project in Django and I'm facing an issue while redirecting from one page to another on the click of a link. No matter what all I've tried, I end up having a url like:
localhost:8080/page1/page2
instead of moving from localhost:8080/page1 to localhost:8080/page2
I've tried by using HttpResponseRedirect(url)
The recommended way is to use {% url 'url-name' arg1 arg2 kwarg='foo' %} in django template.
You shouldn't hardcode urls in your template but use url names.
More details: https://docs.djangoproject.com/en/1.9/ref/templates/builtins/#url
The equivalent in python code is django.utls.reverse which returns te absolute url or django.shortcuts.redirect which is equivalent to HttpResponseRedirect(reverse('url_name'))
https://docs.djangoproject.com/en/1.10/ref/urlresolvers/#django.urls.reverse
EDIT #1
Use database to pass items between views.
models.py
from django.db.models import Model
class Item(Model):
# your model fields
views.py
def list_view(request):
items = Item.objects.all()
context = {'items': items}
return render(request, 'list_template.html', context)
def details_view(request, item_id):
item = Item.objects.get(id=item_id)
context = {'item': item}
return render(request, 'details_template.html', context)
urls.py
urlpatterns = [
url(r'^/list/$', views.list_view, name='list')
url(r'^/details/(?P<item_id>[0-9]+)/$', views.details_view, name='details'),
]
list_template.html
<!-- your html -->
<ul>
{% for item in items %}
<li>
item number {{ item.id }}
</li>
{% endfor %}
</ul>
<!-- your html -->
{% url ... %} tag produces absolute url to pattern named "details" and substitute part of the address with function argument. In the addres, instead of (?P<item_id>[0-9]+), you'll have item id eg. /details/1/. When you click the link, number 1 is grabbed by regex and passed to the function argument where you can take your Item from the database.
Related
I have a database with blog style documents, i.e., author's name, publication date, body text, etc.
I have built a django framework to output entries from the database as a result of a search term. That part is ok. The problem is that I want to show sections of the body text with the matched search terms highlighted (equivalent to a google search result). This means that I can't create a template tag with the body_text attribute only, because that text is not highlighted. I already did a function that receives as input the query and the body text and outputs the same text with the found search terms in bold.
My problem now is how do I pass this result to the html template?
Using the tutorial from Django documentation suppose you have the following views.py:
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
context = {'latest_question_list': latest_question_list}
return render(request, 'polls/index.html', context)
and the correspondent template:
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li>{{ question.question_text }}</li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
Now suppose you have the function in views.py:
def signal_tokens(text,query_q):
...
return new_text
What should be the best way to replace the {{ question.question_text } with the output from signal_tokens? My solution was to replicate the context variable with a list of dictionaries, where each dictionary is a copy of each entry, except for the 'question_text' key, where I used signal_tokens result:
def index(request):
query_q = 'test'
latest_question_list = Question.objects.order_by('-pub_date')[:5]
new_context = []
for entry in latest_question_list:
temp_d = {}
temp_d['id'] = entry.id
temp_d['question_text'] = signal_tokens(entry.question_text,query_q)
new_context.append(temp_d)
context = {'latest_question_list': new_context}
return render(request, 'polls/index.html', context)
But the problem is that I need to copy all entries. Is there a more elegant way to solve this problem?
This is an ideal use case for a template filter. Move your highlight code to a file in the templatetags directory, register it as a filter, then you can call it from the template:
{{ question.question_text|highlight:query_q }}
Obviously you will need to pass query_q to the template context as well.
I want to use more than one forms in the same page from the same model.
Ok, lets take it easy.
I have Social modules that have 3 attributes (network, url and image) charfield.
I've added 4 values in Social database (Facebbok, Twitter, Youtube, Pinterest)
In the settings view (settings.html) i want to have all 4 forms (for Facebook, Twitter etc.) to edit them.
Something like that:
Facebook: text input (that contains the current facebook url)
Youtube: text input (that contains the current youtube url)
etc.
So when i go to settings.html i can change, update social url for all networks.
I have something like this for General Settings module (that have 3 fields, Title, Slug, Description and 1 attribute cuz the website have 1 title, 1 slug and 1 description). For this one is pretty simple i can use get_object_or_404 because Settings module have just 1 value and i can select it.. but the problem is Social Module have more values and i want to have on my page all forms from them so i can edit how ever i want.
views.py
def settings(request):
sidebar_items = Sidebar.objects.order_by('position')
social_items = Social.objects.order_by('network')
settings = get_object_or_404(Settings, pk = 1)
if request.method == "POST":
form_settings = SettingsForm(request.POST, instance = settings)
if form_settings.is_valid():
settings = form_settings.save(commit = False)
settings.save()
return HttpResponseRedirect('/dashboard/settings')
else:
form_settings = SettingsForm(instance = settings)
context = {'sidebar_items' : sidebar_items, 'form_settings' : form_settings, 'social_items' : social_items}
return render(request, 'dashboard/settings.html', context)
Django doesn't care how many forms you want to initialize in your view. If they're for the same model, you can use a formset. Otherwise, you can initialize and create objects however you want.
Example:
def your_view(request):
social_items = Social.objects.order_by('network')
forms = []
for index, social_item in enumerate(social_items):
forms.append(SocialForm(request.POST or None, instance=social_item,
prefix="form_{}".format(index)))
if request.method == 'POST':
for form in forms:
if form.is_valid():
form.save()
# do whatever next
return render(request, 'some-template.html', {'forms': forms})
You don't need three separate form tags in your template. You can submit all of the data in one post. Django will try to hydrate an instance of each model from the POST data, and return any errors if that fails.
In your template, you'll need to iterate over the form instances:
# some-template.html
<form action="." method="post" enctype="x-www-form-urlencoded">
{% for form in forms %}
<ol>
<li>
{{ form.network }}
{{ form.network.errors }}
</li>
<li>
{{ form.url }}
{{ form.url.errors }}
</li>
<li>
{{ form.image }}
{{ form.image.errors }}
</li>
</ol>
{% endfor %}
<button type="submit">Save</button>
</form>
I have a same template that is used for different urls (in this case: /create/ and /edit/[PK of an item] , named "create" and "edit" in the url.py).
I would like to show different things in my template depending if I'm on /edit/ or /create/.
How can I check this ?
{% if '/create' in request.path %} works, but I'd like to use a url tag (or equivalent, to not have it "hard coded").
What I would like to do looks like (in pseudo code - this doesn't work) {% if request.path in url create %} XXX {% endif %}.
Should I make all the necessary tests in the views.py, send a variable about it in the context, test on this variable in the template? In my case it seems a bit heavy for a simple url test ...
You can set a url with a as value.
{% url 'some-url-name' arg arg2 as the_url %}
{% if the_url in request.path %}
I'd say go for making two views if it's a significant difference (different form, etc.) - eliminates url logic in templates entirely, and no real 'test' needed either - don't have to check request.path/pass url/etc.
urls
urlpatterns = patterns('',
(r'^create/$', create),
(r'^edit$', edit),
)
views
def create(request):
text = "Create something"
return render_to_response('same-template.html', {'text': text}, context_instance=RequestContext(request)
def edit(request):
text = "Edit something"
return render_to_response('same-template.html', {'text': text}, context_instance=RequestContext(request)
template
{% text %}
Can also pass multiple changes easily with a list this way too:
views
def create(request):
data = []
data['text'] = "Create something"
data['form'] = CreateForm()
return render_to_response('same-template.html', {'data': data}, context_instance=RequestContext(request)
def edit(request):
data = []
data['text'] = "Edit something"
data['form'] = EditForm()
return render_to_response('same-template.html', {'data': data}, context_instance=RequestContext(request)
template
{% data.text %}
{% data.form %}
Either you do it in a view, or write a template tag.
Looking on django snippets, this one looks nice: http://djangosnippets.org/snippets/1531/
I am new to the Django web framework.
I have a template that displays the list of all objects. I have all the individual objects listed as a link (object title), clicking on which I want to redirect to another page that shows the object details for that particular object.
I am able to list the objects but not able to forward the object/object id to the next template to display the details.
views.py
def list(request):
listings = listing.objects.all()
return render_to_response('/../templates/listings.html',{'listings':listings})
def detail(request, id):
#listing = listing.objects.filter(owner__vinumber__exact=vinumber)
return render_to_response('/../templates/listing_detail.html')
and templates as:
list.html
{% for listing in object_list %}
<!--<li> {{ listing.title }} </li>-->
{{ listing.title}}<br>
{% endfor %}
detail.html
{{ id }}
The variables that you pass in the dictionary of render_to_response are the variables that end up in the template. So in detail, you need to add something like {'listing': MyModel.objects.get(id=vinumber)}, and then the template should say {{ listing.id }}. But hat'll crash if the ID doesn't exist, so it's better to use get_object_or_404.
Also, your template loops over object_list but the view passes in listings -- one of those must be different than what you said if it's currently working....
Also, you should be using the {% url %} tag and/or get_absolute_url on your models: rather than directly saying href="{{ listing.id }}", say something like href="{% url listing-details listing.id %}", where listing-details is the name of the view in urls.py. Better yet is to add a get_absolute_url function to your model with the permalink decorator; then you can just say href="{{ listing.get_absolute_url }}", which makes it easier to change your URL structure to look nicer or use some attribute other than the database id in it.
You should check the #permalink decorator. It enables you to give your models generated links based on your urls pattern and corresponding view_function.
For example:
# example model
class Example(models.Model):
name = models.CharField("Name", max_length=255, unique=True)
#more model fields here
#the permalink decorator with get_absolute_url function
#models.permalink
def get_absolute_url(self):
return ('example_view', (), {'example_name': self.name})
#example view
def example_view(request, name, template_name):
example = get_object_or_404(Example, name=name)
return render_to_response(template_name, locals(),
context_instance=RequestContext(request))
#example urls config
url(r'^(?P<name>[-\w]+)/$', 'example_view', {'template_name': 'example.html'}, 'example_view')
Now you can do in your templates something like this:
<a href={{ example.get_absolute_url }}>{{ example.name }}</a>
Hope this helps.
In your detail method, just pass the listing into your template like so:
def detail(request, id):
l = listing.objects.get(pk=id)
return render_to_response('/../templates/listing_detail.html', {'listing':l})
I'm trying to do pagination with the page parameter in the URL (instead of the GET parameter). I also want my pagination to be shared code across multiple different templates.
Given that, I think I need to do something like this :
urls.py:
url(r'^alias/page;(?P<page>[0-9]+)/(?P<id>.*)$', alias.get, name="alias"),
tempaltes/alias.html:
<div>...stuff...</div>
{% include "paginator.html" %}
templates/paginator.html :
{% if page_obj.has_previous or page_obj.has_next %}
{% load filters %}
<div class="pagination clear">
{% if page_obj.has_previous %}
‹‹ previous
...
What is somemagic?
Assume I want to keep my url the same except set the page page_obj.previous_page_number
Edit:
You need somemagic to be a variable with the name of the current view.
Try this:
{% with request.path_info|resolve_url_name as current_view %}
{% url current_view page_obj.previous_page_number object.id %}
{% endwith %}
You can get this working with some code from django-snippets:
Variable resolving URL template tag Makes the {% url %} tag resolve variables from context.
Resolve URLs to view name The function resolve_to_name(path) returns the view name for path. You just need to create a filter that uses this function.
This solution wont work with urls like:
'alias/param1_regexp/param2_regexp/page;(?P<page>[0-9]+)/(?P<id>.*)$'
because you've no clue about param1 and param2.
A modification can be done to the django-snippets above to make this kind of urls work:
First snippet modifications:
from django.template import defaulttags, VariableDoesNotExist, Variable
class ResolvingURLNode(defaulttags.URLNode):
def render(self, context):
original_view_name = self.view_name
try:
resolved = Variable(self.view_name).resolve(context)
if len(resolved) > 1:
self.view_name = resolved[0]
if resolved[1]:
self.args = [Variable(arg) for arg in resolved[1]]
elif len(resolved) > 0:
self.view_name = resolved[0]
else:
self.view_name = resolved
except VariableDoesNotExist:
pass
ret = super(defaulttags.URLNode, self).render(context)
# restore view_name in case this node is reused (e.g in a loop) in
# which case the variable might resolve to something else in the next iteration)
self.view_name = original_view_name
return ret
defaulttags.URLNode = ResolvingURLNode
Second snippet modifications
from django.core.urlresolvers import RegexURLResolver, RegexURLPattern, Resolver404, get_resolver
__all__ = ('resolve_to_name',)
def _pattern_resolve_to_name(self, path):
match = self.regex.search(path)
if match:
name = ""
if self.name:
name = self.name
elif hasattr(self, '_callback_str'):
name = self._callback_str
else:
name = "%s.%s" % (self.callback.__module__, self.callback.func_name)
if len(match.groups()) > 0:
groups = match.groups()
else:
groups = None
return name, groups
def _resolver_resolve_to_name(self, path):
tried = []
match = self.regex.search(path)
if match:
new_path = path[match.end():]
for pattern in self.url_patterns:
try:
resolved = pattern.resolve_to_name(new_path)
if resolved:
name, groups = resolved
else:
name = None
except Resolver404, e:
tried.extend([(pattern.regex.pattern + ' ' + t) for t in e.args[0 ['tried']])
else:
if name:
return name, groups
tried.append(pattern.regex.pattern)
raise Resolver404, {'tried': tried, 'path': new_path}
# here goes monkeypatching
RegexURLPattern.resolve_to_name = _pattern_resolve_to_name
RegexURLResolver.resolve_to_name = _resolver_resolve_to_name
def resolve_to_name(path, urlconf=None):
return get_resolver(urlconf).resolve_to_name(path)
Basically, resolve_to_name returns the name of the view and it's parameters as a tuple, and the new {% url myvar %} takes this tuple and uses it to reverse the path with the view name and it's parameters.
If you don't like the filter approach it can also be done with a custom middleware.
Previous answer
You should check django-pagination, it's a really nice django application, easy tu use and gets the job done.
With django pagination the code to paginate an iterable would be:
{% load pagination_tags %}
{% autopaginate myiterable 10 %} <!-- 10 elements per page -->
{% for item in myiterable %}
RENDERING CONTENT
{% endfor %}
{% paginate %} <!-- this renders the links to navigate through the pages -->
myiterable can be anything that is iterable:list, tuple, queryset, etc
The project page at googlecode:
http://code.google.com/p/django-pagination/
It will be something like the following. Except I don't know what you mean by id so I just put a generic object id. The syntax for url is {% url view_name param1 param2 ... %}
{% url alias page_obj.previous_page_number object.id %}
Updated base on your need:
{% url alias page_obj.previous_page_number object.id as prev_url %}
{% include "paginator.html" %}
...
{% if page_obj.has_previous %}
‹‹ previous