Django - 'QuerySet' object has no attribute 'künstler_set' - django

I have a relation between an artist and images. I want to show a single artist and his related images. I created two models for artist and image. Inside the image class I made a ForeignKey to artist:
class Artist(models.Model):
profilepic = models.ImageField( blank=True)
surname = models.CharField(max_length=120)
class Image(models.Model):
image = models.ImageField()
relArtist = models.ForeignKey(Artist, null=True, on_delete=models.SET_NULL)
inside my views.py I tried to get the artist by ID (primaryKey) which is working perfectly but it didn't work with the images.
def artistSingle(request, pk):
artist = Artist.objects.filter(id=pk)
images = artist.relArtist_set.all()
return render(request, 'artists/artistSingle.html', {
'artist': artist,
'images': images,
})
If I run the code it throws an error:
'QuerySet' object has no attribute 'relArtist_set'
I dont know how to get the images which rely to the artist. Does someone have a solution?

You should first get your artist with get() method ( filter returns QuerySet)
artist = Artist.objects.get(id=pk)
You should use get and not filter, filter returns QuerySet and it is meant to return multiple artist objects) and your actual artist in this case would be artist = Artist.objects.filter(id=pk)[0]
Default is relatedmodelname_set as documented so:
images = artist.image_set.all()
It can be set to different value by using related_name attribute
relArtist = models.ForeignKey(Artist, null=True, on_delete=models.SET_NULL related_name='images')
images = artist.images.all()

images = Image.objects.filter(relArtist=artist)
Normally, the Artist would not be aware of any images tied to it, so you should check for the images whose artist match the one you have.
However, Django provides a Manager to reverse the foreign key functionality, making the Artist aware of the images tied to it.
images = artist.image_set.all()

Please try the following one. It will resolve your problem.
def artistSingle(request, pk):
artist_queryset = Artist.objects.filter(id=pk)
artist = artist_queryset.first() if artist_queryset.first() else None
try:
images = artist.image_set.all()
except Exception as exp:
images = []
return render(request=request, template_name='artists/artistSingle.html', context={
'artist': artist,
'images': images,
})

Related

Getting a TypeError while trying to make a unique page in Django

I'm making a picture gallery web-app. I want to make some of displayed photos to belong to a specific collection. Each collection is supposed to have its own page that displays all of the pictures that belong to it.
The name of each unique page is supposed to be photo_collection model, which I added to the class Image in models.py. But for some reason, I get TypeError at /projects/sample_collection_name/ - photo_collection() got an unexpected keyword argument 'photo_collection'
No idea what's causing this error. I tried renaming the photo_collection function (it has the same name as my model), but it didn't work.
models.py
class Image(models.Model):
title = models.CharField(max_length=300)
image = models.ImageField(null=True, blank=True, upload_to='images/')
pub_date = models.DateTimeField('Date published', default=timezone.now)
photo_collection = models.CharField('Photo collection', max_length=250, null=True, blank=True)
views.py
def photo_collection(request):
image = Image.objects.all()
return render (request, 'photo_app/collection.html', context={'image': image})
urls.py
urlpatterns = [
#some other patterns here
path('projects/<str:photo_collection>/', views.photo_collection, name='photo_collection'),
]
gallery.html
{% if i.photo_collection != Null %}
{{i.photo_collection}}
{% endif %}
you need to add photo_collection to your view parameters.
it will be like this:
def photo_collection(request, photo_collection):
image = Image.objects.all()
return render (request, 'photo_app/collection.html', context={'image': image})
when ever you add a variable to your url path you need to add that variable to view parameters too.
here is the documentation for this matter:
https://docs.djangoproject.com/en/4.1/topics/http/urls/

How do you create a Django Rest Framework serializer with many to many field?

