My django generic DetailView doens't show any data - python

Hello everyone I have just started developing my blog with django but I don't get to display my posts individually. DetailView doesn't work, please help!
here is my url
from django.urls import path
from .views import Home, ArticleDetailView
urlpatterns = [
path('', Home.as_view(), name='home'),
path('article/<int:pk>', ArticleDetailView.as_view(), name='article_details'),
]
Here is my view.
from django.shortcuts import render
from django.views.generic import ListView, DetailView
from .models import Article
# Create your views here.
class Home(ListView):
model = Article
template_name = 'home.html'
class ArticleDetailView(DetailView):
model = Article
template_name = 'article_detail_view.html'
My model
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Article(models.Model):
title = models.CharField(max_length=255)
author = models.ForeignKey(User, on_delete=models.CASCADE)
body = models.TextField()
def __str__(self):
return self.title + '|' + str(self.author)
class Meta:
verbose_name = 'Article'
verbose_name_plural = 'Articles'
Home.html
<h2>Post</h2>
<ul>
{% for post in object_list %}
<li>{{post.title}} by {{ post.author }}</br>
<p>{{post.body}}</p></li>
{% endfor %}
</ul>
article_detail_view.html
<h2>Article Detail View</h2>
<h2>{{post.title}} By {{ post.author }}</h2></br>
<p>{{post.body}}</p>

Thanks for updating the question.
First add the get_absolute_url method to the model as follows:
class Article(models.Model):
title = models.CharField(max_length=255)
author = models.ForeignKey(User, on_delete=models.CASCADE)
body = models.TextField()
def __str__(self):
return self.title + '|' + str(self.author)
class Meta:
verbose_name = 'Article'
verbose_name_plural = 'Articles'
def get_absolute_url(self):
return reverse("article_details", kwargs={"pk": self.pk})
In your article_detail_view.html, you can access the article using the article instance:
<h2>Article Detail View</h2>
<h2>{{article.title}} By {{ article.author }}</h2></br>
<p>{{article.body}}</p>

in your article_detail_view.html
you can access the article by: {{object.title}}
you can also specify what to return in template and how you wanna name it by overriding get_context_data
check this

in models.py
class Meta:
managed = True
verbose_name = 'Article'
verbose_name_plural = 'Articles'

Related

How can I configure these multiple slugs in my urls and views: Django

