Get only instance related Items in Django Admin - django

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.

Related

Editing dynamic choice fields in Django

I have a standard Django blog with a Post model, only on the model I have added a ManyToManyField for approvers, the idea being that the backend passes the post to 2 or more approvers to confirm the content before it is published.
class Post(models.Model):
author = models.ForeignKey(
get_user_model(), null=True, on_delete=models.SET_NULL)
title = models.CharField(max_length=30)
content = models.CharField(max_length=30)
approvers = models.ManyToManyField(Approvers)
I will probably learn towards something like django-fsm to create a finite state machine for the Post model to govern whether it is draft/in approval/published, but I would like to be able to change the approvers field so that the number and order of approvers (users) can be changed dynamically by the user.
What is the best way to do this? I thought I could try and change the approvers field to a JSONField so that users can add / delete / change the order of approvers and then handle the interpretation in the frontend and write some function to interface with django-fsm, but this feels like it conflates things too much. Am I missing a simpler route?
Why not make another model to do so like
class PostApprover(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='approvers')
user = models.ForeignKey(Approver, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
To access order in which post(let say with id 5) is approved (descending).you can do like
post = Post.objects.get(id=5)
post.approvers.order_by('-created_at')
you can change the value of created_at to change the order.
Or you can also make an integer field that determines your order

How can i add a 'preview' button in the edit page of the django admin?

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.

Django Query: How to order posts by amount of upvotes?

I'm currently working on a website (with Django), where people can write a story, which can be upvoted by themselves or by other people. Here are the classes for Profile, Story and Upvote:
class Profile(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
first_name = models.CharField(max_length=30, null=True)
last_name = models.CharField(max_length=30, null=True)
class Story(models.Model):
author = models.ForeignKey('accounts.Profile', on_delete=models.CASCADE, related_name="author")
title = models.CharField(max_length=50)
content = models.TextField(max_length=10000)
class Upvote(models.Model):
profile = models.ForeignKey('accounts.Profile', on_delete=models.CASCADE, related_name="upvoter")
story = models.ForeignKey('Story', on_delete=models.CASCADE, related_name="upvoted_story")
upvote_time = models.DateTimeField(auto_now=True)
As you can see, Upvote uses two foreign keys to store the upvoter and the related story. Now I want to make a query which gives me all the stories, sorted by the amount of upvotes they have. I've tried my best to come up with some queries myself, but it's not exactly what I'm searching for.
This one doesn't work at all, since it just gives me all the stories in the order they were created, for some reason. Also it contains duplicates, although I want them to be grouped by story.
hot_feed = Upvote.objects.annotate(upvote_count=Count('story')).order_by('-upvote_count')
This one kind of works. But if I'm trying to access a partical story in my template, it just gives me back the id. So I'm not able to fetch the title, author and content from that id, since it's just an integer, and not an object.
hot_feed = Upvote.objects.values('story').annotate(upvote_count=Count('story')).order_by('-upvote_count')
Could someone help me out with finding the query I'm searching for?
You are querying from the wrong model, you here basically fetch Upvotes ordered by the number of stories, or something similar.
But your probaby want to retrieve Storys by the number of upvotes, so you need to use Story as "queryset root", and annotate it with the number of upvotes:
Story.objects.annotate(
upvote_count=Count('upvoted_story')
).order_by('-upvote_count')
I think the related_name of your story is however a bit "misleading". The related_name is the name of the relation "in reverse", so probably a better name is upvotes:
class Upvote(models.Model):
profile = models.ForeignKey(
'accounts.Profile',
on_delete=models.CASCADE,
related_name='upvotes'
)
story = models.ForeignKey(
'Story',
on_delete=models.CASCADE,
related_name='upvotes'
)
upvote_time = models.DateTimeField(auto_now=True)
In that case the query is:
Story.objects.annotate(
upvote_count=Count('upvotes')
).order_by('-upvote_count')

Data modeling suggestions for Django app

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.

django cms plugin that display model with specific value checked

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?