I have these models:
class BlogCategory(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return self.name
def get_number_of_categorys_items(self):
return self.post_set.count()
class Post(models.Model):
title = models.CharField(max_length=130)
content = models.TextField()
category = models.ForeignKey(BlogCategory, related_name='blog_category')
def __str__(self):
return self.title
And when I try to call method get_number_of_categorys_items it cause error:
AttributeError: 'BlogCategory' object has no attribute 'post_set'
This method should return number of posts with this category.
What can I do?
Since you've specified the related_name, Django would not automatically create the related name as post_set for you. Either use:
def get_number_of_categorys_items(self):
return self.blog_category.count()
Or, don't specify the related_name:
category = models.ForeignKey(BlogCategory)
Related
you need to get the filter using the get_related_filter class method
views
modelPath = 'Money.models'
app_model = importlib.import_module(modelPath)
cls = getattr(app_model, 'Money')
related_result = cls().get_related_filter(search_query='search_query')
models.py
class Money(models.Model):
money = models.DecimalField(max_digits=19, blank=True, default=0, decimal_places=2)
def get_related_filter(self, **kwargs):
results = super(Money, self).objects.filter(Q(money__icontains=kwargs['search_query']))
return results
def __str__(self):
return self.money
why gives 'super' object has no attribute 'objects' Python Django, and does not return filter
It makes no sense to work with super(Money, self) for two reasons:
this proxy object will resolve to Model, but Model nor it parents have an objects attribute; and
even if that was the case, you can only access .objects on a model class, not the instance.
You thus can filter with:
class Money(models.Model):
money = models.DecimalField(max_digits=19, blank=True, default=0, decimal_places=2)
def get_related_filter(self, search_query, **kwargs):
return Money.objects.filter(money__icontains=search_query)
def __str__(self):
return str(self.money)
The __str__ is also supposed to return a string, not a decimal, so you should return str(self.money), not self.money.
I am running a django app and have a setup like this:
ModelSuper(models.Model):
class Meta:
abstract = False
ModelSub1(ModelA):
name = models.CharField(...)
def __str__:
return self.name
ModelSub2(ModelA)
name = models.CharField(...)
def __str__:
return self.name
ModelForeign(models.Model):
element = models.ForeignKey(ModelA)
def __str__:
return self.name
So ModelForeign has a FK to ModelSuper. What happens now is that when I create an instance of ModelForeign I can choose if it belongs either to ModelSub1 or to ModelSub2. But the string representation is ModelSuper Onject (3) where (3) is the id.
Normally I can change this representation by overwriting the __str__ method on the model, but since I do not have any fields on the Supermodel I can't return anything.
What I tried:
I have already implemented the __str__ method in the Submodels but that does not help.
I wanted to make the Super model abstract. But this does not let me point FKs to the Supermodel, so I can't do this. My setup requires this FK
I used a generic FK with django's ContentType framework. This is also not an option because it messes completely with my app and is also not recommended from an SQL perspective.
Also when I do API-calls I get ModelSuper Onject (3) back instead of a human-readable name.
Is there a way to do what I intend to do? Thanks in advance for help and hints. Very much appreciated!
EDIT1: What I tried thanks to Abdul's help:
class ModelA(models.Model):
class Meta:
abstract = False
TYPE_CHOICES = [('sub1', 'sub1'), ('sub2', 'sub2')]
type_model = models.CharField(max_length=50, choices=TYPE_CHOICES, null=True, blank=True)
def __str__(self):
if self.type_model == "sub1":
return "sub1"
elif self.type_model == "sub2":
return "sub2"
else:
return "unkown"
I am not understanding how your foreign key works as model inheritance means the tables are separate. How about trying something like this:-
ModelA(models.Model):
TYPE_CHOICES = [('Sub1', 'ModelSub1'), ('Sub2', 'ModelSub2')]
model_type = models.CharField(max_length=4, choices=TYPE_CHOICES)
def __str__:
# Return string representation using if-else
class Meta:
abstract = False
ModelSub1(ModelA):
name = models.CharField(...)
model_a = models.ForeignKey(ModelA, on_delete=models.CASCADE)
def __str__:
return self.name
ModelSub2(ModelA)
name = models.CharField(...)
model_a = models.ForeignKey(ModelA, on_delete=models.CASCADE)
def __str__:
return self.name
ModelForeign(models.Model):
element = models.ForeignKey(ModelA)
def __str__:
return self.name
I want my model object to always return the image.url of field image.
My model:
class Content(models.Model):
...
avatar = models.ImageField(upload_to=file, blank=True, null=True)
I want something like:
class Content(models.Model):
...
def get_avatar(self): # some default func for returning fields
return self.avatar.url
It have to work like this, When I get the object:
content = Content.objects.get(pk=1)
print(content.avatar)
And it should print the path:
/media/uploads/dsadsadsa.jpg
Briefly, I want something that will change the return of model field.
You could add a property to your model like this, notice I added an underscore to the field name:
class Content(models.Model):
...
_avatar = models.ImageField(upload_to=file, blank=True, null=True)
#property
def avatar(self):
return self._avatar.url
Now you can do:
print(content.avatar)
Use __str__() method
class Content(models.Model):
...
avatar = models.ImageField(upload_to=file, blank=True, null=True)
def __str__(self):
try:
return self.avatar.url
except AttributeError: # "self.avatar" may be None
return "no avatar"
UPDATE-1
I think, the #propert may suite you
class Content(models.Model):
...
avatar = models.ImageField(upload_to=file, blank=True, null=True)
#property
def avatar_url(self):
try:
return self.avatar.url
except AttributeError: # "self.avatar" may be None
return "no avatar"
Now, you could access the url as,
print(content.avatar_url)
How can I can use managers to query my foreign key and then retrieve objects that are connected to foreign key?
Here is my models.py:
from django.db import models
# Create your models here.
class BookManager(models.Manager):
def title_count(self,keyword):
return self.filter(title__icontains=keyword).count()
class CategoryManager(models.Manager):
def category_count(self):
return self.filter(category__icontains=python).count()
class Category(models.Model):
title=models.CharField(max_length=20)
def __str__(self):
return self.title
class Enquiry(models.Model):
title=models.CharField(max_length=200)
category=models.ForeignKey(Category ,default=False,blank=False)
detail=models.TextField()
objects = BookManager()
objects=CategoryManager()
# tags=models.ChoiceField()
def __str__(self):
return self.title
I tried to use category manager but it gave me a strange error.
I just want to know how exactly we can get the objects that are connected with category foriegn-key and show them as list to the users.
You can combine both the title_count and category_count methods under one Manager. When filtering through a ForeignKey, your field lookup needs to specify the name of the field you're trying to filter on, else it will assume you're querying the ID field. So instead of category__icontains, you would do category__title__icontains.
Another note, in newer versions of Django, you are required to specify the on_delete parameter when defining a ForeignKey.
This is a working example of what I think you're trying to accomplish.
class BookManager(models.Manager):
def title_count(self, keyword):
return self.filter(title__icontains=keyword).count()
def category_count(self, keyword):
return self.filter(category__title__icontains=keyword).count()
class Category(models.Model):
title = models.CharField(max_length=20)
def __str__(self):
return self.title
class Enquiry(models.Model):
title = models.CharField(max_length=200)
category = models.ForeignKey(Category,
default=False,
blank=False,
on_delete=models.CASCADE)
detail = models.TextField()
books = BookManager()
# tags=models.ChoiceField()
def __str__(self):
return self.title
Here's how you would use it:
Enquiry.books.category_count('python')
Enquiry.books.title_count('test')
I have a class as
class PlaylistManager(models.Manager):
def add_playlist(self, name):
playlist = Playlist(name=name)
playlist.save()
return playlist
def get_playlist_with_id(self, id):
return super(PlaylistManager, self).get_query_set().filter(pk=id)
class Playlist(models.Model):
name = models.CharField(max_length=30)
date_created = models.DateTimeField(auto_now_add=True)
date_modified = models.DateTimeField(auto_now=True)
deleted = models.BooleanField(default=False)
objects = PlaylistManager() # is a customer manager
def __repr__(self):
return '<Playlist name:%s, date_created:%s, date_modified:%s, deleted:%s>' % \
(self.name, self.date_created, self.date_modified, self.deleted)
class Meta:
db_table = 'playlists'
and i test as
def test_get_playlist(self):
playlist = Utility.add_playlist()
self.assertEqual(Playlist.objects.get_playlist_with_id(playlist.id), playlist)
class Utility():
#staticmethod
def add_playlist(playlist_name=PLAYLIST):
return Playlist.objects.add_playlist(playlist_name)
When I run the test, I see error as
AssertionError: [<Playlist name:playlist, date_created:2012-07-18 19:54:12.265909+00:00, date_modified:2012-07-18 19:54:12.265955+00:00, deleted:False>] != <Playlist name:playlist, date_created:2012-07-18 19:54:12.265909+00:00, date_modified:2012-07-18 19:54:12.265955+00:00, deleted:False>
even when the two objects are same.
Is there anything I am missing here?
assertEqual() uses the == operator to compare the classes. The default == operator of user-defined classes compares instances by object identity. This means two instances are only considered equal when they are the same instance.
Compare model id or pk and it will be ok.
The AssertionError is correct. Your get_playlist_with_id returns a Queryset not a Playlist instance. If you want get_playlist_with_id to return the single instance then you should use get not filter.