Django View/Model Attribute Error - python

I'm new to Django and I'm in the process of converting a PHP project into Python etc.
I'm trying to do something super simple, but I keep getting the following error:
AttributeError at /news/1/
'QuerySet' object has no attribute 'slug'
Here is my most of my Model to help explain:
class Article(models.Model):
title = models.CharField(max_length=200)
STATUS_CHOICES = ((1,'Published'), (2,'Hidden'), (3,'Draft'))
status = models.IntegerField(choices=STATUS_CHOICES,default=3)
pub_date = models.DateField('date published')
tags = TaggableManager()
header_width = models.IntegerField(default=1,blank=True,null=True)
header_height = models.IntegerField(default=1,blank=True,null=True)
header = models.ImageField(upload_to='news/',width_field='header_width',height_field='header_height',blank=True,null=True)
header_filter = models.BooleanField('Enable filter',default=1)
excerpt = HTMLField(blank=True)
body = HTMLField(blank=True)
custom_link_text = models.CharField(max_length=20,default="Read More")
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
slug = AutoSlugField(unique=True,max_length=200,populate_from='db_slug',default="",slugify=return_value)
def __str__(self):
return self.title
Im currently just testing to pull through the slug, so my view method currently looks like this:
def detail_redirect(request, pk):
a = Article.objects.all().filter(pk=pk)
return HttpResponse(a.slug)
# return redirect('news:detail',args=(a.slug,pk))
The plan is for this method to redirect to another URL in my application. It queries the DB via the primary key and fetches the Slug, which I then pass on to the redirect shortcut.
It seems to be something that should just work, but it's not. It's really frustrating. The object i query appears to return ok. Because of my __str__ method it returns the title. But any other attributes throw and error. Could it be todo with visibility such as being private or protected?
I'm hoping it's something simple I'm missing. Let me know if you require more code/detail to help explain.
Thanks for taking the time to look at my question.

