Replacing default forms in django-postman via urlpatterns and views - django

django-postman docs say that you can replace the default forms in views with this:
urlpatterns = patterns('postman.views',
# ...
url(r'^write/(?:(?P<recipients>[^/#]+)/)?$',
WriteView.as_view(form_classes=(MyCustomWriteForm, MyCustomAnonymousWriteForm)),
)
But what is patterns? Where do I import that from, and where would this code go? In the project's urls.py?
My project level urls.py currently includes django-postman, as recommended in the docs, like this:
urlpatterns = [
...
url("r'messages/', include('postman.urls', namespace='postman'),
]
So the custom url pattern should be overwriting the default that will already be included in urls.py.

Yes, this is a code for urls.py. However, it's quite outdated.
The modern version would look like:
from django.urls import re_path
urlpatterns = [
re_path(r'^write/(?:(?P<recipients>[^/#]+)/)?$',
WriteView.as_view(form_classes=(MyCustomWriteForm, MyCustomAnonymousWriteForm)),
]
Edit
I guess you're including postman urls in your root urls.py, then you can do something like this to overwrite one of them:
urlpatterns = [
...
re_path(r'^messages/write/(?:(?P<recipients>[^/#]+)/)?$',
WriteView.as_view(form_classes=(MyCustomWriteForm, MyCustomAnonymousWriteForm)),
path('messages/', include('postman.urls')),
]

Related

How to write a urls.py in django so that I can do something like */page

Here is the problem:
I have an app with the following models: project, position, outreach
A position is connected to a project and project only with a Foreign key
An outreach is connected to a position and a position only with a Foreign key
I can create a new project from almost anywhere in my app (same for the other objects). Currently I wrote that a new project is created from the url dashboard/newjobproject but I would to make it so that depending on the page that I am, the url simply becomes something like www.myapp.com/..../newproject
What's a way to write the urls.py to achieve that?
from django.urls import path
from action import views
app_name = 'action'
urlpatterns = [
# ex: /action/
path('', views.login, name='login'),
path('dashboard/', views.dashboard, name='dashboard'),
path('contacts/', views.contacts, name='contacts'),
path('projects/', views.project, name='project'),
path('contacts/newcontact', views.new_contact, name='new_contact'),
path('projects/newjobproject', views.new_outreach, name='new_outreach'),
path('dashboard/newjobproject', views.new_jobproject, name='new_jobproject'),
path('projects/<uuid>/newjobposition', views.new_jobposition, name='new_jobposition'),
]
However,
Try adding this to the bottom of urlpatterns:
path('<path:p>/newjobproject', views.new_jobproject, name='whatever-name-you-want'),
and in your views.py:
def new_jobproject(request, p):
Tbh though, this is sort of a hacky way to do it. It'll break in a few locations. If you have a main urlpatterns array in which you're including the urls for this 'action' app as APIs, this solution won't work outside the API urls.
For eg. if you have:
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include('action.urls')),
]
And you access your url like this -> www.myapp.com/api/v1/....../newjobproject, then the code will work. If you try to access www.myapp.com/..../newjobproject or www.myapp.com/admin/..../newjobproject then the code will break and it will not match any of the paths. I'm not sure how you'd get it to work in that case.
If the above scenario is not an issue, if you're not going to be using these views as APIs, and your urlpatterns looks something like this:
urlpatterns = [
path('admin', admin.site.urls),
path('/', include('action.urls')),
]
then the code should work for all urls except for the admin/.../newjobproject case.

Building URL from name

I've got a url of 'accounts:produce_setup' (i.e. namespace/app is 'accounts' and name of url is 'product_setup'). I'd like to build the full url associated with this view and pass it as context into a template.
How would I go about doing this? Would I use build_absolute_uri()?
Thanks!
you should include your app in project_name/urls.py and bind your application to special URL pattern like this:
from account.urls import urlpatterns as account_urlpatterns
urlpatterns = [
url(r'^account/', include(account_urlpatterns, namespace='account')),
url(r'^admin/', admin.site.urls),
]
and after this in your account/urls.py you can implement your urlpatterns and set your special name for each url like this:
from django.conf.urls import url
from .views import produce_setup_view
urlpatterns = [
url(r'^produce_setup/$', produce_setup_view, name='produce_setup')),
]
at the end now you can use them in your template and views or any python file in your django project like this:
.py in django project:
from django.urls import reverse
url_string = reverse('account:produce_setup')
print(url_string)
>>> '/account/produce_setup/'
in template:
Good Luck :)
Actually, you don't need to. You can simply use {% url "accounts:product_setup" %} in template. For more details check here. And if you want to build the url is views(maybe for other reasons) you can use reverse.

