How to stop titles / slugs with special characters from being queried - django

I'm having some issues with the slug field, the Error shows like this.
NoReverseMatch at /blog/
Reverse for 'blog_details' with keyword arguments '{'slug': 'We’ve-caught-a-black-hole-devouring-a-neutron-star-for-the-first-time-f84f375e-65a1-4b4a-b0e6-39a450e1d552'}' not found. 1 pattern(s) tried: ['blog/details/(?P[-a-zA-Z0-9_]+)$']
how to solve special character issues in the title...
this is the views:
from django.shortcuts import render, HttpResponseRedirect
from django.views.generic import CreateView, UpdateView, ListView, DetailView, DeleteView, TemplateView, View
from app_blog.models import Blog, Comment, Likes
from django.urls import reverse, reverse_lazy
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
import uuid
# Create your views here.
class CreateBlog (LoginRequiredMixin, CreateView) :
model = Blog
template_name = 'app_blog/create_blog.html'
fields = ('blog_title', 'blog_content', 'blog_image',)
def form_valid ( self, form ) :
blog_obj = form.save (commit = False)
blog_obj.author = self.request.user
title = blog_obj.blog_title
blog_obj.slug = title.replace (' ', '-') + '-' + str (uuid.uuid4 ())
blog_obj.save ()
return HttpResponseRedirect (reverse ('index'))
class BlogList (ListView) :
context_object_name = 'blogs'
model = Blog
template_name = 'app_blog/blog_list.html'
#login_required
def blog_details ( request, slug ) :
blog = Blog.objects.get (slug = slug)
return render (request, 'app_blog/blog_details.html', context = {'blog' : blog})
this is the model
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Blog (models.Model) :
author = models.ForeignKey (User, on_delete = models.CASCADE, related_name = 'post_author')
blog_title = models.CharField (max_length = 264, verbose_name = 'Put a Title')
# slug is used for using title in the url
slug = models.SlugField (max_length = 264, unique = True)
blog_content = models.TextField (verbose_name = 'Whats on your mind?')
blog_image = models.ImageField (upload_to = 'blog_images', verbose_name = 'Image')
publish_date = models.DateTimeField (auto_now_add = True)
update_date = models.DateTimeField (auto_now = True)
class Meta :
ordering = ['-publish_date']
def __str__ ( self ) :
return self.blog_title
class Comment (models.Model) :
blog = models.ForeignKey (Blog, on_delete = models.CASCADE, related_name = 'blog_comment')
user = models.ForeignKey (User, on_delete = models.CASCADE, related_name = 'user_comment')
comment = models.TextField ()
comment_date = models.DateTimeField (auto_now_add = True)
class Meta :
ordering = ('-comment_date',)
def __str__ ( self ) :
return self.comment
class Likes (models.Model) :
blog = models.ForeignKey (Blog, on_delete = models.CASCADE, related_name = 'liked_blog')
user = models.ForeignKey (User, on_delete = models.CASCADE, related_name = 'liker_user')
def __str__ ( self ) :
return self.user + "likes" + self.blog
this is the HTML:
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block title_block %} {{ blog.blog_title }} {% endblock %}
{% block body_block %}
<div class = "row">
<div class = "col-sm-6">
<h2>{{ blog.blog_title }}</h2>
<h4>Posted by: #{{ blog.author }}</h4>
<i><h6>Publish on: {{ blog.publish_date }}</h6></i>
<i><h6>Updated on: {{ blog.update_date }}</h6></i>
</div>
<div class = "col-sm-6">
<img src = "/media/{{ blog.blog_image }}" width = "100%">
</div>
<p>{{ blog.blog_content|linebreaks }}</p>
</div>
{% endblock %}

You should not slugify things yourself. Django has the slugify(…) function [Django-doc] for this:
from django.utils.text import slugify
# …
blog_obj.slug = f'{slugify(title)}-{uuid.uuid4()}
blog_obj.save()
This function normally guarantees that the outcome is a valid slug. It will:
strip diacritics;
convert it to lowercase;
remove symbols; and
join the groups with a hyphen (-).

Related

Django form fields required and optional configuration