I've been trying to configure my urls and views for this password safe app
a site can have many accounts, and to edit an account I plan to use this url config:
home/[sitename]/[accountusername]/edit/. but its bringing errors. How do I go about this?
views.py:
class SiteDetailView(DetailView):
model = Site
template_name = "site_detail.html"
class SiteDeleteView(DeleteView):
model = Site
template_name = "site_delete.html"
success_url = reverse_lazy("home")
class SiteEditView(UpdateView):
model = Site
template_name = "site_edit.html"
fields = ("siteName",)
class AccountDeleteView(DeleteView):
model = Account
template_name = "account_delete.html"
# def get_success_url(self):
# return reverse_lazy("site_detail", kwargs={"slug": self.object.slug})
class AccountEditView(UpdateView):
model = Account
template_name = "account_edit.html"
fields = (
"username",
"password",
)
urls.py:
from django.urls import path
from .views import (
IndexView,
HomePageView,
SiteDetailView,
SiteDeleteView,
AccountDeleteView,
AccountEditView,
SiteEditView,
)
urlpatterns = [
path("home/<slug:slug>/edit/", SiteEditView.as_view(), name="site_edit"),
path(
"home/<slug:slug>/<slug:slug_field>/edit/",
AccountEditView.as_view(),
name="account_edit",
),
path(
"home/<slug:slug>/<slug:slug_field>/delete/",
AccountDeleteView.as_view(),
name="account_delete",
),
path("home/<slug:slug>/delete/", SiteDeleteView.as_view(), name="site_delete"),
path("home/<slug:slug>/", SiteDetailView.as_view(), name="site_detail"),
path("home", HomePageView.as_view(), name="home"),
path("", IndexView.as_view(), name="index"),
]
models.py:
from django.db import models
from django.urls import reverse
from django.conf import settings
from django.template.defaultfilters import slugify
class Site(models.Model):
siteName = models.CharField(max_length=200)
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
slug = models.SlugField(null=False, unique=True)
date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.siteName
def get_absolute_url(self):
return reverse("site_detail", kwargs={"slug": self.slug})
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.siteName)
return super().save(*args, **kwargs)
class Account(models.Model):
site_name = models.ForeignKey(Site, on_delete=models.CASCADE)
username = models.CharField(max_length=140)
password = models.CharField(max_length=50)
slug_field = models.SlugField(null=False, unique=True)
def __str__(self):
return self.username
def get_absolute_url(self):
return reverse("home")
def save(self, *args, **kwargs):
if not self.slug_field:
self.slug_field = slugify(self.username)
return super().save(*args, **kwargs)
my site_detail.html:
{% extends 'base.html' %}
{% block content %}
<h2>{{ object.siteName }}</h2>
<hr>
{% for username in object.account_set.all %}
<p>Username: {{ username.username }}</p>
<p>Password: {{ username.password }}</p>
<p><button type="button">Edit account</button>
<button type="button">Delete account</button></p>
<hr>
{% endfor %}
<p><button type="button">Delete site</button>
<button type="button">Edit site</button></p>
{% endblock content %}
The current error I am facing:
raise FieldError(
django.core.exceptions.FieldError: Cannot resolve keyword 'site' into field. Choices are: id, password, site_name, site_name_id, slug_field, username
This is how a detail view looks at url http://127.0.0.1:8000/home/redditcom/
this is how a detail view looks at url http://127.0.0.1:8000/home/redditcom/
For Django to clearly handle the slug, the field name should be named as "slug", so, for your Site model there will be no problem, but, for account model you named it "slug_field", then, you have 2 options:
Change the "slug_field" to just "slug".
Override the slug field in the Account Views so Django takes them as the slug field, like this:
slug_field = "slug_field"
slug_url_kwarg = "slug_field"
You use siteName in your Site model and site_name in your Account model. I'm not sure what code is generating the error since I don't see anything referencing just site in what you posted here, but if you look at the error, you can see from the other fields listed that it's referencing the Account model. So you need to replace site with site_name somewhere.
For me, when doing stuffs like this, you use use a unique slug. You can add a random unique number to the slug by generating it from uuid4, and using a while loop go make sure no slug repeats its self .
Just create a util.py file in your app and write the function to generate a random unique number the add it to your slug in the models

ModelForm in Django not showing

I'm trying to display a basic form in django but does not render the form once I run the server, I would appreciate if you could help me with these, here my code.
models.py
STATUS_OPTIONS =(
('OP', 'OPEN'),
('CL', 'CLOSED')
)
class Employee(models.Model):
id = models.AutoField(primary_key=True)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
email = models.EmailField(max_length=200)
status = models.CharField(max_length=50, choices=STATUS_OPTIONS)
password = models.CharField(max_length=100)
def __str__(self):
return self.first_name
forms.py
from django import forms
from .models import Employee
class EmployeeForm(forms.Form):
class Meta:
model = Employee
fields = "__all__"
urls.py
from django.urls import include, path
from . import views
urlpatterns = [
path('', views.create_employee),
]
views.py
from .forms import EmployeeForm
# Create your views here.
def create_employee(request):
form = EmployeeForm()
return render(request, 'employee/create_employee.html', {'form':form})
create_employee.html
<h1>Formu</h1>
<form action="" method='POST'>
{{form.as_p}}
<input type="submit">
</form>
When I run the program the only thing rendered is the tag, any idea?
In order to create forms out of models you need to use ModelForm not Form. Otherwise you end up with a regular form without any field.
from django.forms import ModelForm
from .models import Employee
class EmployeeForm(ModelForm):
#...
More about ModelForm here

Model data not displayed on template - django

Short Story: I have made two apps. Properties and Tenants within a django project. First I started rendering data from Property model to property_detail.html template and it works fine, but after I created & migrated the Tenants model, and I try to render data from there to property_detail.html it doesn't work. Yet it doesn't give me any errors. It just doesn't show up.
Models.py
import arrow
import uuid
from django.db import models
from django_countries.fields import CountryField
from django.urls import reverse
from django.conf import settings
from properties.models import Property
class Tenant(models.Model):
id = models.UUIDField( # new
primary_key=True,
default=uuid.uuid4,
editable=False)
full_name = models.CharField("Full Name", max_length=255, null=True)
email = models.EmailField(unique=True, null=True)
phone = models.CharField(max_length=20, unique=True, null=True)
description = models.TextField("Description", blank=True)
country_of_origin = CountryField("Country of Origin", blank=True)
creator = models.ForeignKey(
settings.AUTH_USER_MODEL, null=True, on_delete=models.SET_NULL)
created_on = models.DateTimeField(
"Created on", auto_now_add=True, null=True)
is_active = models.BooleanField(default=False)
apartment = models.ForeignKey(
Property,
on_delete=models.CASCADE,
related_name='reviews',
)
rent_tenant = models.CharField(
"Rent he/she pays", max_length=10, blank=True)
def __str__(self):
return self.full_name
def get_absolute_url(self):
""""Return absolute URL to the Contact Detail page."""
return reverse('tenant_detail', kwargs={'pk': str(self.pk)})
urls.py
from django.urls import path
from .views import TenantListView, TenantDetailView
urlpatterns = [
path('', TenantListView.as_view(), name='tenant_list'),
path('<uuid:pk>', TenantDetailView.as_view(), name='tenant_detail'), # new
]
views.py
from django.views.generic import ListView, DetailView
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin # new
from .models import Tenant
class TenantListView(LoginRequiredMixin, ListView): # new
model = Tenant
context_object_name = 'tenant_list'
template_name = 'tenants/tenant_list.html'
login_url = 'account_login' # new
class TenantDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView): # new
model = Tenant
context_object_name = 'tenant'
template_name = 'tenants/tenant_detail.html'
login_url = 'account_login' # new
permission_required = 'books.special_status' # new
and here is the html template section where I need it to be rendered.
<li class="list-group-item">
{% if tenant.full_name %}
<b>Layout</b> <a class="float-right">{{ tenant.full_name }}</a>
{% endif %}
</li>
<li class="list-group-item">
{% if property.usable_sqm %}
<b>SQM</b> <a class="float-right">{{ property.usable_sqm }}</a>
{% endif %}
</li>
The other app is EXACTLY the same. Basically I copy-pasted everything from there and then just changed the fileds and renamed all the fields from Property to Tenant (By that I mean all the functions and urls ... ) What seems to be the problem? Because by my logic this should work.
The views.py document you have provided doesn’t have property_details.html template, instead it has tenant templates( you trying to render tenant objects into property template right?). I am not sure how you trying passing tenant model to property template from the code provided.
Why don’t you import tenant model into property views and pass whatever tenant objects you want to the property template?