How to register DRF router url patterns in django 2

My DRF routers specify a namespace so that I can reverse my urls:
urls.py:
router = DefaultRouter()
router.register('widget/', MyWidgetViewSet, base_name='widgets')
urlpatterns =+ [
url(r'/path/to/API/', include(router.urls, namespace='widget-api'),
]
Which, when upgrading to django 2, gives:
django.core.exceptions.ImproperlyConfigured: Specifying a namespace in include() without providing an app_name is not supported. Set the app_name attribute in the included module, or pass a 2-tuple containing the list of patterns and app_name instead.
Django 2 now requires app_name if the namespace kwarg is specified when using include. What's the right way to specify app_name when the url patterns are constructed by a DRF url router? I don't think the documentation is up-to-date for django 2 on this subject.
You need to put app_name = 'x' in your application's url.py file. This is a little buried in the documentation:
https://docs.djangoproject.com/en/2.0/topics/http/urls/#id5
For example, if in /project/project/urls.py you have:
path('', include('app.urls', namespace='app'))
Then in the corresponding url file (in /project/app/urls.py) you need to specify the app_name parameter with:
app_name = 'app' #the weird code
urlpatterns = [
path('', views.index, name = 'index'), #this can be anything
]
It's just necessary to use '{basename}-list' in reverse function.
In your case, it's going to be: reverse('widgets-list')
You need to include the router.urls as a tuple and add the app name to the tuple instead of only include router.urls
According to your example you should try with something like:
router = DefaultRouter()
router.register('widget/', MyWidgetViewSet, base_name='widgets')
urlpatterns =+ [
url(r'/path/to/API/', include((router.urls, 'my_app_name'), namespace='widget-api'),
]
The recommended approach is
from django.conf.urls import url, include
from rest_framework import routers
router = routers.DefaultRouter()
router.register(r'widget/', MyWidgetViewSet)
urlpatterns = [
url(r'^path/to/API/', include('rest_framework.urls', namespace='widget-api'))
]
See http://www.tomchristie.com/rest-framework-2-docs/tutorial/quickstart#urls

Django url dispatcher uses strings to specify function, why?

The Django documentation shows examples like this:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
]
However, I have seen some code that looks like this:
from django.conf.urls import url
urlpatterns = [
url(r'^articles/2003/$', 'myapp.views.special_case_2003'),
]
Where special_case_2003 is the name of a function in myapp/views.py.
What is the difference between these two approaches?
urlpatterns = [
url(r'^articles/2003/$', 'myapp.views.special_case_2003'),
]
Code like this is out of date. Providing the view as a string like this is deprecated in Django 1.8, and does not work in Django 1.10+. In Django 1.10+, you must use the callable.

Django: international subroutes

It's written in official documentation here that i18n_patterns() is only allowed in your root URLconf.
This is a problem for me because I need those URLs working:
/en/products/
/fr/produits/
/sv/produkt/
/en/products/detail/[my product name]/
/en/produits/detail/[my product name]/
/sv/produkt/detalj/[my product name]/
/sv/produkt/detalj/[my product name]/
Heres my root urls.py:
urlpatterns += i18n_patterns(
url(_(r'^produits/detail/'),
include('produits.urls', namespace="produits")
),
url(_(r'^produits/'),
include('produits.urls', namespace="produits")
),
)
So, for the lastest translation works ok, but the first one doesn't. The translation is ok, but I want to transfer the last part ('detail/') to the app produits that should handle it transparently.
How do I do?
Here's how I've solved the problem. This is not a good solution but it's the only one working for now with Django 1.8.
I've removed my routes from my "produits" application, and added them to the main urls.py which means mixing application configuration with global configuration. I dont like it.
I've also added the name of the application before each route: produits_detail and produits_index. Thus I know the app those routes are for. Once again I dont like mixing "global setting" and specific settings, but it seems I have no choice. Anyway, few lines of code, and it works pretty well.
from django.contrib import admin
from django.conf.urls import include, url
from django.conf.urls.i18n import i18n_patterns
from django.utils.translation import ugettext_lazy as _
from produits import views as p_views
urlpatterns = [
url(r'^i18n/', include('django.conf.urls.i18n')),
url(r'^admin/', include(admin.site.urls)),
]
urlpatterns += i18n_patterns(
url(_(r'^produits/detail/(?P<slug>[a-zA-Z0-9-_]+)/$'),
p_views.DetailView.as_view(), name='produits_detail'),
url(_(r'^produits/'),
p_views.IndexView.as_view(), name='produits_index'),
)