I have a model(Project) that contains ManyToManyField to another model(Screenshot). I want to create a view inheriting CreateAPIView such that it is able to serialize data for creating an instance of project model including the Screenshot model from the same view.
models.py
class Screenshot(models.Model):
image = models.ImageField(default='screenshots.jpg',upload_to='screenshots')
class Project(models.Model):
team=models.ForeignKey(Team,on_delete=models.CASCADE)
name=models.CharField(max_length=100,null=True,blank=True)
theme = models.ForeignKey(Theme,on_delete=models.CASCADE,null=True,blank=True)
desc=models.TextField()
accepted = models.BooleanField(default=False)
git_url=models.URLField(null=True,blank=True)
youtube_url=models.URLField(null=True,blank=True)
screenshots=models.ManyToManyField(Screenshot)
serializers.py
class ScreenshotCreateSerializer(serializers.ModelSerializer):
class Meta:
model = Screenshot
fields=['image']
class ProjectCreateSerializer(serializers.ModelSerializer):
image_1 = ScreenshotCreateSerializer()
image_2 = ScreenshotCreateSerializer()
image_3 = ScreenshotCreateSerializer()
image_4 = ScreenshotCreateSerializer()
image_5 = ScreenshotCreateSerializer()
class Meta:
model = Project
fields = ['name','theme','desc','git_url','youtube_url','image_1','image_2','image_3','image_4','image_5']
def create(self,validated_data):
try:
image1 = validated_data.pop('image_1')
image2 = validated_data.pop('image_2')
image3 = validated_data.pop('image_3')
image4 = validated_data.pop('image_4')
image5 = validated_data.pop('image_5')
except:
pass
print(validated_data)
test_team_obj = Team.objects.all()[0]
project_obj = Project(**validated_data)
project_obj.team = test_team_obj
project_obj.save()
if (image1):
project_obj.screenshots.create(image=image1.get('image'))
if (image2):
project_obj.screenshots.create(image=image2.get('image'))
if (image3):
project_obj.screenshots.create(image=image3.get('image'))
if (image3):
project_obj.screenshots.create(image=image4.get('image'))
if (image4):
project_obj.screenshots.create(image=image5.get('image'))
return project_obj
The form is displayed as expected with 5 image fields. After submitting the form, the required project instance is created, screenshot instances are created as well and the just created screenshot instances are linked to that just created project instance. Everything runs well. But an error arises saying:
Got AttributeError when attempting to get a value for field image_1 on serializer ProjectCreateSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the Project instance.
Original exception text was: 'Project' object has no attribute 'image_1'.
Regardless of the error, the data is well updated on the database as desired. But the error is what killing me! I even tried to use a single image field instead of 5 and put many=True but it says:
Lists are not currently supported in HTML input

Subquery many-to-many relation in Django 1.9

I have such models:
class Genre(models.Model):
name = models.TextField(null=True, blank=True)
min_age = models.IntegerField(default=0)
max_age = models.IntegerField(default=0)
objects = GenreManager()
class Meta:
get_latest_by = 'id'
class Book(models.Model):
name = models.TextField(null=True, blank=True)
genres = models.ManyToManyField(Genre, related_name='genres')
suggested_age = models.IntegerField(default=0)
objects = BookManager()
and I want to query it in such way: there can be duplicates (when min/max age changes, new object will be saved to db), but I want to get the latest one, so I come up with:
class GenreManager(models.Manager):
def get_latest_genre_obj(self, genre):
return self.get_queryset().filter(name=genre).latest()
to be able to retrieve one. Now, I want to get books, using Genre object from above - I need min and max age values in my query. I've tried something like this:
class BookManager(models.Manager):
def get_books_from_genre(self, genre):
genre = Genre.objects.get_latest_genre_obj(genre)
return self.get_queryset().annotate(actual_genre=genre).filter(actual_genre__min_age__gte=F('suggested_age'), actual_genre__max_age__lte=F('suggested_age'))
But it looks like I cannot annotate object to other object:
AttributeError: 'Genre' object has no attribute 'resolve_expression'
So, how to query it like I want to? I thought about Subquery() as I thought it can help me, but it's Django 1.11 feature andI'm using 1.9 version. To sum up what I want to achieve: from genres, retrieve newest (with highest id) object with particular name and use it's fields while querying for books - so I need to have access to it's fields.
I think you need to remove annotate from the code, and use it like this:
If you want Books for a specific genre:
class BookManager(models.Manager):
def get_books_from_genre(self, genre):
genre_object = Genre.objects.get_latest_genre_obj(genre)
return self.get_queryset().filter(genres=genre_object)
Now if you want to have books from multiple genre with same name, then you can try like this:
class BookManager(models.Manager):
def get_books_from_genre(self, genre):
return self.get_queryset().filter(genres__name=genre, genres__min_age__gte=F('suggested_age'), genres__max_age__lte=F('suggested_age'))

