Imagine that you have a product which has a cover URL (cover is presented to customers on the landing page) and a list of image URLs (these images show different sides of the product)
problem: how to separate cover from other images?
class Image(models.Model):
url = models.URLField()
class Product(models.Model):
cover = ...?
album_images = ...?
Using ForeignKey in the Image model is not an option because when using product.image_set.all() you will get all images including the cover.
Any suggestions will be appreciated.
One common way would be:
class Product(models.Model):
...
class Image(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name="images")
URL = models.URLField()
is_cover = models.BooleanField()
Because of the "related_name" you can access the images from the product instance.
prod = Product.objects.get(pk=123)
cover = [x for x in prod.images if x.is_cover]
To find the cover image best to add a method to the Product so you can call something like prod.get_cover() or so.
Related
What is the best practice to choose one item from a m2m relationship?
Lets say I've got an album of photos:
class Photo(models.Model):
img = models.FileField()
class Album(models.Model):
photos = models.ManyToManyField("Photo")
But now I also want to pick one photo as a cover. I could use a Foreign Key in Album to one Photo, but then I'd always need to check whether this photo is actually in the photos of that album. Is there a better way?
Sorry for the basic question I just somehow can't find the right words to google it.
Thanks,
Michael
You can make a custom through=… model [Django-doc] with a boolean cover that is set to True in case it is the cover item:
from django.db.models import Q, UniqueConstraint
class Photo(models.Model):
img = models.FileField()
class Album(models.Model):
photos = models.ManyToManyField(Photo, through='AlbumPhoto')
class AlbumPhoto(models.Model):
photo = models.ForeignKey(Photo, on_delete=models.CASCADE)
album = models.ForeignKey(Album, on_delete=models.CASCADE)
cover = models.BooleanField(default=False)
class Meta:
constraints = [
UniqueConstraint(fields=['photo', 'album'], name='no_photo_multiple_times'),
UniqueConstraint(fields=['album'], condition=Q(cover=True), name='one_cover_per_album'),
]
The first constraint guarantees that you can not add the same Photo multiple times to the same Album, whereas the second condition gurantees that each Album has at most one Photo for which cover=True.
I have the folllowing class model in my Django website:
class Buy(models.Model):
category = models.ForeignKey(Category, related_name='sell', on_delete=models.CASCADE)
title = models.CharField(max_length=100)
image = models.FileField()
image2 = models.FileField(blank=True)
description = models.CharField(max_length=300)
date = models.DateField(default=timezone.now)
buy_price = models.DecimalField(max_digits=6, decimal_places=2)
sell_price = models.DecimalField(max_digits=6, decimal_places=2)
seller = models.ForeignKey(Seller, on_delete=models.PROTECT)
showcase = models.BooleanField(default=False)
As you can see, I store photos files with 2 fields: image and image2. But now my client requested me to add more photos. My doubt is:
Should I continue adding new fields to this class, for example, image3, image4, image5 and so on? The problem I see: not every records will have so many photos and the most of them will become "empty".
Should I only upload the new photos without saving their names into the database? In this way, the new photos should follow some name related to the image class field. I mean, unique_photo_1.jpg goes inside the image field, unique_photo_2.jpg is not saved into the database but is related to this field, as well as the unique_photo_3.jpg.
What is the best practice?
Thank you!
On #1, the best practice is to follow database normalization principles, and create a separate Image model that relates back to your Buy model. If you anticipate that the images may be reused in several Buy model instances, use many-to-many relationships; otherwise, use many-to-one (i.e. ForeignKey). That means removing image and image2 from your Buy model, and then creating e.g.:
class Image(models.Model):
image = models.FileField()
image_type = models.CharField()
buy = models.ForeignKey(Buy, on_delete=models.PROTECT)
By #2, if you mean you're considering skipping using FileField or ImageField to instead write code that will search for files in some storage space, then that doesn't sound like a good idea, because then you're divorcing your file (meta)data from the rest of your database contents. Using FiledField/ImageField will also make it much easier to use storage backends such as AWS S3.
Edited my question to make it more clear. And I am sorry if what i'm asking is obvious or easy to solve, I am just starting out.
Hello, I am developing a website which has 2 models for the content: Article and Comic. Now I want a system that allows me to tag Articles and Comics with certain keywords. These keywords can then be used to retrieve a list of objects from both the models and display them.
At first, I set up the system as follows:
class Article(models.Model):
.....
class Comic(models.Model):
.....
class Tag(models.Model):
tag = models.CharField(max_length = 25)
article = models.ForeignKey(Article)
comic = models.ForeignKey(Comic)
However, this did not work out.
Then I tried implementing 2 different tag models for the 2 different models: ArticleTag and ComicTag, in the following way:
class Article(models.Model):
.....
class ArticleTag(models.Model):
tag = models.CharField(max_length = 25)
article = models.ForeignKey(Article)
class Comic(models.Model):
.....
class ComicTag(models.Model):
tag = models.CharField(max_length = 25)
comic = models.ForeignKey(Comic)
This also did not work, as I was able to get a list of tags of an article, but I could not get a list of articles that had the same tag. And also it was using 2 different tag models so that was also not preferable.
A user suggested a ManyToManyField based on the previous information I had provided. However, how would this exactly work?
Now, what is the best way to create a content tagging system using Django? It should preferably work with just 3 models: Article, Comic and Tag, not 4 like I tried. In conclusion, I want a system that lets me get a list of objects from 2 models using one single tag. So, I would really appreciate help of any kind as I am an amateur programming (pretty obvious) and I am completely stumped by this problem.
You could use a ManyToManyField.
Basically something like the following. It's more intuitive if you change the name of ArticleTag.tag to ArticleTag.name. I've also added a related_name field to the M2M relationship so you can retrieve an article based on its tags using Article.objects.filter(tags__name="tag_name_here"). In the reverse direction, you could get all the tags for an article using ArticleTag.objects.filter(article__title="article_name_here").
class Article(models.Model):
title = models.CharField(max_length=140)
.....
class ArticleTag(models.Model):
name = models.CharField(max_length = 25)
articles = models.ManyToManyField(Article, related_name="tags")
[EDIT based on your updated question]
Based on your update, you could do this:
class Article(models.Model):
.....
class Comic(models.Model):
.....
class Tag(models.Model):
tag = models.CharField(max_length = 25)
articles = models.ManyToManyField(
Article,
related_name="tags",
blank=True,
null=True
)
comics = models.ManyToManyField(
Comic,
related_name="tags",
blank=True,
null=True
)
This way an Article/Comic can have many different tags, and any one tag can tag many different articles/comics. The blank=True, null=True means that you don't have to have an associated comic/article with a given tag, i.e., one tag could happen tag only comics but no articles.
To get a list of articles with the same tag:
Article.objects.filter(tags__name="your_tag_name")
how to add extra information to the tag system or access through model in django-taggit?
My model 'Post' has an image and a TaggableManager, so that each Post (or image) can have multiple tags on it, and users can search all posts by their tags. Now, I need to specify the position of the tagged tag on each image (similar concept that users tag a friend on a specific location on a photo).
I think I need to add extra information to the through model because the coordinates belong only to the relation of a post and tag, not to the tag itself. Here is the model.py (simplified):
class TaggedPost(taggit.models.TaggedItemBase):
content_object = models.ForeignKey('Post')
x = models.IntegerField()
y = models.IntegerField()
class Post(models.Model):
image = models.ImageField(upload_to='p/%Y/%m/%d/')
tags = TaggableManager(through=TaggedPost)
However, I cannot access the through model via the API of TaggableManager. Is it possible to read the data? I don't want to build another relation or mapping table.
Thanks for any suggestion.
I asked in the Google forum of taggit but no replies. Here is my solution at the end (might not be the best)
I build my own GenericTaggedItemBase like this:
class GenericPostTaggedItemBase(ItemBase):
content_object = models.ForeignKey('Post', related_name='%(class)s')
x = models.IntegerField(null=True, default=None, blank=True)
y = models.IntegerField(null=True, default=None, blank=True)
class Meta:
abstract = True
Then similar to TaggedItem in Taggit:
class PostTaggedItem(GenericPostTaggedItemBase, TaggedItemBase):
class Meta:
verbose_name = _("Tagged Item")
verbose_name_plural = _("Tagged Items")
In my Post model:
class Post(models.Model):
# whatever fields go here
tags = TaggableManager(through=PostTaggedItem)
To assess the data:
Post post = Post.objects.get(pk=1)
models = post.posttaggeditem.all()
for item in models:
# here is item.x and item.y
The key here is the related_name in GenericPostTaggedItemBase. It must be %(class)s or similar (see the source in taggit). So that the generic base can be used with other type of tags, if you have. Also, this is kind of 'recommended' for abstract class (don't use fixed related_name for abstract class). For details, search about related_name and %(class). I will skip this here.
If you have any ideas or suggestions, please let me know.
I'm trying to model my app and I've come across this problem:
I have a Slides which can be images, text or videos.
Also, images and videos can be in many different slides and presentations of the same user.
I also want to store which presentation the slide belongs to and the insert date (slides must have an order).
class Slide(models.Model):
user = models.ForeignKey(User)
presentation = models.ForeignKey(Presentation)
insert_date = models.DateTimeField(auto_now_add=True)
-
class Image(models.Model):
def get_image_path(instance, filename):
return os.path.join('users/images', str(instance.id), filename)
user = models.ForeignKey(User)
slide = models.ManyToManyField(Slide)
image = models.ImageField(upload_to=get_image_path)
insert_date = models.DateTimeField(, auto_now_add=True)
-
class SlideText(models.Model):
slide = models.OneToOneField(Slide)
text = models.TextField()
[Video model will be similar to Image]
Problems with this model are that a Slide can be empty, and that a slide can contain both Images and Texts (as well as Video) and it shouldn't.
I can image that this would be a common problem: certain Item have some information related depeding on the "type of Item" (that'd be Slide of image, Slide of text...), so what's the common solution ?
any help really appreciated! thanks!
Generic relations are what you want.