filter always returns a queryset, which is a list-like object potentially consisting of many items. Querysets do not have model attributes, only their members do. You should use get instead:
a = Article.objects.get(pk=pk)
(Note you don't need all(), in either version of the code.)

Related

How to make Django queries with associated tables?

I'm trying to create a 'saved post' feature on a website. I'm struggling with how to create a query that I can use to populate my HTML template with posts.
Here are my models:
class User(AbstractUser):
pass
class Post(models.Model):
title = models.CharField(max_length=200)
description = models.CharField(max_length=500)
class SavedPost(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE)
user = models.ForeignKey (User, on_delete=models.CASCADE, null=True)
My .views looks like this
def savedpostsview(request):
posts = Post.objects.all
savedposts = posts.savedpost_set(user = request.user)
return render(request, "posts/savedposts.html",{
'savedposts': savedposts
})
Right now I'm getting the error "'function' object has no attribute 'savedpost_set'".
I know I'm getting something wrong syntactically, but I've been reading documentation forever and can't figure out what it is for the life of me. Does anybody have any insight into what I'm doing wrong?
first of all here Post.objects.all all() is a function and thats why error is "'function' object has no attribute 'savedpost_set'"
You should call Post.objects.all() this will return queryset.
Then You are trying to reverse query on queryset which not possible and will throw error.
All you want is this Post.objects.filter(savedpost__user=request.user)

Get record from master table if alteast one record exists in slave/child tables using django api

To elaborate
e.g.
I have two models "Subject" and "Question"
class Subject(models.Model):
title = models.CharField(max_length=200,unique=True)
is_active = models.BooleanField(default=True)
def __str__(self):
return self.title
class Question(models.Model):
title = models.CharField(max_length=500)
is_active = models.BooleanField(default=True)
subject = models.ForeignKey('Subject')
def __str__(self):
return self.title
I want the list of active subjects having at least one active question.
I have done initial search and also checked django queryset api, but did not got answer.
I am not looking for raw sql query option.
I hope this clears the query. I have tried django api, but did not get expected result. I think this is very obvious query and there should be simple answer to it.
Thanks in advance for any help.
Did you try this?
Subject.objects.filter(question__id__isnull=False).distinct()
You might even be able to simplify it to the following, but I'm too lazy to look up if it's correct or try it out:
Subject.objects.filter(question__isnull=False).distinct()

DJANGO - Queryset and model design

So I've been stuck with a design problem for the last couple of days and have sunk countless hours into it, to no avail.
My problem is that I wish return all the active Articles. I have made a method within the model, however am unable to use .filter(is_active=True)which would be the worlds best solution.
So now I have made the method into one long filter in the ArticleManager, the problem being that I cannot seem to figure out a way to count the current clicks in a way that can be useful to me. (The current_clicks method in the Article model is what I am aiming for).
Models.py
class ArticleManager(models.Manager):
def get_queryset(self):
return super(ArticleManager, self).get_queryset().filter(article_finish_date=None).filter(article_publish_date__lte=timezone.now())
#this is where i need something to the effect of .filter(article_max_clicks__gt=click_set.count())
class Article(models.Model):
article_name_text = models.CharField(max_length=200)
article_max_clicks = models.IntegerField(default=0)
article_creation_date = models.DateTimeField('date created')
article_publish_date = models.DateTimeField('date published', null=True, blank=True)
article_finish_date = models.DateTimeField('date finished', null=True, blank=True)
def __str__(self):
return self.article_name_text
def is_active(self):
if self.article_finish_date==None:
if self.article_publish_date <= timezone.now():
return self.current_clicks() < self.article_max_clicks
else:
return False
else:
return False
def current_clicks(self):
return self.click_set.count()
is_active.boolean = True
actives = ArticleManager()
class Click(models.Model):
click_article = models.ForeignKey(Article, on_delete=models.CASCADE)
click_user = models.ForeignKey(User, on_delete=models.CASCADE)
click_date = models.DateTimeField('date clicked')
def __str__(self):
return str(self.id) + " " + str(self.click_date)
This is how the clicks are created in views.py if this helps
article.click_set.create(click_article=article, click_user=user, click_date=timezone.now())
If anyone has any sort of idea of how abouts I should do this it would be greatly appreciated!
Many thanks in advance, just let me know if you need anymore information!
Django's annotate functionality is great for adding properties at the time of querying. From the docs -
Per-object summaries can be generated using the annotate() clause. When an annotate() clause is specified, each object in the QuerySet will be annotated with the specified values.
In order to keep your querying performance-minded, you can use this in your manager and not make the (possibly very slow) call of related objects for each of your Articles. Once you have an annotated property, you can use it in your query. Since Django only executes your query when objects are called, you can use this annotation instead of counting the click_set, which would call a separate query per related item. The current_clicks method may still be useful to you, but if calling it for multiple articles your queries will add up quickly and cause a big performance hit.
Please note - I added a related_name of clicks keyword arg to your click_article field in order to use it in place of 'click_set'.
In addition, you'll see the use of Q objects in the query below. What this allows us to do is chain together multiple filters together. These can be nested while using AND (,) / OR(|) operands. So, a reading of the Q objects below would be:
Find all articles where article publish date is before now AND (article has no finish date OR article finish date is after now)
from django.db.models.query import Q,Count
class ArticleManager(models.Manager):
def get_queryset(self):
return super(ArticleManager, self).get_queryset().filter(
Q(article_publish_date__lte=timezone.now()),
( Q(article_finish_date__isnull=True)|
Q(article_finish_date__gte=timezone.now())
).annotate(
click_count=Count('clicks')
).filter(
article_max_clicks__gt=click_count
)
class Article(models.Model):
actives = ArticleManager()
def current_clicks(self):
return self.clicks.count()
# Now you can call Article.actives.all() to get all active articles
class Click(models.Model):
click_article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='clicks') # added a related_name for more explicit calling of prefetch_related

Different serializers for serializing/deserializing using Django REST framework

I've got a model with a recursive relationship to itself:
class Tweet(models.Model):
text = models.CharField(max_length=140)
original = models.ForeignKey("self", null=True, blank=True)
And a serializer that renders the original Tweet inline:
class TweetSerializer(serializers.ModelSerializer):
class Meta:
model = Tweet
fields = ('id', 'text', 'original', 'original_id')
original_id = serializers.IntegerField(source='original_id', required=False)
def to_native(self, obj):
ret = super(TweetSerializer, self).to_native(obj)
del ret['original_id']
return ret
TweetSerializer.base_fields['original'] = TweetSerializer(source='original', read_only=True)
As you can see I've also got an original_id field that is removed in to_native. The purpose of original_id is to allow me to set the original_id of a new tweet, rather than having to supply a full blown Tweed object to the original field. You could say that I'm using it as a write only field.
This seems a bit clunky though. Is there a better way to do it?
OK, two points:
Have you tried using PrimaryKeyRelatedField for your original_id? It would seem to target your use-case specifically. Combined with the depth option it may give you everything you need.
You can switch serializers (e.g. based on request method) by overriding get_serializer_class() on your view. Not sure if you'll get the exact behaviour you want here though.

Django model manager didn't work with related object when I do aggregated query

I'm having trouble doing an aggregation query on a many-to-many related field.
Here are my models:
class SortedTagManager(models.Manager):
use_for_related_fields = True
def get_query_set(self):
orig_query_set = super(SortedTagManager, self).get_query_set()
# FIXME `used` is wrongly counted
return orig_query_set.distinct().annotate(
used=models.Count('users')).order_by('-used')
class Tag(models.Model):
content = models.CharField(max_length=32, unique=True)
creator = models.ForeignKey(User, related_name='tags_i_created')
users = models.ManyToManyField(User, through='TaggedNote',
related_name='tags_i_used')
objects_sorted_by_used = SortedTagManager()
class TaggedNote(models.Model):
"""Association table of both (Tag , Note) and (Tag, User)"""
note = models.ForeignKey(Note) # Note is what's tagged in my app
tag = models.ForeignKey(Tag)
tagged_by = models.ForeignKey(User)
class Meta:
unique_together = (('note', 'tag'),)
However, the value of the aggregated field used is only correct when the model is queried directly:
for t in Tag.objects.all(): print t.used # this works correctly
for t in user.tags_i_used.all(): print t.used #prints n^2 when it should give n
Would you please tell me what's wrong with it? Thanks in advance.
I have figured out what's wrong and how to fix it now :)
As stated in the Django doc:
Django interprets the first Manager defined in a class as the "default" Manager, and several parts of Django will use that Manager exclusively for that model.
In my case, I should make sure that SortedTagManager is the first Manager defined.
2.I should have count notes instead of users:
Count('notes', distinct=True)

Categories