How can I order post entries in a Django template

I made my post model where I store all the post info, like the title, the body, the tags an so on. And I linked it to my index template with a for loop:
<!-- Blog Post -->
{% for blog in object_list %}
<div class="card mb-4">
<div class="card-body">
<h4 id="post_title" class="card-title">{{blog.title}}</h2>
<div id="post_body" class="card-text">{{blog.formatted_markdown|safe}}</div>
Read More
</div>
<div class="card-footer text-muted">
<p id="foot_page">{{blog.date}}</p>
<a id="foot_page" href="#">{{blog.author}}</a>
</div>
</div>
{% endfor %}
And when I run my server the post appear on the blog ordered by pub_date ascending, so the new ones appear delow the old ones.
What can I do to make the newest post appear on top?
Here's my Post model class if it's useful:
class Post(models.Model):
title = models.CharField(max_length=255)
body = MarkdownxField()
tags = models.ManyToManyField(Tag)
author = models.CharField(max_length=255, default='Raúl Chirinos')
date = models.DateTimeField(auto_now_add=True, blank=True)
#property
def formatted_markdown(self):
return markdownify(self.body)
def __str__(self):
return self.title
I managed the views within the urls file:
from django.conf.urls import url
from django.urls import include, path
from django.contrib import admin
from django.views.generic.list import ListView
from django.views.generic.detail import DetailView
from raulchirinos.models import Post
app_name = 'raulchirinos'
urlpatterns = [
url(r'^markdownx/', include('markdownx.urls')),
url(r'^admin/', admin.site.urls, name='admin-site'),
url(r'^$', ListView.as_view(model=Post, template_name='raulchirinos/index.html'), name='index'),
url(r'^details/(?P<pk>[0-9]+)/$', DetailView.as_view(model=Post, template_name='raulchirinos/post_template/post.html'), name='post_details'),
]
Add a meta class to the models and set the sort according to your requirement.
Ex:
class Post(models.Model):
title = models.CharField(max_length=255)
body = MarkdownxField()
tags = models.ManyToManyField(Tag)
author = models.CharField(max_length=255, default='Raúl Chirinos')
date = models.DateTimeField(auto_now_add=True, blank=True)
class Meta:
ordering = ['-date']
#property
def formatted_markdown(self):
return markdownify(self.body)
def __str__(self):
return self.title
You have several options depending on the level where you need the ordering to happen:
Set a Meta subclass to your Post model with the ordering attribute set to order by date descending. See: https://docs.djangoproject.com/en/2.0/ref/models/options/#ordering
class Post(models.Model):
# ...
class Meta:
ordering = ["-date"]
Order the data from the modle in your view before passing it onto the context.
Reverse the for loop in the template.
Of course the best option is probably the first one, since it's likely that you want this ordering in any case when you retrieve multiple Posts.

