In Django app models, how to get the url prefix - django

I am writing a Django blog app named blogengine
in the root urls.py:
url(r'^blog/', include('blogengine.urls')),
In my blogengine/models.py
class Post(models.Model):
title = models.CharField(max_length=200)
pub_date = models.DateTimeField()
text = models.TextField()
def get_absolute_url(self):
return "/blog/post/%s/" % self.id
Here I defined a function get_absolute_url with a hard coding /blog/ prefix.
How could I prevent this hard code and using some way to get the prefix in ROOT_URLCONF

You can use reverse resolution of named url. Here is the link to the detail https://docs.djangoproject.com/en/1.8/topics/http/urls/#reverse-resolution-of-urls
Here is the example.
url(r'^post/(?P<id>\d+)/$', post_view, name='post_detail'),
This is the model.
from django.core
from django.core.urlresolvers import reverse
class Post(models.Model):
title = models.CharField(max_length=200)
pub_date = models.DateTimeField()
text = models.TextField()
def get_absolute_url(self):
return reverse('post_detail', kwargs={'id': self.id})

No, this is absolutely not the way to do it. Your model should not care at all about the prefix.
Instead you should use the provided reverse function to calculate the URL, whatever the prefix:
def get_absolute_url(self):
return reverse('blog-post', kwargs={'id': self.id})

get_absolute_url() is not necessary:
url(r'^blog/$', views.post_list, name='post_list'),
url(r'^blog/(?P<post_id>[\w+-]*)/$', views.post_detail, name='post_detail')

Related

Reverse for 'Page' not found. 'Page' is not a valid view function or pattern name

this is the error I got when I wanted to create a dynamic sitemap.
sitemap.py
from django.contrib import sitemaps
from django.shortcuts import reverse
from django.utils import timezone
from django.contrib.sitemaps import Sitemap
#models
from home.models import Page
class StaticViewSitemap(sitemaps.Sitemap):
priority = 0.5
changefreq = "daily"
protocol = 'https'
def items(self):
return [
'home:about',
]
def location(self, item):
return reverse(item)
def lastmod(self, item):
return timezone.now()
class DynamicSitemap(Sitemap):
changefreq = "daily"
priority = 0.5
def items(self):
return Page.objects.all()
models.py
class Page(models.Model):
city = models.CharField(max_length=40, verbose_name="Şehir")
seo = models.CharField(max_length=50, verbose_name="Seo")
def __str__(self):
return self.city
def get_absolute_url(self):
return reverse('home:page', kwargs={'pk': self.pk})
home/urls.py:
app_name = "home"
urlpatterns = [
# ⋮,
path(r'page/<int:pk>', views.yardimsayfalari, name="page"),
# ⋮,
]
static sitemap works fine but dynamic sitemap I get the same error. Thank you to those who are interested so far.
I'm sorry for my bad english
Based on the get_absolute_url, you try to link this to:
path(r'page', views.yardimsayfalari, name='page'),
The name of your view is page, not Page. Furthermore you specified app_name = 'home', hence full name of the view is home:page. Finally your path does not contain any parameter, so args=(self.pk,) makes not much sense.
You thus likely should include a primary key parameter:
app_name = "home"
urlpatterns = [
# &vellip;,
path('page/<int:pk>/', views.yardimsayfalari, name="page"),
# &vellip;,
]
include that pk parameter in your view:
def yardimsayfalari(request, pk):
# …
# return HTTP response
and finally refer to the view with:
class Page(models.Model):
# &vellip;
def get_absolute_url(self):
return reverse('home:page', args=(self.pk,))
It might also make more sense to work with a named parameter, so:
class Page(models.Model):
# &vellip;
def get_absolute_url(self):
return reverse('home:page', kwargs={'pk': self.pk})
based on this, I would advise to (re)read the third part of the Django tutorial.

How can I program a dynamic sitemap in django, mine not working

