I have a Django app where users leave comments for each other. I'm now going to add a photo feature. I need some help in formulating the data model(s) for this photo feature.
Under this feature, users will be able to upload photos in a common area of the website, where the said photos will appear most-recent first. This is simple enough, so let's now add two complications to the feature:
1) For each photo entry, uploaders will have the option of including
additional photos (as a stream). The first photo will then be treated
as a cover photo that is shown in the common area of the website. Upon
clicking this cover, the entire stream will become visible.
2) For each photo entry, any viewer will be able to reply with a
photo of their own. If that happens, the two photos will be put
together as a stream, with the reply treated as a cover photo, to
appear in the common area of the website. Clicking this cover photo
will show both entries one after the other, thus showing the users
what the original photo was, and what the reply to it was.
How should I model the above requirements? I can't seem to wrap my head around this. Something like:
class PhotoReply(models.Model):
owner = models.ForeignKey(User)
which_photo = models.ForeignKey(Photo)
class Photo(models.Model):
owner = models.ForeignKey(User)
is_stream = models.BooleanField(default=False)
image = models.ForeignKey(upload_to=upload_photo_to_location, storage=OverwriteStorage())
upload_time = models.DateTimeField(db_index=True, auto_now_add=True)
stream_id = models.IntegerField(default=0)
is_reply = models.BooleanField(default=False)
reply = models.ForeignKey(PhotoReply, blank=True, null=True)
But there are obvious weakness, inconsistencies in that. Please advise.
Did I understand you correctly that every photo can become a "cover photo", as soon as a user replies to it with another photo? If that's the case, then you only need to keep track of the "children" that a photo has, to know if you want to display it as "cover" or not.
class Photo(models.Model):
owner = models.ForeignKey(User)
parent = models.ForeignKey('self', db_index=True, null=True, default=None)
child_count = models.IntegerField(default=0, db_index=True)
image = models.ForeignKey(upload_to=loc)
upload_time = models.DateTimeField(db_index=True)
So a photo that has > 0 children is a "cover". And for each "cover" photo "x" you just need to look to look up all photos that have "x" as a parent.
Related
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.
After long searches, I still didn't find any answers I've been able to apply.
I have in my django app a models which creates new pages in the website:
class Page(models.Model):
name = models.CharField(max_length=255, null=False, blank=False, unique=True)
content = HTMLField('Content')
slug = models.CharField(max_length=255)
background_image = models.ImageField(
upload_to="page_background/",
null=False,
blank=False,
default="default/livresse_logo.png",
)
As you can see there's a WYSIWYG editor in it, a title and a background image.
When I go to the admin page it's like this:
I'm looking for a way to add a button 'preview' (maybe next to the save button) that would show the content of my model included in the template that will be use to display the page before saving.
I'd like this button only displaying for that model.
Hope i'm clear enough.
I'm not sure if there is an elegant solution, but you can solve your problem a little differently, implement the Boolean parameter is_published in the model, and write the view in such a way that the articles that are not yet is_published are only seen by the superuser, so I usually organize a preview.
I am new to python and Django so I hope I can get some help here.
I have an "app" where I have some models like "Raum", "Platz" and "Buchung". in English (Room, Postion and booking). In the web app a user can book a Position in a Room.
Here are my 3 Models.
Room:
class Raum(models.Model):
raumID = models.CharField(max_length=1, primary_key=True)
name = models.CharField(max_length=250, default='')
Position:
class Platz(models.Model):
platzID = models.CharField(max_length=3, primary_key=True)
raum = models.ForeignKey(Raum, on_delete=models.CASCADE, default='')
Booking:
class Buchung(models.Model):
cearted_on = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(Mitarbeiter, on_delete=models.CASCADE, default='')
raum = models.ForeignKey(Raum, on_delete=models.CASCADE, default='')
platz = models.ForeignKey(Platz, on_delete=models.CASCADE, default='')
I want to be able to choose a Room and a Position when trying to book a Room. But it should only show the positions for the room I choose. And thats my Problem, I don't really know how to do that. I looked into the Django documentation and found "to_field" but I don't think thats right and also it doesn't work.
Booking in admin page.
So as u can see I have a Room(raum) called "seestern" and a Position(Platz) it shows 4 choices. But Room Seestern has Only "A1" and "A2". I want to only display those that belongs to a room.
How can I do that?
Hopefully I get some Help.
Thanks.
Use https://django-autocomplete-light.readthedocs.io/en/master/tutorial.html#filtering-results-based-on-the-value-of-other-fields-in-the-form. It seems to do the thing you want to achieve. It requires you to write some logic manually, but still does a great job on frontend so you don't have to deal with JavaScript and HTML of admin panel. Create the form for you model and add it to your admin class like form=MyForm. Try to follow the documentation from the beginning and then apply the technique described in the link I have provided, because if you jump straight to it you will be a bit overwhelmed.
I made a model that displays articles and when you create an article you have the possibility to choose if this article will be a featured one.
So this is basically what I have in my Article model :
class Article(ModelMeta, TranslatableModel):
taints_cache = True
"""
Press article element,
"""
date_created = models.DateTimeField(auto_now_add=True)
date_modified = models.DateTimeField(auto_now=True)
date_realization = models.DateField(_('Realised in'),
default=timezone.now)
image = FilerImageField(verbose_name=_('Featured image'), blank=True,
null=True,
on_delete=models.SET_NULL,
related_name='image_press_article',
help_text=_('Set if the article will be featured'))
sources = models.ManyToManyField(ArticleSource, verbose_name=_('Source'),
blank=False, null=True, related_name='sources_press_article')
regions = models.ManyToManyField(Country, verbose_name=_('Country of the article'),
blank=True, null=True,
related_name='regions_press_article')
global_regions = models.BooleanField('Global', default=True)
featureArticle = models.BooleanField(_('Feature'), help_text=_('Feature this article'), default=False)
Then, I created a plugin that displays the featured articles.
But the thing is, in the django plugin admin I let the user the possibility to choose which article he wants to display (with a maximum of 3).
But in this choosing list, all my articles are listed.
What I want to, is to list only the articles that are checked as "featured", in my plugin admin. Instead of having all the articles.
Here what I have with my cms_plugin's model :
class FeaturedArticlePlugin(CMSPlugin):
selected_article = SortedManyToManyField(Article, blank=True, verbose_name=_('Selected articles'),
help_text=_('Select the featured articles to display'))
def __str__(self):
return u'%s Selected articles' % self.selected_article.all()
def copy_relations(self, oldinstance):
self.selected_article = oldinstance.selected_article.all()
And in my cms_plugins.py :
class PressPlugin(CMSPluginBase):
module = 'Press'
class PressFeaturedArticlePlugin(PressPlugin):
module = _('Press')
name = _('Press feature')
model = FeaturedArticlePlugin
render_template = 'djangocms_press/plugins/feature_article.html'
number_article = 3
def render(self, context, instance, placeholder):
"""
Get a list of selected_articles
"""
selected_article = instance.selected_article.all()
number_selected_article = selected_article.count()
feature_article_list = list(selected_article[:self.number_article])
context['instance'] = instance
context['feature_article_list'] = feature_article_list
return context
plugin_pool.register_plugin(PressFeaturedArticlePlugin)
So, I am sure it's nothing complicated but I can't point this out.
Anyone has a clue ?
EDIT
From what I understand, the only thing that concern the display of all articles is this line :
selected_article = SortedManyToManyField(Article, blank=True, verbose_name=_('Selected articles'),
help_text=_('Select the featured articles to display'))
So what I am suppose to do is to filter this selected_article with the featureArticle=True. But how to do it ?
I am not quite sure if I am missing something, but, couldn't you just apply a filter here?
selected_article = instance.selected_article.all().filter(featureArticle=true)
number_selected_article = selected_article.count()
Or is the problem with the lines after?
feature_article_list = list(selected_article[:self.number_article])
If your problem is selecting the extra articles, maybe you need to order them by date and select only the necessary?
feature_article_list = list(Articles.all().order_by('-created')[:self.number_article - number_selected_article]
Which will only select the extra necessaries?
Edit: Your situation kind of reminds me of a problem I once had. So I'll refer you to the same page that helped me in the past just in case you'd manage to figure it out.
Restrict django admin change permissions
Edit 2 : "I created a plugin that displays the featured articles. But the thing is, in the django plugin admin I let the user the possibility to choose which article he wants to display (with a maximum of 3). But in this choosing list, all my articles are listed."
Isn't it ok if all the articles are displayed there? How can you choose among them if they are not all displayed?
I'm trying to execute a complex query using Django's ORM and I can't seem to find a nice solution. Namely, I have a web application where users answer questions based on a video. I need to display all the videos for a specified user that have at least one question unanswered (not responded to). I haven't been able to figure it out yet with the ORM ... I know that I could probably write a SQL query for this and just execute it with the raw SQL function, but I really would prefer to stay in the ORM.
Models: Video, Question, Response and default User.
Relationships:
Question has a many to many relation towards video
Response has a foreign key each to Question, Video and User
What the query needs to do:
Display all the videos for a specified user that have at least one video question unanswered (not responded to).
Any help would be awesome! I've been struggling with this for way too long.
EDIT: The models I have are (simplified):
class Video(TimeStampedModel):
title = models.CharField(max_length=200)
source_id = models.CharField(max_length=20)
class Question(TimeStampedModel):
DEMOGRAPHIC_QUESTION = 'd'
QUESTION_TYPES = (
(VIDEO_QUESTION, 'Video related question'),
(DEMOGRAPHIC_QUESTION, 'Demographic question'),
)
MULTIPLE_CHOICE = 0
PLAIN_TEXT = 1
RESPONSE_TYPE = (
(MULTIPLE_CHOICE, 'Multiple Choice'),
(PLAIN_TEXT, 'Plain Text')
)
type = models.CharField(max_length=1, choices=QUESTION_TYPES)
videos = models.ManyToManyField(Video, null=True, blank=True)
title = models.CharField(max_length=500)
priority = models.IntegerField()
class Response(TimeStampedModel):
user = models.ForeignKey(User)
question = models.ForeignKey(Question)
video = models.ForeignKey(Video, blank=True, null=True)
choice = models.ForeignKey(Choice, null=True, blank=True,related_name='selected_choice')
text = models.CharField(max_length=500, blank=True)
// Not relevant but included for clarity
class Choice(TimeStampedModel):
question = models.ForeignKey(Question)
text_response = models.CharField(max_length=500)
image = models.FileField(upload_to=_get_choice_img_path, blank=True)
value = models.IntegerField(default=0)
external_id = models.IntegerField(default=0)
Judging logically by the way your models look like, I think something close to the following should be fine.
q = Response.objects.select_related().filter(user__name=user).filter(response__choice=None)
videos = Video.objects.filter(id__in=q.extra(where=["{}>=1".format(q.count())]).values('video_id'))
Hope you understand what I did there. The first line basically tries to take a natural join of the model objects. The second line is using the query generated in the first line to get the count and checks if it is at least 1, and gets the Videos that belong to that query.