I'm pretty new to django and i'm working on a website that needs a dynamic URL for a database table, and it all works fine, but i would like to know how to remove the "?id=" from the url, so rather than
localhost:8000/dynamicurl/?id=XXXXX
The url becomes
localhost:8000/dynamicurl/XXXXX
Instead
I did a fine amount of searching in the documentation and didn't find a lot, though it's pretty likely i missed something.
EDIT:
thanks everyone for helping, the simplest answer was to remove the object i was using to fetch the ID and just replace it for ID in evert instance,
so my url became
url(r'^dynamicurl/(?P[0-9]+)/$', views.dynamicurl)
and my view became
def dynamicurl(request, id):
i'm like very very new to django FYI
you can capture a variable in url definition in the apps urls.py file. It would look something like this:
url(r'^dynamicurl/(?P<id>[0-9]+)?$', dynamicurl, name = 'dynamicurl'),
then in your view function you receive that parameter:
def dynamicurl(request, id):
If you are talking about how to change your url inside the urls, I suggest you to use code that already answered above: https://stackoverflow.com/a/41988051/6396981
But, if you talking about how to redirect localhost:8000/dynamicurl/?id=XXXXX to localhost:8000/dynamicurl/XXXXX, hope this usefull..
1. views.py
from django.http import HttpResponse
from django.views.generic.base import RedirectView
from django.core.urlresolvers import reverse
class RedirectView(RedirectView):
permanent = False
def get_redirect_url(self):
get_id = self.request.GET.get('id')
if get_id is not None:
return reverse('redirected_page', kwargs={'id': id})
return reverse('origin_page')
def redirected_view(request, id):
# your final view goes here...
return HttpResponse("You're looking for id: %d." % id)
2. urls.py
from django.conf.urls import url
from yourapp.views import views (RedirectView, redirected_view)
urlpatterns = [
# first view the pool to doing redirection
url(r'^pool/$', RedirectView.as_view(), name='origin_page'),
# the final url
url(r'^pool/(?P<id>[\d]+)/$', redirected_view, name='redirected_page'),
]
Related
There is a class in admin.py:
class NewsAdmin(TranslationAdmin):
form = NewsForm
list_display = ('title', 'date' 'show_url')
def show_url(self, obj):
return format_html("<a href='http://www.host.ru/news/{url}' target='_blank'>view</a>", url=obj.id)
show_url.short_description = "View"
Need a link http://www.host.ru replace with a relative one, something like this: protocol + domain name + news/{url}
How can this be done?
I think you are better off making it hardcoded value in your settings, like BASEURL = 'http://www.host.ru'
then having different settings.py for production and development (dev with BASEURL = 'https://localhost:8080' for testing)
and then you can fetch it with:
def show_url(self, obj):
from django.conf import settings
return format_html("<a href='{base}/news/{url}' target='_blank'>view</a>", base=settings.BASEURL, url=obj.id)
# or use reverse so it's dynamically linked to your urls.py (this is what I do)
def show_url_with_reverse(self, obj):
from django.conf import settings
from django.urls import reverse
return format_html("<a href='{base}{url}' target='_blank'>view</a>",
base=settings.BASEURL,
url=reverse('myviewname', args=[obj.id])
)
This isn't the answer you wanted, but I'm throwing it in as a way. I hope someone smarter than me has found a better way, but this is a fallback.
Reasoning
This is all moot because you don't have access to the request object inside that method.
I've found that you need the request object to dynamically get the host, the www.host.ru part, with request.get_host().
But that still leads the http:// and https://, which is not available anywhere (that I've found), so I have that hardcoded in my settings.py.
So either way something will have have to be hardcoded, so might as well be the entire url. It's gross, I hate it, but w/e it gets the job done
Hello! Please tell me how to organize a redirect correctly.
There is an old version of the site and a new one. In the old version (another CMS, not Django) the objects have their own URL, in the new revised scheme, and the objects have a different URL.
In each object on the new site, there is a completed field with the old URL. In model.py it looks like this:
old_url = models.CharField('Old URL', blank=True, max_length=100)
I specifically moved the old url to a separate field. Or was it not necessary to do this?
Question. How to set up a redirect correctly, so that after going to the object using the old URL, the site visitor will be redirected to the new URL of this object?
IMHO, I don't think writting old_url for each and every object is pretty inefficient. Instead you can implement a custom 404 view, and handle the redirection there.
I think you can create some regex or plain url maps to new url and redirect accordingly.
import re
from django.http import HttpResponseNotFound
OLD_URL_MAP = { 'old_url_regex': 'new_url_path'}
def handler404(self, request):
for old_re, new_url in OLD_URL_MAP.items():
if re.match(old_re, request.path):
return redirect(new_url, request.resolver_match.kwargs)
return HttpResponseNotFound('not found')
# inside urls.py
handler404 = 'myapp.views.handler404'
Here I have used a map hard coded in python, you can create a model for that as well.
Update
A costly solution is to use middleware. You can try like this:
import re
from django.urls import resolve
OLD_URL_MAP = { 'old_url_regex': 'new_url_path'}
class RerouteMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
try:
resolve(request.path_info) # trying to find if the current url exists in your django project. if not, it will throw exception.
except:
for old_re, new_url in OLD_URL_MAP.items(): # iterating through urls
if re.match(old_re, request.path):
return redirect(new_url, request.resolver_match.kwargs)
response = self.get_response(request)
return response
And add that middleware at the bottom of MIDDLEWARE settings.
FYI, its a regex based solution, assuming those urls are dynamic. Instead you can use plain text urls, but its up to you.
Use redirect() from django.shortcuts [the same library from where you import render]. Also, assuming, that the old_url contains only the relative url.
from django.shortcuts import render, redirect
def someView(request):
q = ~some queryset returning the current object~
current_url = request.get_full_path().strip("http://www.example.com/")
if q.old_url == current_url:
redirect(q.new_url)
else:
pass
Remember, redirect() returns an HttpResponse.
I'm new to django (1.5.1) and got a bit stuk with HttpResponseRedirect.
If I understand right that needs a static string, and when you want it to dynamic redirect, you get a reverse() or a get_absolute_url()
I think I get the part of the get_absolute_url, but I'm stuck on redirecting to the following url (first is mysite.urls.py second is my characters.view.py
url(r'^users/', include('characters.urls')),
url(r'^(?P<user_id>\d+)/characters/$', views.user_characters, name='user_characters'),
from this view:
if new_char_form.is_valid():
#save form with commit=False
new_char_obj = new_char_form.save(commit=False)
#set user and save
new_char_obj.user = user
new_char_obj.save()
return HttpResponseRedirect('%s/characters/' % user.id)
So I know I can't use the HttpResponseRedirect that way, and since I can't include a get_absolute_url function in the user model, I found the next option.
Include this in my settings
ABSOLUTE_URL_OVERRIDES = {
'auth.users': lambda o: "/users/%s/" % o.id,
}
but then I have no clue how to call for that.
Can someone please give me help (sort of stuck on this for some time)
With kind regards
Hans
The easiest way to redirect to the user_characters view is to use the redirect shortcut.
from django.shortcuts import redirect
# in the view
return redirect('user_characters', user.id)
This is equivalent to using HttpResponseRedirect and reverse
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
# in the view
return HttpResponseRedirect(reverse('user_characters', args=[user.id]))
If you want to use ABSOLUTE_URL_OVERRIDES to override the get_absolute_url method for the User model, you have to make sure that the url matches the format of your view named user_characters.
ABSOLUTE_URL_OVERRIDES = {
'auth.users': lambda o: "/users/%s/characters/" % o.id,
}
You would then be able to call user.get_absolute_url() in your views, and do
return HttpResponseRedirect(user.get_absolute_url())
Or, since the redirect shortcut allows you to pass a model instance:
return redirect(user)
So, kind of a in a weird situation here. I've got a Django project using TastyPie to power its API and some views/templates that will be used to power plugins for various sites. Rather than building this plugins as standard Django templates, I've been asked to use our API to process requests to the plugins, which means I'm calling a view on my server from another view, and for some reason that isn't working with any of my views. For reference:
#views.py
from django.http import HttpResponse
from django.shortcuts import render_to_response
from django.template.context import Context, RequestContext
import json, urllib, urllib2
SITE_NAME = "http://localhost:8000/"
API_PATH = "api/v1/"
def aggregate(request):
template = 'lemonwise/plugins/aggregate.html'
sku = request.GET.get('sku')
url = ''.join([SITE_NAME, API_PATH, 'product/?sku=', sku])
product = json.loads(urllib.urlopen(url).read())['objects'][0]
return render_to_response(template, product)
def reviews(request):
template = 'lemonwise/plugins/reviews.html'
sku = request.GET.get('sku')
url = ''.join([SITE_NAME, API_PATH, 'product/?format=json&sku=', sku])
#Comment the next line out and the url is passed correctly
response = urllib2.build_opener().open(url).read()
return HttpResponse(url)
#page = opener.open(url).read()
#return HttpResponse(url)
#product = json.loads(urllib2.build_opener().open(url).read())['objects'][0]
#return HttpResponse(url)
#reviews = [json.loads(urllib.urlopen(SITE_NAME + uri)) for uri in product['reviews']]
#return render_to_response(template, {'reviews': reviews})
def survey(request):
template = 'lemonwise/plugins/survey.html'
sku = request.GET.get('sku')
url = ''.join([SITE_NAME, API_PATH, 'product/?sku=', sku])
product = json.loads(urllib2.build_opener().open(url).read())['objects'][0]
return render_to_response(template, product)
def mosthelpfulpositive(request):
template = 'lemonwise/plugins/mosthelpfulpositive.html'
sku = request.GET.get('sku')
url = ''.join([SITE_NAME, API_PATH, 'product/?sku=', sku])
product = json.loads(urllib2.build_opener().open(url).read())['objects'][0]
uri = product['most_helpful_positive']
most_helpful_positive = json.loads(urllib.urlopen(SITE_NAME + uri))
return render_to_response(template, most_helpful_positive)
def mosthelpfulnegative(request):
template = 'lemonwise/plugins/mosthelpfulnegative.html'
sku = request.GET.get('sku')
url = ''.join([SITE_NAME, API_PATH, 'product/?sku=', sku])
product = json.loads(urllib2.build_opener().open(url).read())['objects'][0]
uri = product['most_helpful_negative']
most_helpful_negative = json.loads(urllib.urlopen(SITE_NAME + uri))
return render_to_response(template, most_helpful_negative)
And the corresponding urls.py (in a different app):
#urls.py
from django.conf import settings
from django.conf.urls.defaults import patterns, include, url
from django.contrib import admin
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from tastypie.api import Api
from lemonwise.reviews.api import *
admin.autodiscover()
v1_api = Api(api_name='v1')
v1_api.register(UserResource())
v1_api.register(MerchantResource())
v1_api.register(ProductFamilyResource())
v1_api.register(ProductResource())
v1_api.register(BooleanAttributeResource())
v1_api.register(SlideAttributeResource())
v1_api.register(ProductAttributeResource())
v1_api.register(SubmissionResource())
v1_api.register(ReviewResource())
v1_api.register(ReviewProductAttributeResource())
v1_api.register(CommentResource())
v1_api.register(BestUseResource())
v1_api.register(HelpfulVoteResource())
#Acess the api via http://127.0.0.1:8000/api/v1/user/?format=json
urlpatterns = patterns('',
url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
url(r'^admin/', include(admin.site.urls)),
# Lemonwise apps
url(r'^reviews/', include('lemonwise.reviews.urls')),
#API
url(r'^api/', include(v1_api.urls)),
)
if settings.DEBUG:
urlpatterns += staticfiles_urlpatterns()
Any idea on how to fix this? I can't find any writings on the subject.
EDIT: More specifically, what's happening is that when I load any of these views they hang trying to read the api page. ALso, my server shows no indications of any requests being processed. (Though I can load the api pages directly.)
Now your comment has clarified the situation, I can take a guess at what the problem is. It is that you are using the built-in development server, which is single-threaded. So while it's processing the original request, it's not able to process the internal request for another URL - so it hangs indefinitely.
The solution, as Mao points out, is to think of a better architecture. If you can't do that, you may have some luck with using something like gunicorn instead of the built-in server.
Particular to Tastypie you can use your Resources in views, if you need to, accessing the objects directly and calling the get methods and building the bundle.
You can find out how: http://django-tastypie.readthedocs.org/en/latest/cookbook.html
Go to the section titled - Using Your Resource In Regular Views
Agreed, your development server likely only has one instance. Launch another one on a different port. ie/
SITE_NAME = "http://localhost:8001/"
Okay, so I already said that having views making HTTPRequests against other views is kind of silly, but I do see what your problem currently is. You are calling json.loads(urllib.urlopen(SITE_NAME + uri)), but urllib.urlopen returns a file-like object, not a string, so it should actually be json.load(urllib.urlopen(SITE_NAME + uri)).
I just encountered the same problem i.e. Calling an API from the same server it is hosted. As Daniel suggested, I was able to solve this by using multi threads in gunicorn:
gunicorn --certfile=crt --keyfile=key --bind 0.0.0.0:8000 app.wsgi --threads 5
I've found very odd thing about using reverse in Django 1.2.1.
I have:
myapp/
views.py
urls.py
in urls.py
from django.conf.urls.defaults import *
urlpatterns = patterns('myapp.views',
url(r'^$', 'browse'),
)
in views.py
from django.shortcuts import render_to_response
from django.core.urlresolvers import reverse
print reverse('myapp.views.browse') # <----- this will print correct value
def browse (request):
print reverse('myapp.views.browse') # <----- this fails with exception
return render_to_response('myapp/browse.html')
When I put reverse method anywhere outside the view method (browse - in this case) I get an exception in every further use of reverse or {% url %} tag.
NoReverseMatch at /
Reverse for 'myapp.views.browse' with arguments '()'
and keyword arguments '{}' not found.
WTF? When I comment/delete the print line outside browse() , second print line inside browse() magically start working!
The most basic case is:
class MyForm(forms.Form):
field = forms.CharField(default=reverse(....))
def some_view(request):
print reverse(...)
....
1) I define a class in main-scope that is initialized when django initialize (and runs reverse)
2) When a request comes the some_view function has been triggered and it evaluates the reverse function again (and fails with exception).
I don't see anything bad at all in this approach. Why not to initialise some values in the django main-scope with results of the reverse() function ?
You will probably need to pass 'request' as the second parameter when calling reverse() from within the view function after it's already been called.
def browse(request):
print reverse('myapp.views.browse', args=[request])
This is odd behavior indeed, but this might possibly be a solution for now.
First, you should be naming your URLs in order to use reverse. That is the correct approach AFAIK.
Second, why are you calling reverse from within a FormField? I really don't get it.
Maybe you could enlighten us by posting the full code rather than a curated set of snippets.
# urls.py
url(r'^/$', 'home_view', name='home'),
url(r'^login/$', 'login_view', name='login'),
# views.py
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.http import HttpResponseRedirect
def login_view(request):
# do login stuff and redirect to home
return HttpResponseRedirect(reverse('home'))
def home(request):
# do home stuff
return render_to_response("home.html", locals(), context_instance=RequestContext(request))
The problem is caused by import hell in python. reverse depends on other things and cannot be used while initialization.
The solution is to use lazy reverse. E.g. using this:
http://djangosnippets.org/snippets/499/