The static part works fine but the dynamic posts of my blog app are not generated
from django.contrib.sitemaps import Sitemap
from django.urls import reverse
from .models import Post
class PostSitemap(Sitemap):
changefreq = "weekly"
priority = 0.9
def items(self):
return Post.objects.all()
I'm not able to get a dynamic sitemap with my blog and my Post class in models:
class Post(models.Model):
title=models.CharField(max_length=100)
header_image = models.ImageField(null=True , blank=True, upload_to="images/")
title_tag=models.CharField(max_length=100)
author= models.ForeignKey(User, on_delete=models.CASCADE)
body = RichTextUploadingField(extra_plugins=
['youtube', 'codesnippet'], external_plugin_resources= [('youtube','/static/ckeditor/youtube/','plugin.js'), ('codesnippet','/static/ckeditor/codesnippet/','plugin.js')])
#body = models.TextField()
post_date = models.DateTimeField(auto_now_add=True)
category = models.CharField(max_length=50, default='uncategorized')
snippet = models.CharField(max_length=200)
likes = models.ManyToManyField(User, blank=True, related_name='blog_posts')
def total_likes(self):
return self.likes.count()
class Meta:
verbose_name = "Entrada"
verbose_name_plural = "Entradas"
ordering = ['-post_date']
def __str__(self):
return self.title + ' | ' + str(self.author)
def get_absolute_url(self):
return reverse('home')
If any one can help me I would be very grateful.
urls.py:
from django.contrib.sitemaps.views import sitemap
from theblog.sitemaps import PostSitemap, StaticSitemap
sitemaps = {'static': StaticSitemap, 'blog': PostSitemap}
Short answer: The get_absolute_url() should implement a canonical URL to the object.
In order to generate the sitemap. Django will call the .location(…) method [Django-doc] of the Sitemap object on each element. If no .location(…) method is defined, as is the case here. It will call the .get_absolute_url(…) method [Django-doc] on the model object.
You implemented a get_absolute_url method, but it looks like:
def get_absolute_url(self):
return reverse('home')
this means that all the "detail pages" for the Post objects are apparently the home page, so this is the only page that will be in the sitemap. It is also not really satisfying the conditions of the .get_absolute_url(…) method:
Define a get_absolute_url() method to tell Django how to calculate the canonical URL for an object. To callers, this method should appear to return a string that can be used to refer to the object over HTTP.
A canonical URL means that it is normally unique per object. So if you have a path defined like:
path('post/<int:pk>', post_details, name='post_details')
then often the canonical url is:
def get_absolute_url(self):
return reverse('post_details', kwargs={'pk': self.pk})

little bit confuse in dgetting absolute url in django

#project url
from django.conf import settings
from django.conf.urls import url
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path, include
import products
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('products.urls')),
url(r'^product/(?P<title>[\w-]+)/$', products.views.single,name='single')
]
# app url
from django.urls import path, include
import products
from . import views
urlpatterns = [
path('', views.home, name='home'),
]
#model
class products(models.Model):
title = models.CharField(max_length=120)
desc = models.TextField()
price = models.DecimalField(max_digits=10, decimal_places=2, default=29.99)
sales_price = models.DecimalField(max_digits=10, decimal_places=2, blank=False, null=False, default=0)
slug = models.SlugField(unique=True)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
update = models.DateTimeField(auto_now_add=False, auto_now=True)
active = models.BooleanField(default=True)
def __str__(self):
return self.title
def get_price(self):
return self.price
def get_absolute_url(self):
return reverse("single", kwargs={"title": self.title})
#views
def home(request):
product = products.objects.all()
template = 'home.html'
context = {'product': product}
return render(request, template, context)
def single(request,title):
try:
product = products.objects.get(title=title)
template = 'products.html'
context = {'product': product}
return render(request, template, context)
except:
raise Http404
plz view my code .. i m littlebit confuse in absolute url.. it returns title of the product after clicking some link but it doesnt give me the title if i change produc to other. for eg:http:/127.0.0.1:8000/product/T-shirt/ gives title but wheni hit http:/127.0.0.1:8000/productS/T-shirtgives eroror
It's hard to tell what your actual problem is from the way you've expressed your question, but there are several issues:
Models, unless a single entity represents a plurality of something, must be named in singular. Also, following Python practices, they should be capitalized.
class products(...) should be class Product(...).
Since title is not an unique field, as soon as you have multiple products named "T-shirt", your single view will crash, since .get() refuses to work if more than one object matches the query.
Rethink your URL scheme (to e.g. use that unique slug field you have).
The product/.../ URL should be in products/urls.py, not your project URLs.
Move it there.
Unless you're absolutely sure what you're doing, don't use a bare except:, since it will happily hide any exception. You're looking for except ObjectDoesNotExist:, probably.
You should consider using generic class-based views.

Incorrect redirection for a single post category