Confused by Django 404s for simple pages

Im doing my first Django site myself after going through several tutorials and running into some errors that I can't figure out what the problem is as they are simple page requests.
I was trying to make a category detail view e.g. 127.0.0.1:8000/news and Ive followed the same setup as other pages such as the index and post detail which have worked fine but this is giving a 404.
here are my files
models.py
from django.db import models
from django.core.urlresolvers import reverse
class EntryQuerySet(models.QuerySet):
def published(self):
return self.filter(publish=True)
class Blog(models.Model):
title = models.CharField(max_length = 200)
slug = models.SlugField(max_length = 100, db_index = True)
body = models.TextField()
publish = models.BooleanField(default=True)
created = models.DateTimeField(auto_now_add=True)
category = models.ForeignKey('blog.category')
objects = EntryQuerySet.as_manager()
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post_detail', kwargs={'slug':self.slug})
class Meta:
verbose_name = 'Blog entry'
verbose_name_plural = 'Blog entries'
ordering = ['-created']
class Category(models.Model):
cat_title = models.CharField(max_length = 200, db_index = True)
cat_slug = models.SlugField(max_length = 100, db_index = True)
def __str__(self):
return self.cat_title
def get_absolute_url(self):
return reverse('category_detail', kwargs={'cat_slug':self.cat_slug})
class Meta:
verbose_name = 'Category'
verbose_name_plural = 'Categories'
views.py
from django.views import generic
from . import models
class index_view(generic.ListView):
queryset = models.Blog.objects.published()
template_name = 'index.html'
class post_view(generic.DetailView):
model = models.Blog
template_name = 'post_view.html'
class category_view(generic.ListView):
model = models.Category
template_name = 'category_view.html'
class category_detail_view(generic.DetailView):
model = models.Category
template_name = 'category_detail_view.html'
class About_page(generic.DetailView):
template_name = 'about.html'
app urls.py
from django.conf.urls import url
from django.contrib import admin
from . import views
urlpatterns = [
url(r'^$', views.index_view.as_view(), name='index'),
url(r'^categories/$', views.category_view.as_view(), name='category_detail'),
url(r'^(?P<slug>\S+)$', views.post_view.as_view(), name='post_detail'),
url(r'^(?P<cat_slug>\S+)$', views.category_detail_view.as_view(), name='category_detail_view'),
url(r'^about/$', views.About_page.as_view(), name='about'),
this is the category detail page 'category_detail_view.html'
{% extends 'base.html' %}
{% block title %} The category detail view page {% endblock %}
{% block category_detail %}
{% for cat_title in object_list %}
<ul>
<li>{{ category.cat_title }}</li>
{% endfor %}
</ul>
{% endblock %}
and the about page
{% extends 'base.html' %}
<h2>This is the about page</h2>
both of these pages return this error message
Page not found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/about/
Raised by: blog.views.post_view
No Blog entry found matching the query
I dont understand why 'blog.post_view' is being raised when neither of these templates refer to the post_view.
I have an index page with all published posts listed, a categories page with all categories listed and a post detail page all of which work fine and are almost exactly the same as these views and templates.
When Django resolves the url /about/, it goes through your url patterns in order. It matches the post_detail url pattern, so runs the post_view, treating about as a slug. Since you don't have any posts with the slug about, you get the 404 error.
One solution is to move the about url pattern above the post_detail pattern. You should also change the category url pattern, otherwise it won't work. For example, you could do:
url(r'^about/$', views.About_page.as_view(), name='about'),
url(r'^(?P<slug>\S+)$', views.post_view.as_view(), name='post_detail'),
url(r'^categories/(?P<cat_slug>\S+)$', views.category_detail_view.as_view(), name='category_detail_view'),

Categories