I am in a middle of a project. I have a model :-
class CustomersModels(models.Model):
def servChoices(servs):
lst = [x.serv_name for x in servs]
ch =()
for a in lst:
ch += (a,a),
return ch
customer_name = models.CharField(max_length=100)
comp_name = models.CharField(max_length=100)
ph_no = models.CharField(max_length=12)
webs_name = models.URLField(max_length=200)
service_insterested = models.OneToOneField(ServiceModel, on_delete = models.CASCADE)
def __str__(self):
return self.customer_name
I have a corresponding form for this model.
Now what i want is the fields customer_name, comp_name, webs_name
to be optional in one page. And required in another page.
Please guide me to establish the task in the most convenient manner
Deleted in 'def servChoices', service_insterested because I don't have access to them in the model. I also made it to return a string with the name of the class return 'CustomersModels', so that you can edit, delete records with empty values.
The field class 'customer_name', 'comp_name' ,'webs_name' are set to blank=True to make them optional.
In the NoForm, the required field is 'ph_no'. YesForm requires all fields to be filled in. For this, a validator (clean) is used, which will display a message on the page which field is not filled in (the form will not be sent until all fields are filled). You can read about clean here:
In the bboard views, replace with your folder where you have the templates (this is the string template_name = 'bboard/templ_yes.html').
urls.py
urlpatterns = [
path('yes/', YesCreateView.as_view(), name='yes'),
path('no/', NoCreateView.as_view(), name='no'),
]
views.py
from django.views.generic.edit import CreateView
from django.urls import reverse_lazy
from .forms import NoForm, YesForm
class NoCreateView(CreateView):
template_name = 'bboard/templ_no.html'
form_class = NoForm
success_url = reverse_lazy('no')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
return context
class YesCreateView(CreateView):
template_name = 'bboard/templ_yes.html'
form_class = YesForm
success_url = reverse_lazy('yes')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
return context
forms.py
from django.forms import ModelForm
from .models import CustomersModels
from django.core.exceptions import ValidationError
class YesForm(ModelForm):
class Meta:
model = CustomersModels
fields = ('customer_name', 'comp_name', 'ph_no', 'webs_name')
def clean(self):
cleaned_data = super().clean()
customer_name = cleaned_data.get('customer_name')
comp_name = cleaned_data.get('comp_name')
webs_name = cleaned_data.get('webs_name')
if len(customer_name) <= 0 or customer_name == '':
raise ValidationError(
"fill in the field customer_name"
)
if len(comp_name) <= 0 or comp_name == '':
raise ValidationError(
"fill in the field comp_name"
)
if len(webs_name) <= 0 or webs_name == '':
raise ValidationError(
"fill in the field webs_name"
)
class NoForm(ModelForm):
class Meta:
model = CustomersModels
fields = ('customer_name', 'comp_name', 'ph_no', 'webs_name')
models.py
class CustomersModels(models.Model):
customer_name = models.CharField(max_length=100, blank=True)
comp_name = models.CharField(max_length=100, blank=True)
ph_no = models.CharField(max_length=12)
webs_name = models.URLField(max_length=200, blank=True)
def __str__(self):
return 'CustomersModels'
tepmplate(templ_yes.html)
<h2>form</h2>
<form method="post" action="{% url 'yes'%}">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="adding">
</form>
tepmplate(templ_no.html)
<h2>form</h2>
<form method="post" action="{% url 'no'%}">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="adding">
</form>

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

cannot accès to my Model Data base from views.py

