What is the best way of creating a 'featured image' in Django? - python

I'm relatively new to Django and I'm looking for a way to create a featured image within an image category.
At the moment I have a Show class and a Photo class:
class Show(models.Model):
title = models.CharField(max_length=100, unique=True, db_index=True)
playwright = models.CharField(max_length=100)
description = models.TextField()
def __str__(self) -> str:
return self.title
class Photo(models.Model):
show = models.ForeignKey(Show, on_delete=models.CASCADE)
image = models.ImageField(upload_to='', default='images/default.png')
def __str__(self) -> str:
return self.image.name
And I'd like to be able to set one photo for each show as the 'featured' image. Of course, I could put a Boolean field in for this, but that runs the risk of having multiple Featured images when there should be only one.
What is the best structure for this? I've had a look around and can't find any tutorial or resource that shows this behavior. I should be able to set this 'featured' setting from the admin panel.
(Also, I'm aware there are gallery apps out there for Django, but this is part of my learning Django, so I'm trying to build this myself.)
EDIT: I'm afraid I was not as clear as I should have been, apologies for that! I mean specifically that one show can have many photos related to it, and that from that pool of photos, one 'featured' image can be selected.
Thanks!

It seems to me that you are looking for the OneToOneField!
class Photo(models.Model):
show = models.OneToOneField(Show, on_delete=models.CASCADE)
image = models.ImageField(upload_to='', default='images/default.png')
def __str__(self) -> str:
return self.image
Make sure you also create a Form in forms.py for it and then make sure to validate it in views.py when you register the Show!
in forms.py something like this:
Class ShowPhoto(forms.ModelForm):
class Meta:
model = Photo
fields =('show','image')
and in Views.py after importing the ShowPhoto form with:
from .forms import ShowPhoto
something like this in the function referring to the html page:
add the variable:
show_pic = ShowPhoto(request.Post)
and add the validation when you are validating the form for the show:
if form.is_valid() and show_pic.is_valid():
show = form.save()
show_picture = show_pic.save(commit=false)
show_picture.show = show
show_picture.save()
remember to pass it to the context when you render!
and don't forget to add the form to add the picture when you create the show in the html template like:
{{ show_pic.as_p }}

Related

Delete a Picture & thumbnails with sorl.thumbnail (Django)

I am working with Python 2.7, Django 1.9 and sorl.thumbnail.
I cannot manage to create a view to delete in one time the original picture file, the Picture entry in the database, the thumbnail pictures generated by sorl.thulbnail, and the thumbnail_kvstore entry in the database.
Here is my Picture model:
class Picture(models.Model):
file = models.ImageField(upload_to="pictures")
slug = models.SlugField(max_length=100, blank=True)
user = models.ForeignKey(User, null=True, blank=True)
exiflnglat = models.PointField(dim=3, geography=True, blank=True, null=True)
objects = models.GeoManager()
def __str__(self):
return self.slug
#models.permalink
def get_absolute_url(self):
return ('upload-new', )
And here is my view:
from sorl.thumbnail import delete
def deletepicnthumbs(request, pk):
allpicfromuser = Picture.objects.filter(user=request.user)
pictodelete = allpicfromuser.get(id=pk)
delete(pictodelete)
return redirect(adddetails)
This view does not delete anything.. What I am doing wrong ?
Thanks a lot
It seems that you are trying to use the delete method from sorl to delete an instance of the Picture model instead of the picture itself.
This code should work :
from sorl.thumbnail import delete
def deletepicnthumbs(request, pk):
pictodelete = Picture.objects.get_object_or_404(id=pk, user=request.user)
# Delete the thumbnails, as well as the original image
# If you want to keep the original image, pass ```delete_file=False```
delete(pictodelete.file)
# We use Django's method to delete the Picture instance, if needed
pictodelete.delete()
return redirect(adddetails)
Hope this helps,
Adela

django ModelForm foreign key - text widget add if not exist