I'm developing my personal blog; it has only two categories and I would like to have a specific list of posts for both categories.
For this reason I've expand get_absolute_url as you can see below:
from django.db import models
from django.urls import reverse
CATEGORY_CHOICES = (
('G.I.S.', 'G.I.S.'),
('Sustainable Mobility', 'Sustainable Mobility'),
)
class Blog(models.Model):
"""
Blog's post definition
"""
title = models.CharField(
max_length=70,
unique=True,
)
slug = models.SlugField(
unique=True,
)
contents = models.TextField()
publishing_date = models.DateTimeField()
category = models.CharField(
max_length=50,
choices=CATEGORY_CHOICES,
)
def __str__(self):
return self.title
def get_absolute_url(self):
if Blog.objects.filter(category="G.I.S."):
return reverse("gis_single_post", kwargs={"slug": self.slug})
if Blog.objects.filter(category="Sustainable Mobility"):
return reverse("sumo_single_post", kwargs={"slug": self.slug})
Below you can see views.py; it has different model based on a category:
from django.shortcuts import render
from django.views.generic.list import ListView
from django.views.generic.detail import DetailView
from .models import Blog
class GisSinglePost(DetailView):
model = Blog
queryset = Blog.objects.filter(category="G.I.S.")
context_object_name = 'post'
template_name = "gis_single_post.html"
class GisListPost(ListView):
model = Blog
queryset = Blog.objects.filter(category="G.I.S.")
context_object_name = 'posts'
template_name = "gis_list_post.html"
class SuMoSinglePost(DetailView):
model = Blog
queryset = Blog.objects.filter(category="Sustainable Mobility")
context_object_name = 'post'
template_name = "sumo_single_post.html"
class SuMoListPost(ListView):
model = Blog
queryset = Blog.objects.filter(category="Sustainable Mobility")
context_object_name = 'posts'
template_name = "sumo_list_post.html"
And below there is urls.py with its four path:
from django.urls import include, path
from .views import GisSinglePost, GisListPost, SuMoListPost, SuMoSinglePost
urlpatterns = [
path("gis/", GisListPost.as_view(), name="gis_list_post"),
path("gis/<slug:slug>/", GisSinglePost.as_view(), name="gis_single_post"),
path("sustainable-mobility/", SuMoListPost.as_view(), name="sumo_list_post"),
path("sustainable-mobility/<slug:slug>/", SuMoSinglePost.as_view(), name="sumo_single_post"),
]
When I click on a single post of GIS's category it's shown the relative details without problem. But when I click on a post of the other category it's shown to me this:
Page not found (404) Request Method: GET Request URL:
http://127.0.0.1:8000/gis/erova-mobilita/ Raised by:
blog.views.GisSinglePost
No Articolo found matching the query
You're seeing this error because you have DEBUG = True in your Django
settings file. Change that to False, and Django will display a
standard 404 page.
I've been stuck on this problem for many days. How I can resolve?
You should redefine your get_absolute_url method. Since your Blog instances with category G.I.S exist you are never reaching second if for Blog instances with category Sustainable Mobility.
def get_absolute_url(self):
if self.category == "G.I.S.":
return reverse("gis_single_post", kwargs={"slug": self.slug})
elif self.category == "Sustainable Mobility":
return reverse("sumo_single_post", kwargs={"slug": self.slug})
Try to redefine your get_absolute_url(self) in the next way:
def get_absolute_url(self):
if self.category == "G.I.S.":
return reverse("gis_single_post", kwargs={"slug": self.slug})
if self.category == "Sustainable Mobility":
return reverse("sumo_single_post", kwargs={"slug": self.slug})

django: how can i make a generic list view see a regular model?

Sorry if this is a dumb way to ask this...
I have a generic list view for the homepage of a site, and would like to use a "homepage" model for informative text on that same page...is it possible? Thanks for your help.
models.py
from django.db import models
class School(models.Model):
school_name = models.CharField(max_length=250, help_text='Maximum 250 characters.')
slug = models.SlugField(unique=True)
def __unicode__(self):
return self.school_name
def get_absolute_url(self):
return "/schools/%s/" % self.slug
class Student(models.Model):
name = models.CharField(max_length=250, help_text='Maximum 250 characters.')
slug = models.SlugField(unique=True)
mugshot = models.ImageField(upload_to='mugshots')
school = models.ForeignKey(School)
honor = models.TextField()
def __unicode__(self):
return self.name
def get_absolute_url(self):
return "/student/%s/" % self.slug
class Homepage(models.Model):
title = models.CharField(max_length=250, help_text='Maximum 250 characters.')
content = models.TextField()
def __unicode__(self):
return self.title
urls.py
from django.conf.urls.defaults import *
from achievers.apps.students.models import School, Student
from achievers.apps.students.views import hello
from django.contrib import admin
admin.autodiscover()
info_dict = {
'queryset': School.objects.all(),
'extra_context': {'school_list': School.objects.all,}
}
info_dict2 = {
'queryset': Student.objects.all(),
'template_name': 'students/student_detail.html',
'extra_context': {'student_detail': Student.objects.all}
}
urlpatterns = patterns('',
(r'^static/(?P<path>.*)$', 'django.views.static.serve', {'document_root': 'static'}),
(r'^student/(?P<slug>[-\w]+)/$', 'django.views.generic.list_detail.object_detail', info_dict2),
(r'^students/(?P<slug>[-\w]+)/$', 'django.views.generic.list_detail.object_detail', info_dict),
(r'^$', 'django.views.generic.list_detail.object_list', info_dict),
(r'^admin/', include(admin.site.urls)),
(r'^hello/', hello),
)
I'm not sure what you mean when you say you would like to "use" the homepage model with the generic list view. If you simply want access to all instances of Homepage, you can add the following to info_dict in your urls.py:
info_dict = {
'queryset' : School.objects.all(),
'extra_context' : {'school_list' : School.objects.all(), 'homepage_list' : Homepage.objects.all()}
}
You can use a similar technique if you want to pass a specific instance of Homepage to the generic view:
...
'extra_context' : {'school_list' : School.objects.all(), 'homepage' : Homepage.objects.filter(id = 1).get()}
Finally, if you want something more complex (like a dynamic id to be used on the filter), you can always define a custom view, and then call object_list from within that view, like:
def my_view(request, dynamic_id):
info_dict = {..., 'extra_context' : {..., 'homepage' : Homepage.objects.filter(id = dynamic_id).get()}}
return django.views.generic.list_detail.object_list(**info_dict)