Home > Blockchain >  Django bug report, different foreign key as URL parameter will cause detailed view not executing
Django bug report, different foreign key as URL parameter will cause detailed view not executing

Time:11-15

Edit3: the culprit is re_path, not foreign key

Original:

This bug is so subtle I couldn't really find a niche way to describe it, For example I have two apps, News and Blogs

In blogs.py model I have something like this:

class BlogType(models.Model):
    blog_type = CharField(max_length=20)
    def __str__(self):
        return self.blog_type

class Blogs(models.Model):
    title = models.CharField(max_length=20)
    blog_author = models.ForeignKey(User, on_delete=models.CASCADE)
    blog_type = models.ForeignKey(BlogType, on_delete=models.DO_NOTHING)

here a blog_type is a foreignkey defined inside the same models.py

In blogs url.py

from django.urls import path, re_path
from . import views
from .views import blogspage

urlpatterns = [
    path('', views.blogs, name='blogs'),
    re_path(r'(?P<blog_type>[\w-] )/(?P<pk>[0-9] )$', blogspage.as_view(), name='blogspage'),
]

Here using the forignkey as a url parameter

And in blogs views.py

class blogspage(DetailView):
    model=Blogs
    template_name='blogs/blogspage.html'
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        print('Print the object if this is executed', self.get_object())

In Django template you would pass something like:

<div><a href="{% url 'blogspage' b.blog_type b.id %}">{{b.title}}</a></div>

Now the news model.py you have:

class NewsType(models.Model):
    news_type = CharField(max_length=20)
    def __str__(self):
        return self.news_type

class News(models.Model):
    title = models.CharField(max_length=20)
    news_author = models.ForeignKey(User, on_delete=models.CASCADE)
    news_type = models.ForeignKey(NewsType, on_delete=models.DO_NOTHING)

The news views, news urls, news templates, are the exactly the same as blog except the name and template name, basically replacing every single "blogs" to "news"

Then here is where the bug would occur, Only one detailed view will ever execute, for example when someone clicks "{%url "blogspage" blog.blog_type blog.id%}" It will go to url blog/blog_type/pk but the content will be news, However, If <foreignkey> blog_type is removed from url parameter, Only then the detailed view of blog will execute and the correct blog content will be rendered.

news url.py:

urlpatterns = [
    path('', views.news, name='news'),
    re_path(r'(?P<news_type>[\w-] )/(?P<pk>[0-9] )$', newspage.as_view(), name='newspage'),
]

root url.py

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('news.urls')),
    path('blogs/',include('blogs.urls')),
] # path('news/', include('news.urls')), will not conflit
# switch the position between blogs.urls and news.urls also no conflit

Edit: www.example.com/blogs/blog_type/1 and www.example.com/news/news_type/1 will not conflit but www.example.com/blogs/blog_type/1 and www.example.com/news_type/1 will

Edit2: Because "" and "/blogs" bugged I automatically assume "/blogs" and "/news" will also bug, But the bug only exist between "" and "/blogs"

CodePudding user response:

It looks like an issue with Django path and re_path method, where as per your scenario the re_path for both blogs and news URLs for newspage and blogpage are matching and django is not able to resolve the correct URL and redirect on the first matching URL.

  • Related