I am just starting out with Django and have the following:
models.py:
class Song(models.Model):
name = models.CharField(max_length=200, blank=False, null=False)
artist = models.ForeignKey(Artist, blank=False, null=False)
class Artist(models.Model):
name = models.CharField(max_length=200, unique=True)
Now I have a model form for Song but currently have no ability to add artists that don't already exist (rendered as a dropdown). It would be nice to allow users to add artists on the fly but haven't been able to find a way to get that working. I saw lots of answers relating to replicating the admin "add another..." but kept running into roadblocks and outdated information.
What I tried:
replicating the "add another" from the admin console
Creating as a regular form - but abandoned it because ModelForms gives me a lot for free
Started researching on formsets but got stuck there, could not find a working example
Is there a way to easily add another artist from the song form? I don't mind rendering a new textbox below the artist selection where the user can add a new artist but I don't know how to do that with ModelForms and then add the artist into the database before saving.
Any advice would be much appreciated!
It would help to see what you are using to create your forms. I assume you are using a ModelFrom. If you are using jQuery I think you could use the following in your forms.py to capture a new artist. However, if you are using jQuery I would save individual forms as templates and display them as necessary depending on a button or link event for a new artist.
forms.py
class SongForm (forms.ModelForm):
new_artist_name = forms.CharField()
class Meta:
model = Song
def save(self, commit=True):
# do something with self.cleaned_data['new_artist']
new_artist = Artists.objects.filter('new_artist_name')
if new_artist.exists():
# Save song to artist.
else:
# Create and save new artist and save song to the
# new artist.
return super(SongForm, self).save(commit=commit)

django admin inline components