How to get object using filter on ManyToManyField

Why target_dialogue is always None?
Model:
class Dialogue(models.Model):
name = models.CharField(max_length=30, blank=True)
is_conference = models.BooleanField(default=False)
participants = models.ManyToManyField(
Person,
related_name='dialogues',
)
def __str__(self):
return self.name or str(self.pk)
And in view I want to get suitable dialogue which contain in participants field 2 objects - user and companion. And if this dialogue doesn't exist I create it:
target_dialogue = None
try:
target_dialogue = Dialogue.objects.get(is_conference=False,participants__in=[user, companion])
except ObjectDoesNotExist:
target_dialogue = Dialogue()
target_dialogue.save()
target_dialogue.participants.add(user)
target_dialogue.participants.add(companion)
finally:
return render(request, 'dialogues/dialogue.html', {
'dialogue': target_dialogue,
})
But target_dialogue is always None. What's a reason of it? I was supposed to solve only a trouble in getting a dialogue from db in order to bad filter parameters, but now I have doubts about it. Maybe something else?
request.user is not a object of Person model with which you have the relation in Dialogue.
You have to first fetch the person object:
user = Person.objecs.get(user=request.user). # According to your person model
Follow same for companion and then query:
target_dialogues = Dialogue.objects.filter(is_conference=False,participants__in=[user,companion]

How can I add a related object to the Admin index view?

I want to be able to show if an Image has been associated with each Product from the list_display view.
I seem to be having trouble because I'm dealing with an associated object.
models.py
class ImageMain(models.Model):
"""This is the Main Image of the product"""
product = models.ForeignKey(Product)
photo = models.ImageField(upload_to='lcdtvs')
pub_date = models.DateTimeField('date published', auto_now_add=True)
class Product(models.Model):
name = models.CharField(max_length=100)
poll = models.ForeignKey(Poll)
pub_date = models.DateTimeField('date published', auto_now_add=True)
size = models.IntegerField(default=0)
admin.py
def photo_for_product(obj):
images = obj.imagemain_set.all()
return images[0].photo
class ProductAdmin(admin.ModelAdmin):
list_display = ('name', "photo_for_product")
inlines = [DescriptionInline, FeatureInline, AffiliateInline]
def upper_case_name(self, obj):
return ("%s" % (obj.name)).upper()
def photo_for_product(self, obj):
images = self.imagemain_set.all()
return images[0].photo
admin.site.register(ImageMain)
admin.site.register(Product, ProductAdmin)
For some reason, the upper_case_name() displays fine in the list view.
The photo_for_product() just keeps displaying (None).
I also tried use pdb in the photo_for_product method, but Django doesn't like that.
I also tried to put the callable before the ModelAdmin method, however, that created a lot of errors:
ProductAdmin.list_display[1], 'photo_for_product' is not a callable or an attribute of 'ProductAdmin' or found in the model 'Product'.
It's not clear from your question exactly what you want the output to be. You say you want to know "if an image has been associated" - if so, you could try this:
def photo_for_product(self, obj):
images = self.imagemain_set.all()
if images:
return True
else:
return False
photo_for_product.boolean = True
If you want to actually see the image, you'll need to return some HTML that renders it in an img tag.
def photo_for_product(self, obj):
images = self.imagemain_set.all()
if images:
return '<img src="%s">' % images[0].photo.url
else:
return ''
photo_for_product.allow_tags = True
Write a method that returns the necessary information as a string and add the name of the method to list_displays on your admin class.
I wanted the output to be a string of the path to the image. Apparently, the issue is that images[0].photo is am ImageFieldFile and not a string.
It seems that by default, ImageFieldFile has the following attributes:
ImageFieldFile.name
ImageFieldFile.path
ImageFieldFile.url
All those attributes return unicode strings.