Does ArchiveIndexView inherit make_object_list? - django-views

Django 1.8.0
This is an example from Django Unleashed by Andrew Pinkham:
class PostList(ArchiveIndexView):
allow_empty = True
allow_future = True
context_object_name = 'post_list'
date_field = 'pub_date'
make_object_list = True
model = Post
paginate_by = 5
template_name = 'blog/post_list.html'
This is address from their GitHub:
https://github.com/jambonrose/DjangoUnleashed-1.8/blob/c5ead7f5f3/blog/views.py
Could you help me understand the expression make_object_list = True.
First of all, I tried to dig the inheritance chain of ArchiveIndexView. Secondly, I just commented it out and looked at the result. The result didn't change.
Well, I suppose, it is a mistake in the book. But maybe I'm wrong.
Could you help me understand for ArchiveIndexView in what base class or a mixin that make_object_list is defined?

Related

DRF Reverse Relationship Unable to Filter in Serializer

Having an interesting problem with DRF and wondering if anyone has any ideas.
For a simplified example, take these two Django models:
class Vote(models.Model):
user_who_voted = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
vote = models.IntegerField(choices = [(-1, "down"), (1, "up")])
timestamp_voted = models.DateTimeField(auto_now = True)
sample_model = models.ForeignKey('SampleModel', on_delete=models.CASCADE, related_name = 'sample_model_votes')
class Meta:
constraints = [models.UniqueConstraint(fields=['user_who_voted', 'sample_model_id'], name='one_vote_pp_sample_model')]
class SampleModel (models.Model):
#does some stuff
In serializing SampleModel, I want to be able to get the value for vote for the request user (of which there is guaranteed to only be one vote, if any).
In a Django shell, I can pull an instance/item of SampleModel easily:
samplemodelexample = SampleModel.objects.get(pk = 1)
and then I can traverse the reverse relationship to Vote successfully to return the vote value:
samplemodelexample.sample_motel_votes.filter(user_who_voted_id = 1).get().vote
Taking this exact same code (simplified to show relevant portions) into DRF seems to create an issue:
class SampleModelSerializer(serializers.ModelSerializer):
user_vote = serializers.SerializerMethodField()
class Meta:
model = SampleModel
fields = ['user_vote']
read_only_fields = fields
def get_user_vote(self, obj):
try:
vote = obj.sample_model_votes.filter(user_who_voted == self.context['request'].user).get().vote #stacktrace on this line
return f"{vote}"
except:
traceback.print_exc()
return '0'
I get an error on the line indicated that NameError: name 'user_who_voted' is not defined
Does anyone have any idea why?
As some additional background: in practice, there would of course be many users and many votes, but if I put just one vote in the Vote table, then substituting the line generating the error in SampleModelSerializer with
vote = obj.sample_model_votes.first().vote
returns the correct value for vote.
In summary, this seems to be an issue with .filter() in DRF.
Thanks in advance!
You have two of = in your query. You should have one only:
obj.sample_model_votes.filter(user_who_voted=self.context['request'].user).get().vote
Because you used two, Python is thinking it is comparison and evaluating user_who_voted as a variable. Since you don't have that variable, you have this error.

Django Beginner. How do I update all objects and set a certain field to a value that is a function of another field?

EDIT:
I needed a student_count field in course because I'm supposed to use this model for REST API. If you can tell me how to add fields in serializer without adding to model, I'd take that too.
This is my model:
class Course(models.Model):
student_count = models.PositiveIntegerField(default=0)
students = models.ManyToManyField()
What I try to do is the following but it doesn't work.
Course.objects.update(student_count=F('students__count'))
The following works but it's not ideal
courses = Course.objects.all()
for course in courses:
course.student_count = course.students.count()
course.save()
return Course.objects.all()
Try to add/update your serializer as below,
from django.db.models import Count
class CourseSerializer(serializers.ModelSerializer):
count = serializers.SerializerMethodField(read_only=True)
def get_count(self, model):
return model.students.aggregate(count=Count('id'))['count']
class Meta:
model = Course
fields = ('count',)
You can use aggregation Count() method instead of queryset.count() its more faster. Read this SO post, aggregate(Count()) vs queryset.count()

example template for django rest framework pagination