I started learn django and I have question. Here is my models:
from django.db import models
class Color(models.Model):
title = models.CharField(max_length=30)
code = models.CharField(max_length=7)
def __unicode__(self):
return '{0} ({1})'.format(self.title, self.code)
class Image(models.Model):
color = models.ForeignKey(Color)
src = models.ImageField(upload_to='media/img/')
alt = models.CharField(max_length=255)
def __unicode__(self):
return '{0} ({1})'.format(self.alt, self.color.title)
class Manufacturer(models.Model):
title = models.CharField(max_length=255)
image = models.ForeignKey(Image)
def __unicode__(self):
return self.title
I need to have possibility to edit image instance on Manufacturer's page (manufacturer has one image). How can I do it in admin.py
I need something like:
class ImageInline(admin.TabularInline):
model = Image
class ManufacturerAdmin(admin.ModelAdmin):
inlines = [ImageInline]
But I receive
Exception Value:
<class 'catalog.models.Image'> has no ForeignKey to <class
'catalog.models.Manufacturer'>
I need one image for one Manufacturer
And second one:
I am planing to create product model, and one product can have many images. I think I should create many to many relation. So how can I describe Product in admin with many images?
Any ideas?
Exception message tells you everything. You need to add FK relation to Image model:
manufacturer = models.ForeignKey(Manufacturer)
If you need only one image for one manufacturer consider putting it in Manufacturer model. This would be more efficient (less DB queries or "select_related" functions) and easier to manage.
As for Many to many relation between Product and Image - just use ManyToManyField (https://docs.djangoproject.com/en/dev/topics/db/examples/many_to_many/) in Product model and leave Image model as is.

Django multiple tag field

I'm trying to find a good tutorial for django how to create multiple tags in a model.
For example:
class Tag(models.Model):
name = models.CharField()
class Sample(models.Model):
name = models.CharField()
urlA = models.CharField()
urlB = models.CharField()
tagA = models.ManyToManyField(Tag)
tagB = models.ManyToManyField(Tag)
I would like to display the tags as an input field and separate by ',' and split in the save method. So I'd like to see 2 different input for the 2 tag field.
If you have an easy way to do or know a good tutorial, please tell me! :)
Thank you guys!
Edit: you do not have to have the actual table sets over laid. You can generate any queryset you want to inn your views. Your url conf can be set up to display the detail view from multiple url. If i am still not understanding then please refine your question.
For having multiple anything tags categories your either going m21 or m2m. So when you create your tags you can add them one by one. Are you familiar with what the Django ORM has to offer with some of its admin functionality? Please give the documentation a good look through. Your approach to this problem is anything but reasonable. Not trying to rub you the wrong way I'm no genius. You would do something like so.
class Tag(models.Model):
title = models.CharField(max_length=250, blank=True)
slug = models.SlugField(blank=True
class Meta:
verbose_name = "tag"
verbose_name_plural = "tags"
ordering = ['title']
#models.permalink
def get_absolute_url(self):
return "/tags/%s/" % self.slug
class Entry(models.Model):
title = models.CharField(max_length=250, blank=True)
body = models.TextField()
tags = models.ManyToMany('Tag')
slug = models.SlugField()
#models.permalink
def get_absolute_url(self):
return "/blog/%s/" % self.slug
There's a little more code to be done for the EntryAdmin and the TagAdmin models, Many other things that can be done as well. I am not sure what you are trying to achieve with that if you could be more clear? Thank you, the above is a rough illustration of how I would approach it.
I found a solution from here:
https://dev.to/thepylot/how-to-add-tags-to-your-models-in-django-django-packages-series-1-3704
django-taggit is very useful for tagging.
It is
a reusable application that primarily offers you a Tag model, and a manager for easily adding tags to any model.
pip install django-taggit
After that, open settings.py and edit the installed apps section:
INSTALLED_APPS = [
...
'taggit'
]
After that, edit your model and add tags like this:
tags = TaggableManager()
The TaggableManager will show up automatically as a field in a ModelForm or in the admin.
Documentation: https://django-taggit.readthedocs.io/en/latest/index.html

Django MTMField: limit_choices_to = other_ForeignKeyField_on_same_model?

I've got a couple django models that look like this:
from django.contrib.sites.models import Site
class Photo(models.Model):
title = models.CharField(max_length=100)
site = models.ForeignKey(Site)
file = models.ImageField(upload_to=get_site_profile_path)
def __unicode__(self):
return self.title
class Gallery(models.Model):
name = models.CharField(max_length=40)
site = models.ForeignKey(Site)
photos = models.ManyToManyField(Photo, limit_choices_to = {'site':name} )
def __unicode__(self):
return self.name
I'm having all kinds of fun trying to get the limit_choices_to working on the Gallery model. I only want the Admin to show choices for photos that belong to the same site as this gallery. Is this possible?
Yes. You need to override the form that admin uses for the Gallery model, then limit the queryset of the photos field in that form:
class GalleryAdminForm(django.forms.ModelForm):
class Meta:
model = Gallery
def __init__(self, *args, **kwargs):
super(GalleryAdminForm, self).__init__(*args, **kwargs)
self.fields['segments'].queryset = Photo.objects.filter(site=self.instance.site)
class GalleryAdmin(django.contrib.admin.ModelAdmin):
form = GalleryAdminForm
django.contrib.admin.site.register(Gallery, GalleryAdmin)
I would delete site field on my Photo model and add a ForeignKey to Gallery. I would remove limit_choices_to from photos fields on Gallery model.
Because you are using ForeignKeys to Sites, that means sites don't share galleries and photos. Therefore having those I mentioned above is already useless.
class Photo(models.Model):
title = models.CharField(max_length=100)
gallery = models.ForeignKey(Gallery, related_name='photos')
file = models.ImageField(upload_to=get_site_profile_path)
def __unicode__(self):
return self.title
class Gallery(models.Model):
name = models.CharField(max_length=40)
site = models.ForeignKey(Site)
def __unicode__(self):
return self.name
Once you set the site on a gallery all its photos will inherit this property. And the site will be accessible as photo_instance.gallery.site:
#property
def site(self):
return self.gallery.site
This should work as if you had a site field. But I haven't tested it.
Things change or course, if you decide that a gallery or a photo can appear in multiple sites.
According to the docs, "limit_choices_to has no effect when used on a ManyToManyField with an intermediate table". By my reading, that means it has no effect at all, because ManyToManyFields use intermediate tables...
I haven't tried to make it work in the Admin site, but from your own views, you can create a form and override the queryset used to populate the list of choices:
form.fields["photos"].queryset = request.user.photo_set.all()

Categories