3

There are two models: groups and posts. The post can be of one of two kinds: assigned to the group, and not assigned to the group. The foreign key field in posts model, which assigns the group to the post, is optional. The post, which belongs to a group, should have a different address than one, which does not belong to the group. Here is the general rule. The former address is when a post does not belong to any group and the latter one if it does.

.../posts/[year]/[month]/[day]/[slug of the post]/

.../groups/[name of the group]/posts/[year]/[month]/[day]/[slug of the post]/

The problem appears. After creating the post both url addresses work.

It is not a surprise, because I include the urls from posts app in urls.py in groups app.

What I want to do is to make the url addresses optional regarding to the group parameter (whether it is passed or not). It can work as something like:

  • if groups parameter is not None choose the url from groups.urls
  • if groups parameter is not None exclude url from posts.urls

Basically I want to choose just one url, not two.

Is it possible in Django to do it in a simple way? Or is the only solution creating two models/two apps instead of one?

Excerpt of my code:

groups/urls.py

app_name = 'groups'

urlpatterns = [
    ...
    path('<slug:slug>/posts/', include('posts.urls', namespace='grouppost')),
    ...
]

posts/urls.py

app_name = 'posts'

urlpatterns = [
    path('', views.PostList.as_view(), name='list'),
    path('create', views.CreatePost.as_view(), name='create'),
    path('<int:year>/<int:month>/<int:day>/<slug:slug>/', views.PostDetail.as_view(), name='detail'),
    path('<int:year>/<int:month>/<int:day>/<slug:slug>/update/', views.UpdatePost.as_view(), name='update'),
    path('<int:year>/<int:month>/<int:day>/<slug:slug>/delete/', views.DeletePost.as_view(), name='delete'),
]

I am using Django 2.0.7.

Update 16.08

I also include the path in mu root urls.py. Sorry for the omission of this important information.

urls.py

urlpatterns = [
    ...
    path('groups/', include('groups.urls')),
    path('posts/', include('posts.urls')),
    ...
] 
Jakub Siwiec
  • 428
  • 4
  • 13
  • What invokes the urls? An Ajax call? A view? – Matt Cremeens Aug 15 '18 at 15:44
  • Why do you add posts urls to groups instead of your root urls.py? What do you mean by optional? In your view or in the template? – schrodingerscatcuriosity Aug 15 '18 at 19:18
  • A view invokes urls. I also have `include` `posts` in the `path` in my root `urls.py`. That is why the first url address from the list in my question also works. I want it optional in my view. What I want is that if `group` foreign key in post model is not `None`, the first url address would be deactivated and if `group` foreign key in post model is `None` then that the second url address from the list would not work. – Jakub Siwiec Aug 16 '18 at 06:35
  • I am going to add that if the `group` foreign key is `None` then the address `/groups/None/posts/[year]/[month]/[day]/[slug of the post]/` works... It should not be like this, even if I can handle in the templates that nobody will enter that address... – Jakub Siwiec Aug 16 '18 at 07:12

1 Answers1

1

You should try to avoid logic in urls. That's what views or business logic in even lower levels are for. Instead, you could create a view that acts as a redirection page that takes the parameter you want and, depending on what it is, redirects to the right url.

If you do that, you would need to keep track of any request arguments.

# url (located wherever you want):
(r'post-redirection/<string:posts_or_group>/<int:year>/<int:month>/<int:day>/<slug:slug>/', post_redirection, name="post_redirection")

# view:
def post_redirection(request, post_or_group, year, month, day, slug):
    if post_or_group == "post":
         post_url_name = "..." # This is the url that you want to go to if it is a request to .../posts/[year]/[month]/[day]/[slug of the post]/
         return HttpResponseRedirect(reverse(post_url_name, kwargs={"year": year, "month": month, "day": day, "slug": slug}))

    elif post_or_group == "groups":
         group_url_name = "..." # This is the url that you want to go to if it is a request to .../groups/[name of the group]/posts/[year]/[month]/[day]/[slug of the post]/
         return HttpResponseRedirect(reverse(group_url_name, kwargs={"year": year, "month": month, "day": day, "slug": slug}))

    else:
        # error. However you want to handle it. You could return an error response or do something else. Maybe return a message that says they didn't choose the right option.

The only issue you might run into is preserving request data (i.e request.POST or request.GET). You would still be able to use this methodology, you would just need to find a way to pass that data on in the new redirection request as that data only lasts for one single request.

Ian Kirkpatrick
  • 1,861
  • 14
  • 33