I am trying to use Django REST framework for the first time and looking at the tutorials there is no template examples, What can I use for template? I tried template_name = 'authorListAjax.html' but I get this response http://imgur.com/fMlyXDN
views.py
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Author
fields = ('subject', 'date', 'time_start')
class AuthorListAll1(ListAPIView):
template_name = 'authorListAjax.html'
queryset = Author.objects.all()
serializer_class = AccountSerializer
paginate_by = 2
paginate_by_param = 'page_size'
max_paginate_by = 100
urls.py
url(r'^ajax/list/$', AuthorListAll1.as_view(), name='ajax_list'),
You need to set a renderer: http://www.django-rest-framework.org/api-guide/renderers#templatehtmlrenderer
This means adding this line (which tells DRF that the response will be HTML, not JSON):
renderer_classes = (TemplateHTMLRenderer,)
Also, you can not set the template name on your view class; the template name belongs to the renderer class. You can either set it directly on the renderer, like this:
TemplateHTMLRenderer.template_name = 'authorListAjax.html'
or you can overwrite the get method and set it there, like this:
return Response({'user': self.object}, template_name='authorListAjax.html')
I recommend you the second way, because the first one sets the template name globally, and it might get you in troubles :)

initialize modelformset with manytomanyfield

All,
I am trying to initialize a modelformset with a manytomanyfield. A catch is that I do not know in advance the name of the manytomanyfield (nor the class it is bound to).
Here are my models and forms:
class Book_model(models.Model):
title = models.CharField(max_length=BIG_STRING)
authors = models.ManyToManyField("Author_model",)
class Author_model(models.Model):
name = models.CharField(max_length=BIG_STRING)
class Book_form(ModelForm):
class Meta:
model = Book_model
class Author_form(ModelForm:
class Meta:
model = Author_model
Author_formset = modelformset_factory(Author_model,form=Author_form)
And elsewhere in my code I am trying to display a Model_form along with an Author_formset. When it comes time to initialize that formset, though, I'm not sure what to do. At that point I know the name of the m2m field ("authors"), the parent model instance (Book_model), the parent form instance (Book_form), and the formset class (Author_formset). I assume that I just need to do something like this:
m2m_field = getattr(book,"authors")
qset = field.filter(<only authors for which there is a m2m relationship from this book>)
formset = Author_formset(queryset=qset)
But, I don't know the right terms to put in the filter.
Any suggestions?
You're on the right track.
book.authors is the queryset of "authors for which there is a m2m from this book". So that is perfectly valid to pass into the formset init.
formset = AuthorFormset(queryset=m2m_field.all())
I think I have solved this.
In theory this is the correct way to do things, as Daniel suggests:
formset = Author_formset(queryset=book.authors.all())
But I can't do that directly, because I am trapped in some generic code that could be called for any model/form/formset. So I'm forced to do this instead:
# these 4 lines are just for clarity's sake
# I don't actually know what these map to in my code
MyModelClass = Book_model
MyFormClass = Book_form
MyFormSetClass = Author_formset
fieldName = "authors"
def DoStuff(model_id=None):
if (model_id):
model = MyModelClass.objects.get(pk=model_id)
else:
model = MyModelClass()
form = MyFormClass(instance=model)
if model.pk:
m2mModels = getattr(model,fieldName)
formset = MyFormSetClass(queryset = m2mModels.all())
else:
m2mModelClass = MyFormSetClass.form.Meta.model
formset = MyFormSetClass(queryset = m2mModelClass.objects.none())
This seems a bit ugly, but it works.

How to put an InlineFormSet into a ModelFormSet in Django?

I'd like to display a number of forms via a ModelFormSet where each one of the forms displays in turn InlineFormSets for all objects connected to the object.
Now I'm not really sure how to provide the instances for each ModelFormSet. I thought about subclassing BaseModelFormSet but I have no clue on where to start and would like to know whether this is possible at all before I go through all the trouble.
Thanks in advance!
I found an article which focuses on the exact problem. It works fine!
http://yergler.net/blog/2009/09/27/nested-formsets-with-django/
For the sake of completeness I copied the code fragments:
class Block(models.Model):
description = models.CharField(max_length=255)
class Building(models.Model):
block = models.ForeignKey(Block)
address = models.CharField(max_length=255)
class Tenant(models.Model):
building = models.ForeignKey(Building)
name = models.CharField(max_length=255)
unit = models.CharField(max_length=255)
form django.forms.models import inlineformset_factory, BaseInlineFormSet
TenantFormset = inlineformset_factory(models.Building, models.Tenant, extra=1)
class BaseBuildingFormset(BaseInlineFormSet):
def add_fields(self, form, index):
# allow the super class to create the fields as usual
super(BaseBuildingFormset, self).add_fields(form, index)
# created the nested formset
try:
instance = self.get_queryset()[index]
pk_value = instance.pk
except IndexError:
instance=None
pk_value = hash(form.prefix)
# store the formset in the .nested property
form.nested = [
TenantFormset(data=self.data,
instance = instance,
prefix = 'TENANTS_%s' % pk_value)]
BuildingFormset = inlineformset_factory(models.Block, models.Building, formset=BaseBuildingFormset, extra=1)
As jnns said, you want to use inlineformset_factory