I m learning Django 2.2, I am trying to a model from named sKills base on a parent model named Profile:
But I have this error :
DoesNotExist at /skills/
Profile matching query does not exist.
Request Method: GET
Request URL: http://127.0.0.1:8080/skills/
Django Version: 2.2
Exception Type: DoesNotExist
Exception Value:
Profile matching query does not exist.
in Skills => models.py:
from django.db import models
from profiles.models import Profile
from django.core.validators import MaxValueValidator, MinValueValidator
# Create your models here.
class Skill(models.Model):
user = models.ForeignKey(Profile, on_delete=models.CASCADE)
name = models.CharField(max_length=220)
score = models.PositiveIntegerField(
validators=[MinValueValidator(1), MaxValueValidator(5)])
def __str__(self):
return "{}-{}-{}".format(self.user, self.name, self.score)
in Skills => Views.py:
# Create your views here.
def skill_view(request):
user_id = request.user.id
profile = Profile.objects.get(pk=user_id)
#profile = get_object_or_404(Profile, pk=user_id)
SkillFormset = inlineformset_factory(Profile, Skill,fields='__all__',extra=1)
formset = SkillFormset( instance=profile)
context = {
'formset': formset
}
return render(request,'skills/add.html',context)
In Skills => urls.py:
app_name = 'skills'
urlpatterns = [
path('', skill_view, name='my-skills'),
]
In Skills => templates =>skills => add.html:
{% extends 'base.html' %}
{% block title %}my skills{% endblock title %}
{% block content %}
<form action="" method="POST">
{{formset}}
</form>
{% endblock content %}
In Profile => Models:
from django.db import models
from django.contrib.auth.models import User
from django.core.validators import FileExtensionValidator
# Create your models here.
class Profile(models.Model):
name = models.ForeignKey(User, on_delete=models.CASCADE)
website = models.URLField(blank=True)
avatar = models.ImageField(upload_to='uploads/img', validators=[FileExtensionValidator(allowed_extensions=['png'])], blank=True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
#property
def get_created(self):
return self.created.strftime("%m/%d/%Y, %H:%M:%S")
def __str__(self):
return "{}-{}".format(self.name, self.get_created)
I have Profile user in database I do not understand:
Thanks for your help
As you are looking up on pk against User id which is not right as you don't have made the name field as primary_key=True or inherited from User model itself. You have to look up on name field of profile
profile = Profile.objects.get(name_id=user_id)
You can set name as primary key like this:
name = models.ForeignKey(User, on_delete=models.CASCADE, primary_key=True)
and then you can look up on pk:
profile = Profile.objects.get(pk=user_id)

Multiple file uploads not working in Form Wizard Django

I am working on a project that requires an upload of multiple images in one of the form wizard steps. The form wizard also has several models used for the wizard which I think complicates the whole process the more. Here is the relevant code:
models.py
from django.db import models
from django.contrib.auth.models import User
from location_field.models.plain import PlainLocationField
from PIL import Image
from django.core.validators import MaxValueValidator, MinValueValidator
from listing_admin_data.models import (Service, SubscriptionType, PropertySubCategory,
PropertyFeatures, VehicleModel, VehicleBodyType, VehicleFuelType,
VehicleColour, VehicleFeatures, BusinessAmenities, Currency
)
class Listing(models.Model):
listing_type_choices = [('P', 'Property'), ('V', 'Vehicle'), ('B', 'Business/Service'), ('E', 'Events')]
listing_title = models.CharField(max_length=255)
listing_type = models.CharField(choices=listing_type_choices, max_length=1, default='P')
status = models.BooleanField(default=False)
featured = models.BooleanField(default=False)
city = models.CharField(max_length=255, blank=True)
location = PlainLocationField(based_fields=['city'], zoom=7, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
expires_on = models.DateTimeField(auto_now=True)
created_by = models.ForeignKey(User,
on_delete=models.CASCADE, editable=False, null=True, blank=True
)
listing_owner = models.ForeignKey(User,
on_delete=models.CASCADE, related_name='list_owner'
)
def __str__(self):
return self.listing_title
def get_image_filename(instance, filename):
title = instance.listing.listing_title
slug = slugify(title)
return "listings_pics/%s-%s" % (slug, filename)
class ListingImages(models.Model):
listing = models.ForeignKey(Listing, on_delete=models.CASCADE)
image_url = models.ImageField(upload_to=get_image_filename,
verbose_name='Listing Images')
main_image = models.BooleanField(default=False)
class Meta:
verbose_name_plural = "Listing Images"
def __str__(self):
return f'{self.listing.listing_title} Image'
class Subscriptions(models.Model):
subscription_type = models.ForeignKey(SubscriptionType, on_delete=models.CASCADE)
subscription_date = models.DateTimeField(auto_now_add=True)
subscription_amount = models.DecimalField(max_digits=6, decimal_places=2)
subscribed_by = models.ForeignKey(User, on_delete=models.CASCADE)
duration = models.PositiveIntegerField(default=0)
listing_subscription = models.ManyToManyField(Listing)
updated_at = models.DateTimeField(auto_now=True)
status = models.BooleanField(default=False)
class Meta:
verbose_name_plural = "Subscriptions"
def __str__(self):
return f'{self.listing.listing_title} Subscription'
class Property(models.Model):
sale_hire_choices = [('S', 'Sale'), ('R', 'Rent')]
fully_furnished_choices = [('Y', 'Yes'), ('N', 'No')]
listing = models.OneToOneField(Listing, on_delete=models.CASCADE)
sub_category = models.ForeignKey(PropertySubCategory, on_delete=models.CASCADE)
for_sale_rent = models.CharField(choices=sale_hire_choices, max_length=1, default=None)
bedrooms = models.PositiveIntegerField(default=0)
bathrooms = models.PositiveIntegerField(default=0)
rooms = models.PositiveIntegerField(default=0)
land_size = models.DecimalField(max_digits=10, decimal_places=2)
available_from = models.DateField()
car_spaces = models.PositiveIntegerField(default=0)
fully_furnished = models.CharField(choices=fully_furnished_choices, max_length=1, default=None)
desc = models.TextField()
property_features = models.ManyToManyField(PropertyFeatures)
price = models.DecimalField(max_digits=15, decimal_places=2)
currency = models.ForeignKey(Currency, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
verbose_name_plural = "Properties"
def __str__(self):
return f'{self.listing.listing_title}'
The forms for this app is as follows:
forms.py
from django import forms
from .models import Listing, Property, Vehicle, Business, ListingImages
class ListingDetails(forms.ModelForm):
class Meta:
model = Listing
fields = ['listing_title', 'city', 'location']
class PropertyDetails1(forms.ModelForm):
class Meta:
model = Property
fields = ['sub_category', 'for_sale_rent', 'bedrooms', 'bathrooms',
'rooms', 'land_size', 'available_from', 'car_spaces', 'fully_furnished',
'desc', 'currency', 'price'
]
class PropertyDetails2(forms.ModelForm):
class Meta:
model = Property
fields = ['property_features']
class ListingImagesForm(forms.ModelForm):
class Meta:
model = ListingImages
fields = ['image_url']
The view that handles all this, though not yet complete as I am still researching on the best way to save the data to the database is as shown below:
views.py
from django.shortcuts import render
import os
from .forms import ListingDetails, PropertyDetails1, PropertyDetails2, ListingImagesForm
from .models import ListingImages
from formtools.wizard.views import SessionWizardView
from django.conf import settings
from django.core.files.storage import FileSystemStorage
from django.forms import modelformset_factory
from django.contrib import messages
from django.http import HttpResponseRedirect
class PropertyView(SessionWizardView):
ImageFormSet = modelformset_factory(ListingImages, form=ListingImagesForm, extra=3)
template_name = "listings/create_property.html"
formset = ImageFormSet(queryset=Images.objects.none())
form_list = [ListingDetails, PropertyDetails1, PropertyDetails2, ListingImagesForm]
file_storage = FileSystemStorage(location=os.path.join(settings.MEDIA_ROOT, 'media'))
def done(self, form_list, **kwargs):
return render(self.request, 'done.html', {
'form_data': [form.cleaned_data for form in form_list],
})
The template that is used to handle the form fields is as below:
create_property.py
<p>Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</p>
<form action="" method="post">
{% csrf_token %}
<table>
{{ wizard.management_form }}
{% if wizard.form.forms %}
{{ wizard.form.management_form }}
{% for form in wizard.form.forms %}
{{ form }}
{% endfor %}
{% else %}
{% for field in wizard.form %}
<div class="form-group">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{{ field }}
<span class="message">{{ field.errors }}</span>
</div>
{% endfor %}
{% endif %}
</table>
{% if wizard.steps.prev %}
<div class="d-flex justify-content-around">
<button name="wizard_goto_step" type="submit" class="btn btn-primary" value="{{ wizard.steps.first }}">First Step</button>
<button name="wizard_goto_step" type="submit" class="btn btn-primary" value="{{ wizard.steps.prev }}">Previous Step</button>
</div>
{% endif %}
<div class="d-flex justify-content-end col-12 mb-30 pl-15 pr-15">
<input type="submit" value="{% trans "submit" %}"/>
</div>
</form>
I have tried to attach all the relevant information for this to work.
The main problem I am facing is that the template doesn't give room for multiple uploads, and again, after I attach a single file that is provided and try to submit, I get a field cannot be empty error message.
I am still new to Django and trying to learn as I code, but so far, not much has been documented about the form wizard and the multiple image upload issues. Most of the posts available appear to be shoddy and only uses the contact form which does not store any details on the database.
The solution is from this Project
MultipleUpload.py
from django import forms
FILE_INPUT_CONTRADICTION = object()
class ClearableMultipleFilesInput(forms.ClearableFileInput):
# Taken from:
# https://stackoverflow.com/questions/46318587/django-uploading-multiple-files-list-of-files-needed-in-cleaned-datafile#answer-46409022
def value_from_datadict(self, data, files, name):
upload = files.getlist(name) # files.get(name) in Django source
if not self.is_required and forms.CheckboxInput().value_from_datadict(
data, files, self.clear_checkbox_name(name)):
if upload:
# If the user contradicts themselves (uploads a new file AND
# checks the "clear" checkbox), we return a unique marker
# objects that FileField will turn into a ValidationError.
return FILE_INPUT_CONTRADICTION
# False signals to clear any existing value, as opposed to just None
return False
return upload
class MultipleFilesField(forms.FileField):
# Taken from:
# https://stackoverflow.com/questions/46318587/django-uploading-multiple-files-list-of-files-needed-in-cleaned-datafile#answer-46409022
widget = ClearableMultipleFilesInput
def clean(self, data, initial=None):
# If the widget got contradictory inputs, we raise a validation error
if data is FILE_INPUT_CONTRADICTION:
raise forms.ValidationError(self.error_message['contradiction'], code='contradiction')
# False means the field value should be cleared; further validation is
# not needed.
if data is False:
if not self.required:
return False
# If the field is required, clearing is not possible (the widg et
# shouldn't return False data in that case anyway). False is not
# in self.empty_value; if a False value makes it this far
# it should be validated from here on out as None (so it will be
# caught by the required check).
data = None
if not data and initial:
return initial
return data
enter code here
from django.core.files.uploadedfile import UploadedFile
from django.utils import six
from django.utils.datastructures import MultiValueDict
from formtools.wizard.storage.exceptions import NoFileStorageConfigured
from formtools.wizard.storage.base import BaseStorage
class MultiFileSessionStorage(BaseStorage):
"""
Custom session storage to handle multiple files upload.
"""
storage_name = '{}.{}'.format(__name__, 'MultiFileSessionStorage')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.prefix not in self.request.session:
self.init_data()
################################################################################################
# Helper
################################################################################################
def _get_data(self):
self.request.session.modified = True
return self.request.session[self.prefix]
def _set_data(self, value):
self.request.session[self.prefix] = value
self.request.session.modified = True
data = property(_get_data, _set_data)
################################################################################################
# formtools.wizard.storage.base.BaseStorage API overrides
################################################################################################
def reset(self):
# Store unused temporary file names in order to delete them
# at the end of the response cycle through a callback attached in
# `update_response`.
wizard_files = self.data[self.step_files_key]
for step_files in six.itervalues(wizard_files):
for file_list in six.itervalues(step_files):
for step_file in file_list:
self._tmp_files.append(step_file['tmp_name'])
self.init_data()
def get_step_files(self, step):
wizard_files = self.data[self.step_files_key].get(step, {})
if wizard_files and not self.file_storage:
raise NoFileStorageConfigured(
"You need to define 'file_storage' in your "
"wizard view in order to handle file uploads.")
files = {}
for field in wizard_files.keys():
files[field] = {}
uploaded_file_list = []
for field_dict in wizard_files.get(field, []):
field_dict = field_dict.copy()
tmp_name = field_dict.pop('tmp_name')
if(step, field, field_dict['name']) not in self._files:
self._files[(step, field, field_dict['name'])] = UploadedFile(
file=self.file_storage.open(tmp_name), **field_dict)
uploaded_file_list.append(self._files[(step, field, field_dict['name'])])
files[field] = uploaded_file_list
return MultiValueDict(files) or MultiValueDict({})
def set_step_files(self, step, files):
if files and not self.file_storage:
raise NoFileStorageConfigured(
"You need to define 'file_storage' in your "
"wizard view in order to handle file uploads.")
if step not in self.data[self.step_files_key]:
self.data[self.step_files_key][step] = {}
for field in files.keys():
self.data[self.step_files_key][step][field] = []
for field_file in files.getlist(field):
tmp_filename = self.file_storage.save(field_file.name, field_file)
file_dict = {
'tmp_name': tmp_filename,
'name': field_file.name,
'content_type': field_file.content_type,
'size': field_file.size,
'charset': field_file.charset
}
self.data[self.step_files_key][step][field].append(file_dict)
form.py
from MultipleUpload import MultipleFilesField, ClearableMultipleFilesInput
class ListingImagesForm(forms.ModelForm):
image_url = MultipleFilesField(widget=ClearableMultipleFilesInput(
attrs={'multiple': True, 'accept':'.jpg,.jpeg,.png'}), label='Files')
class Meta:
model = ListingImages
fields = ['image_url']
views.py
from MultipleUpload import MultiFileSessionStorage
class PropertyView(SessionWizardView):
storage_name = MultiFileSessionStorage.storage_name
ImageFormSet = modelformset_factory(ListingImages, form=ListingImagesForm, extra=3)
template_name = "listings/create_property.html"
formset = ImageFormSet(queryset=Images.objects.none())
form_list = [(....), ('ListingImagesForm',ListingImagesForm)]
file_storage = FileSystemStorage(location=os.path.join(settings.MEDIA_ROOT, 'media'))
def done(self, form_list, **kwargs):
cleaned_data = self.get_cleaned_data_for_step('ListingImagesForm')
for f in cleaned_data.get('image_url',[]):
instance = ListingImages(image_url=f, .....)
instance.save()
return render(self.request, 'done.html', {
'form_data': [form.cleaned_data for form in form_list],
})

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()