Slugfield not working if field name is different from slug - django

Good evening, Django is completely new for me and it's my first question here.
I'm trying to create a Webapp. I'm using Django, Python and MariaDB.
I created a project with two apps and I have a model for each app. In the fist one I used "slug" as field name and everything is working fine. In the second one I wanted to differentiate that field giving a different name (bk_slug) defined as SlugField. I tried to use the same kind of instructions lines and modifying them for the field name it seems not working. I cannot have the right URL (Class based ListView) and cannot access to the Class based DetailView....
Thanks in advance for your support.
models.py
from django.db import models
from django.conf import settings
from django.utils import timezone
from django.urls import reverse
# book masterdata
class Book(models.Model):
bk_title = models.CharField("Book Title", max_length=100,
primary_key=True)
bk_originaltitle = models.CharField("Book original Title",
max_length=100, blank=True)
bk_author = models.CharField("Author", max_length=50)
bk_editor = models.CharField("Editor", max_length=50)
bk_editiondate = models.CharField("Book Edition date",
max_length=30)
bk_recblocked = models.BooleanField("Book record blocked")
bk_creator = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.PROTECT,
related_name='+', verbose_name="Created by")
bk_creationdate = models.DateTimeField("Creation date",
auto_now=True)
bk_modifier = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.PROTECT,
related_name='+', verbose_name="Last modification by")
bk_modified = models.DateTimeField("Last modification date",
auto_now=True)
bk_slug = models.SlugField(max_length=100, allow_unicode=True,
blank=True)
def __str__(self):
return self.bk_title
def get_absolute_url(self):
return reverse('book_detail', kwargs={'slug': self.bk_slug})
urls.py
from django.urls import path
from dimlibrary.views import BookListView
from dimlibrary.views import BookDetailView
urlpatterns = [
path('', BookListView.as_view(), name='book_list'),
path('<slug:bk_slug>/', BookDetailView.as_view(),
name='book_detail'),
]
views.py
from django.shortcuts import render
# Create your views here.
from django.shortcuts import render
from django.utils import timezone
from django.views.generic.list import ListView
from django.views.generic.detail import DetailView
from dimlibrary.models import Book
# book views :
# List view
class BookListView(ListView):
model = Book
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
return context
# Details View
class BookDetailView(DetailView):
model = Book
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
return context
```html
{% extends 'base/base.html' %}
{% load static %}
{% block content %}
<h1>Books List</h1>
<ul>
{% for book in object_list %}
<li><a href="{{ dimlibrary.book.get_absolute_url }}">{{
book.bk_title }}</a> - {{ book.bk_author }} -
{{ book.bk_editor }}</li>
{% empty %}
<li>No book registred yet.</li>
{% endfor %}
</ul>
{% endblock content %}

In your DetailView, you need to specify the slug_field [Django-doc] as 'bk_slug':
class BookDetailView(DetailView):
model = Book
slug_field = 'bk_slug'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
return context
In the model, you will need to slugify(…) [Django-doc] the name, so:
from django.utils.text import slugify
class Book(models.Model):
# …
def save(self, *args, **kwargs):
if not self.bk_slug:
self.bk_slug = slugify(self.title)
return super().save(*args, **kwargs)

Related

Django dropdown filter queryset with FilterView

I want to filter apartments by selecting subcity field in a dropdown in my django app. I'm using django-filters and django-bootstrap-form. But the dropdown does not populate with database querysets. How can I make the dropdown work?
models.py:
from django.contrib.sites.models import Site
from django.contrib.gis.db import models
from django.utils.crypto import get_random_string
from django.contrib.gis.geos import GEOSGeometry,Point
from django.contrib.auth.models import AbstractUser
from django.shortcuts import render
from django.urls import reverse
from django.forms import ModelForm
from django.template.defaultfilters import slugify
import datetime
from leaflet.forms.widgets import LeafletWidget
from django.contrib.gis.db import models as geo_models
# Create your models here.
class User(AbstractUser):
pass
geos_pnt=Point(4314498.56, 1003834.600,srid=3857)
#pnt=GEOSGeometry('POINT(4314498.56, 1003834.600)').wkt
class Apartment(models.Model):
ADKT='Addis Ketema'
AKLT='Akaki-Kality'
ARDA= 'Arada'
BOLE='Bole'
GLLE='Gulele'
KLFE='Kolfe-Keranio'
KIRK='Kirkos'
LDTA='Lideta'
YEKA='Yeka'
NFSL='Nefas Silk-Lafto'
SUBCITY_CHOICES = [
(ADKT, 'Addis Ketema'),
(AKLT, 'Akaki-Kality'),
(ARDA, 'Arada'),
(BOLE, 'Bole'),
(GLLE, 'Gulele'),
(KLFE, 'Kolfe-Keranio'),
(KIRK,'Kirkos'),
(LDTA, 'Lideta'),
(NFSL, 'Nefas Silk-Lafto'),
(YEKA, 'Yeka')]
apt_id = models.CharField(max_length=200, primary_key=True,editable=True)
geom = geo_models.PointField(null=True)
apt_area = models.IntegerField(default=0, null=True)
no_bedrooms = models.IntegerField(null=True)
apt_cost = models.IntegerField(default=0, null=True)
apt_subcity = models.CharField(default='KIRK',choices=SUBCITY_CHOICES,max_length=30,null=True)
register_date = models.DateTimeField(auto_now_add=True,null=True)
objects = models.Manager()
sites =models.ManyToManyField(Site)
#change points from apt_rent_db to kml
def pointkml(self):
points = Apartment.objects.kml()
return render("placemarks.kml", {'places': points})
def get_absolute_url(self):
return reverse('rent_app:apartment-listing', kwargs={'pk': self.pk})
def save(self, *args, **kwargs):
#self.Latitude = self..y
#self.Longitude = self.location.x
self.slug = slugify(self.apt_id)
super(Apartment, self).save(*args, **kwargs)
class Meta:
# order of drop-down list items
verbose_name = ("Apartment")
verbose_name_plural = ("Apartments")
ordering = ('apt_cost',)
app_label = 'rent_app'
def __unicode__(self):
return self.apt_id
#property
def picture_url(self):
return self.picture.url
class UserProfile(models.Model):
first_name = models.CharField(max_length=100, null=False)
last_name = models.CharField(max_length=100,null=False)
gender = models.CharField(max_length=100)
phone_no = models.CharField(max_length=12)
sites = models.ManyToManyField(Site)
views.py:
class ApartmentFilterView(FilterView):
model = Apartment
context_object_name = 'apartments'
filter_class = ApartmentFilter
filters.py:
import django_filters
from .models import Apartment,UserProfile
class ApartmentFilter(django_filters.FilterSet):
ADKT = 'Addis Ketema'
AKLT = 'Akaki-Kality'
ARDA = 'Arada'
BOLE = 'Bole'
GLLE = 'Gulele'
KLFE = 'Kolfe-Keranio'
KIRK = 'Kirkos'
LDTA = 'Lideta'
YEKA = 'Yeka'
NFSL = 'Nefas Silk-Lafto'
SUBCITY_CHOICES = [
(ADKT, 'Addis Ketema'),
(AKLT, 'Akaki-Kality'),
(ARDA, 'Arada'),
(BOLE, 'Bole'),
(GLLE, 'Gulele'),
(KLFE, 'Kolfe-Keranio'),
(KIRK, 'Kirkos'),
(LDTA, 'Lideta'),
(NFSL, 'Nefas Silk-Lafto'),
(YEKA, 'Yeka')]
ordering = django_filters.ChoiceFilter(label='Ordering',subcity_choices=SUBCITY_CHOICES, method='filter_by_ordering')
class Meta:
model = Apartment
fields = {
'apt_cost': ['lte'],
#'apt_dist': ['lt'],
'apt_subcity': ['icontains'],
}
template:
{% extends 'base.html' %}
{% load bootstrap %}
{% block title %} የተገኙ ቤቶች | Apartment List {% endblock title %}
{% block content %}
<form action="" method="get">
{{ filter.form.as_p }}
<input type="submit">
</form>
{% for obj in filter.qs %}
{{obj.apt_id}} - Birr {{obj.apt_cost}}
{% endfor %}
{% endblock %}
Your model should be listed in the Meta class.
class yourfilter(django_filters.FilterSet):
class Meta:
model = your_model

Django NoReverseMatch :Reverse for 'blog_detail' with arguments '(1,)' not found

I created a topic as a categories for blog project.
I pointed 'topic' as a PK to my model
It is successfully to access by the follow path:
http://127.0.0.1:8000/django/1
and http://127.0.0.1:8000/IDE/2 django and IDE is the topic of my model
from django.shortcuts import render, get_object_or_404
from .models import Blog, Topic
from django.views.generic import DetailView
def post_list(request, topic_slug=None):
topic= None
topics = Topic.objects.all()
blogs = Blog.objects.filter(available=True)
if topic_slug:
topic = get_object_or_404(Topic, slug=topic_slug)
blogs = blogs.filter(topic=topic)
return render(request,
'topiclist.html',
{'topics': topics,
'topic':topic,
'blogs': blogs,
})
class BlogDetail(DetailView):
model = Blog
template_name ='detail.html'
from django.urls import path
from . import views
from .views import BlogDetail
urlpatterns = [
path('<slug:topic_slug>/', views.post_list, name='post_list'),
path('<slug:topic_slug>/<int:pk>/', BlogDetail.as_view(), name='blog_detail'),
]
from django.db import models
from ckeditor.fields import RichTextField
from django.urls import reverse
class Topic(models.Model):
name = models.CharField(max_length=50)
slug = models.SlugField(max_length=50, default='self.name', db_index=True, unique=True)
class Meta:
verbose_name = 'topic'
verbose_name_plural = 'topics'
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('post:topiclist', args=[self.slug])
class Blog(models.Model):
title = models.CharField(max_length=50)
author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
content = RichTextField()
topic = models.ForeignKey(Topic, default=1, on_delete=models.SET_DEFAULT)
available = models.BooleanField(default=True)
class Meta:
verbose_name = 'post'
verbose_name_plural = 'posts'
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post_detail', args=[str(self.id)])
It show the error
NoReverseMatch at /django/
Reverse for 'blog_detail' with arguments '(1,)' not found. 1 pattern(s) tried: ['(?P<topic_slug>[-a-zA-Z0-9_]+)/(?P<pk>[0-9]+)/$']
when I use the the URL config of
blog_detail
My HTML template
{% block content %}
{% for blog in blogs %}
{{ topic.title }}</li>
{% endfor %}
{% endblock content %}
It works for using post_list but when I am using blog_detail it show the error. Any idea for this? I am new for django and programming. so many thanks if anyone could help. I read this question but it not help
Reverse for 'blog_detail' with no arguments not found. 1 pattern(s) tried: ['blog/(?P<pk>[0-9]+)$']
According to your urls.py code, the blog_detail url requires two arguments (the topic slug and the pk) and you only supplied the pk. If you pass in both, it should work (or refactor the url so the topic slug is not required).
{% url 'blog_detail' blog.topic.slug blog.pk %}

Dynamic buttons that filter objects Django #UPDATE

#UPDATE
I want to make dynamic multiple buttons that filtering objects, similar to website https://justjoin.it/brands
For now I've done filtering with Django-filter that allows users to filter companies by Type, City and is company open for Students. But this django-filter require page to be refreshed which means it's not dynamic updating. It looks like this
image 1
image 2
and this is functional, works excellent.
Then I've created simple API with django-rest-framework which is accesible on 127.0.0.1:8000/api/companies and looks like this
Image
and also works fine.
The next thing that I've made is adding jQuery and simple script to get data from API, when someone submit form with ID=submit (image below)
image
But now I've stucked because I dont know how to get Data from API and compare this to template. I'm asking for any suggetions because I couldnt find any good example.
My files (updated)
models.py
from django.db import models
from django.db import models
from django.utils import timezone
from django.utils.text import slugify
from django.core.validators import MinValueValidator
from multiselectfield import MultiSelectField
import django_filters
TYPES = (
('Startup', 'Startup'),
('Software House', 'Software House'),
....)
CITIES = (
('Warszawa', 'Warszawa'),
('Poznan', 'Poznan'),
....)
COMPANY_TECHNOLOGIES = (
('PHP', 'PHP'),
('js', 'JavaScript'),
....)
STUDENTS = (
('No', 'No'),
('Yes', 'Yes')
)
class Company(models.Model):
name = models.CharField(max_length=100, blank=False)
students = models.CharField(max_length=3, choices=STUDENTS)
type = models.CharField(max_length=15, choices=TYPES)
workers = models.PositiveIntegerField(validators=[MinValueValidator(1)])
city = models.CharField(max_length=15,choices=CITIES)
stack = MultiSelectField(choices=COMPANY_TECHNOLOGIES)
....
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Company, self).save(*args, **kwargs)
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.name
views.py
from django.shortcuts import render, get_object_or_404, redirect
from django.utils import timezone
from .models import Company
from .filters import CompanyFilter
from rest_framework import viewsets
from .serializers import CompanySerializer
# Create your views here.
def companies_list(request):
my_companies = Company.objects.all()
## filter by company type
type = request.GET.get('type')
if type:
my_companies = Company.objects.filter(type=type)
## filter by company city
city = Company.objects.all()
if city:
my_companies = Company.objects.filter(city=city)
## filter by company technologies
stack = request.GET.get('stack')
if stack:
my_companies = Company.objects.filter(city=city)
my_companies = my_companies.order_by('published_date')
return render(request, 'company/companies_list.html', {'my_companies': my_companies})
def comp_list(request):
f = CompanyFilter(request.GET, queryset=Company.objects.all())
return render(request, 'company/comp_list.html', {'filter': f})
##def brands(request, slug):
## brands = Company.objects.all()
##return render(request, 'company/comp_view.html', {'brands': brands})
def brands(request, pk):
brand = get_object_or_404(Company, pk=pk)
return render(request, 'company/comp_view.html', {'brand': brand})
comp_list.html
{% extends 'company/base.html' %}
{% block content %}
<div id="filter">
<form action="" method="get" id="submit">
{{ filter.form.as_p }}
<input type="submit"/>
</form>
{% for obj in filter.qs %}
{{ obj.name }}
<p>Image {% if obj.image != None %}
<img src="{{ obj.image.url }}">
{% endif%}</p>
<p>Icon {% if obj.icon != None %}
<img src="{{ obj.icon.url }}" width="30" height="30">
{% endif%}</p>
<br> Type: {{ obj.type }} City: {{ obj.city }} Stack: {{ obj.stack }}
<br />
<br>
{% endfor %}
{% endblock %}
serializers.py
from .models import Company
from rest_framework import serializers
class CompanySerializer(serializers.ModelSerializer):
class Meta:
model = Company
fields = "__all__"
filters.py
import django_filters
from .models import Company, COMPANY_TECHNOLOGIES
from django_filters import ChoiceFilter
class CompanyFilter(django_filters.FilterSet):
class Meta:
model = Company
fields = ['type', 'city', 'students']
def __init__(self, *args, **kwargs):
super(CompanyFilter, self).__init__(*args, **kwargs)
self.filters['type'].extra.update(
{'empty_label': 'All'})
self.filters['city'].extra.update(
{'empty_label': 'All'})
self.filters['students'].extra.update(
{'empty_label': 'All'})
ajax.js
$( "#submit" ).click(function(event) {
event.preventDefault();
$.ajax({
url: "http://127.0.0.1:8000/api/companies/",
method: 'GET',
success: function(data){
console.log(data)
},
error: function(error_data){
console.log("error")
console.log(error_data)
}
})});
Filtering is usually done via GET parameters.
In this example, if you add ?company_name=acme to the URL, only company names with acme in the name would be shown:
def companies_list(request):
my_companies = company.objects.filter(
published_date__lte=timezone.now())
company_name = request.GET.get('company_name', None)
if company_name:
my_companies = my_companies.filter(company_name__icontains=company_name)
my_companies = my_companies.order_by('published_date')
return render(request, 'company/index.html', {'my_companies': my_companies})
There's also django-filter to ease this stuff.
As for the SPA, this is beyond the scope of the question, but it should be done with an AJAX request and replacing the DOM element with the response of the view, or returning a JSONResponse and building the element with JavaScript.

Cannot resolve keyword 'name' into field using get_queryset

Sorry is this is basic but I'm new at this
I am attempting to take the captured group from a url in the template, (the primary key of the story model) and then use that to filter the correct posts from the Post datbase, which it has a one(story) to many(Post) relationship with. I based the code of the docs: https://docs.djangoproject.com/en/2.0/topics/class-based-views/generic-display/#dynamic-filtering
But when I run it, I get the error:
FieldError at /story/1/
Cannot resolve keyword 'name' into field. Choices are: body, id, title, work, work_id
My code:
#views
from django.shortcuts import get_object_or_404, render
from django.views.generic import ListView, DetailView
from . models import Post, Story
class StoryListView(ListView):
model = Story
template_name = 'home.html'
class PostListView(ListView):
template_name = 'story_overview.html'
def get_queryset(self):
self.work_id=get_object_or_404(Post, name=self.kwargs['pk'])
return Post.objects.filter(work_id=self.work_id)
#urls
from django.urls import path
from . import views
urlpatterns = [
path('', views.StoryListView.as_view(), name='home'),
path('story/<int:pk>/', views.PostListView.as_view(), name='story_overview'),
]
#templates/home.html
{% extends 'base.html' %}
{% block content %}
{% for post in object_list %}
<h2>{{ post.title }}</h2>
<p>{{ post.description }}</p>
{% endfor %}
{% endblock content %}
#models
from django.db import models
class Story(models.Model):
title = models.CharField(max_length=200)
description = models.CharField(max_length=1500, default= "Description")
def __str__(self):
return self.title
class Post(models.Model):
title = models.CharField(max_length=200, default= "Title")
work = models.ForeignKey(Story,on_delete=models.CASCADE,)
body = models.TextField()
def __str__(self):
return self.title
If you filter using work_id then you should use the integer.
def get_queryset(self):
return Post.objects.filter(work_id=self.kwargs['pk'])
If you want to fetch the Story instance then you should call get_object_or_404 with Story, and filter on the pk field instead of name:
def get_queryset(self):
self.work=get_object_or_404(Story, pk=self.kwargs['pk'])
return Post.objects.filter(work=self.work)
Note I've renamed work_id to work because it's a model instance, not an id.
You are trying to get object from Post() model using name field. Is name field present in your Post() model?
Instead of doing this
self.work_id=get_object_or_404(Post, name=self.kwargs['pk'])
Do this
self.work_id=get_object_or_404(Post, id=self.kwargs['pk'])
Hope it helps!

Why is this Django class-based year archive view not working?

I'm trying to subclass the YearArchiveView class-based view to show a list of articles published in a year, but the filtering doesn't work and example.com/2012 shows articles from all years.
Note that I do not want the view code in urls.py. Rather, I want the LogbookYearArchive wrapper to continue living in views.py.
models.py:
class Entry(models.Model):
KIND = (
('L', 'Link'),
('A', 'Article'),
)
title = models.CharField(max_length=200)
slug = models.SlugField(unique_for_date='pub_date')
kind = models.CharField(max_length=1, choices=KIND, default=1,
help_text="Is this a link to other content or an original article?")
url = models.URLField(blank=True, help_text="The link URL")
body = models.TextField(blank=True)
body_html = models.TextField()
content_format = models.CharField(choices=CONTENT_FORMAT_CHOICES,
max_length=50, default=1)
is_active = models.BooleanField(help_text=_("Tick to make this entry\
live (see also the publication date). Note that administrators\
(like yourself) are allowed to preview inactive entries whereas\
the general public aren't."), default=True)
pub_date = models.DateTimeField(verbose_name=_("Publication date"),
help_text=_("For an entry to be published, it must be active and its\
publication date must be in the past."))
mod_date = models.DateTimeField(auto_now_add=True, editable=False)
class Meta:
db_table = 'blog_entries'
verbose_name_plural = 'entries'
ordering = ('-mod_date',)
get_latest_by = 'pub_date'
def __unicode__(self):
return self.title
#models.permalink
def get_absolute_url(self):
"""Construct the absolute URL for an Entry of kind == Article."""
return ('logbook-entry-detail', (), {
'year': self.pub_date.strftime("%Y"),
'month': self.pub_date.strftime("%m"),
'slug': self.slug})
urls.py:
from __future__ import absolute_import
from django.conf.urls import patterns, include, url
from .models import Entry
from .views import LogbookYearArchive
urlpatterns = patterns('',
url(r'^(?P<year>\d+)/$',
view=LogbookYearArchive.as_view(),
name='archive-year'),
)
views.py:
from django.views.generic.list import MultipleObjectMixin
from django.views.generic import ArchiveIndexView, MonthArchiveView, YearArchiveView, DetailView
from django.core.urlresolvers import reverse
from .models import Entry
class LogbookYearArchive(YearArchiveView):
"""Yearly archives of articles"""
model = Entry
date_field = 'pub_date'
year_format='%Y'
make_object_list=True,
template_name = 'hth/archive_year.html'
allow_future = False
def get_context_data(self, **kwargs):
context = super(LogbookYearArchive, self).get_context_data(**kwargs)
# =todo: fix filtering by date which is not working
context['object_list'] = Entry.objects.filter(
is_active=True, kind='A').order_by('-pub_date', 'title')[:9999]
return context
archive_year.html:
{% block content %}
<h1 style="margin-bottom:1em;">Articles Published in {{ year|date:"Y" }}</h1>
{% for object in object_list %}
{% ifchanged %}
<h2 class="dateline datelinearchive">{{ object.pub_date|date:"F Y" }}</h2>
{% endifchanged %}
<p>
{{ object.title }}
</p>
{% endfor %}
{% endblock %}
Can you try this:
class LogbookYearArchive(YearArchiveView):
"""Yearly archives of articles"""
model = Entry
date_field = 'pub_date'
year_format='%Y'
make_object_list=True,
template_name = 'hth/archive_year.html'
allow_future = False
queryset = Entry.objects.filter(
is_active=True, kind='A').order_by('-pub_date', 'title')
I added a queryset attribute and removed get_context_data()
I had the same problem. All ArchiveViews were working except YearArchiveView. Solution was found in make_object_list property. It should be True
That's a cut from django code
if not self.get_make_object_list():
# We need this to be a queryset since parent classes introspect it
# to find information about the model.
qs = qs.none()