2010-11-22 4 views
4

Я пытаюсь создать приложение URL-alias, которое позволяет пользователю создавать псевдонимы для существующего url на своем веб-сайте.Django: создание/изменение объекта запроса

Я пытаюсь сделать это с помощью промежуточного слоя, где request.META['PATH_INFO'] проверяются с записями базы данных псевдонимов:

try: 
    src: request.META['PATH_INFO'] 
    alias = Alias.objects.get(src=src) 
    view = get_view_for_this_path(request) 

    return view(request) 
except Alias.DoesNotExist: 
    pass 

return None 

Однако, для этого, чтобы работать правильно это жизненная важность, что (по крайней мере) PATH_INFO изменяется на путь назначения.

Теперь есть некоторые фрагменты, которые позволяют разработчику создавать объекты запроса тестирования (http://djangosnippets.org/snippets/963/, http://djangosnippets.org/snippets/2231/), но они заявляют, что они предназначены для целей тестирования.

Конечно, это может быть так, что эти фрагменты подходят для использования в живой среде, но мои знания о обработке запросов Django слишком неразвиты, чтобы оценить это.

+1

переадресовывает лучше не только потому, что они делают это легче поддерживать код, но и - они позволяют иметь уникальный URL для каждой страницы. Это, вероятно, лучше для вашего рейтинга поиска. – Evgeny

+0

Можно ли это обойти, блокируя роботов от прямого доступа к псевдониму? –

ответ

4

Вместо подхода, который вы принимаете, рассмотрели ли вы приложение Redirects?

Это не невидимо псевдоним пути/Foo/вернуть строку вида(), но он будет перенаправлять/Foo/к/бар/

+0

Спасибо за предложение stevejalim. Однако невидимое сглаживание было именно тем, к чему я стремился. Что касается запроса, я ошибочно предположил, что объект запроса является неизменным (поскольку QueryDicts есть). Можно добавить en изменить атрибуты запроса, включая request.path, request.path_info и т. Д. Еще не проверял мой код экспирации, но опубликует результаты как ответ, когда закончите. –

+0

Рад, что вы нашли решение, которым вы довольны, Izz, но моя внутренняя проблема заключается в том, что в итоге вы получите больше боли, изменив путь объекта запроса, когда вы идете - не в последнюю очередь - в отладку/обслуживание. Можно ли просто установить новые пути для существующих URL-адресов Django (возможно, с новыми, настраиваемыми urlconfs для приложений Contrib, если необходимо?) –

1

(отправил в ответ, потому что комментарии, похоже, не будет поддерживать переносы строк или другая разметка)

Благодарим за консультацию. У меня такое же чувство относительно изменения атрибутов запроса. Должна быть причина, по которой в руководстве Django указано, что они должны считаться только для чтения.

Я пришел с этим: промежуточного

def process_request(self, request): 
    try: 
     obj = A.objects.get(src=request.path_info.rstrip('/')) #The alias record. 
     view, args, kwargs = resolve_to_func(obj.dst + '/') #Modified http://djangosnippets.org/snippets/2262/ 
     request.path = request.path.replace(request.path_info, obj.dst) 
     request.path_info = obj.dst 
     request.META['PATH_INFO'] = obj.dst 
     request.META['ROUTED_FROM'] = obj.src 
     request.is_routed = True 

     return view(request, *args, **kwargs) 
    except A.DoesNotExist: #No alias for this path 
     request.is_routed = False 
    except TypeError: #View does not exist. 
     pass 

    return None 

Но, принимая во внимание возражения против изменения атрибутов на запросы, не было бы лучшим решением, чтобы просто пропустить эту часть, и только добавить is_routed и ROUTED_TO (вместо того, чтобы направлять из них)?

Код, который опирается на исходный путь, затем может использовать этот ключ из META.

Выполнение этого с использованием URLConfs невозможно, так как это псевдонимы предназначено для того, чтобы конечный пользователь мог настроить собственные URL-адреса, исходя из предположения, что конечный пользователь не имеет доступа к кодовой базе или не знает, как писать его собственный URLConf.

Хотя можно было бы написать функцию, которая преобразует редактируемый пользователем файл (например, XML) в действительные URL-адреса Django, он считает, что использование записей базы данных позволяет более динамично генерировать псевдонимы (другие объекты, определяющие их собственные псевдонимы).

1

Извините, некро-пост, но я только что нашел эту тему, ища ответы. Мое решение кажется более простым. Может быть, а) Я в зависимости от новых возможностей django или б) у меня пропала ошибка.

Я столкнулся с этим, потому что есть бот с именем «Mediapartners-Google», который запрашивает страницы с параметрами url, которые все еще закодированы как от наивной царапины (или с двойным кодированием в зависимости от того, как вы на нее смотрите).У меня есть 404-й в моем журнале из него, которые выглядят как:

1.2.3.4 - - [12/Nov/2012:21:23:11 -0800] "GET /article/my-slug-name%3Fpage%3D2 HTTP/1.1" 1209 404 "-" "Mediapartners-Google 

Обычно я просто игнорировать сломанный бот, но это один я хочу успокоить, потому что он должен лучше нацеливать нашу рекламу (Это бот Google AdSense в) в результате чего получается лучший доход - если он может видеть наш контент. Ходят слухи, что он не следует переадресации, поэтому я хотел найти решение, подобное исходному Q. Я не хочу, чтобы обычные клиенты обращались к страницам с помощью этих сломанных URL-адресов, поэтому я обнаружил пользовательский агент. Другие приложения, вероятно, этого не сделают.

Я согласен, что перенаправление, как правило, будет правильным ответом.

Моего (? Полный) решение:

from django.http import QueryDict 
from django.core.urlresolvers import NoReverseMatch, resolve 

class MediapartnersPatch(object): 
    def process_request(self, request): 
     # short-circuit asap 
     if request.META['HTTP_USER_AGENT'] != 'Mediapartners-Google': 
      return None 

     idx = request.path.find('?') 
     if idx == -1: 
      return None 

     oldpath = request.path 
     newpath = oldpath[0:idx] 
     try: 
      url = resolve(newpath) 
     except NoReverseMatch: 
      return None 

     request.path = newpath 
     request.GET = QueryDict(oldpath[idx+1:]) 
     response = url.func(request, *url.args, **url.kwargs) 
     response['Link'] = '<%s>; rel="canonical"' % (oldpath,) 
     return response