Create Django Application Settings Page - python

I have a Django app and am trying to make some specific model information changeable while the site is loaded. For example, I'd like to be able to change certain images on pages (banners and such) based on changes I make on the admin panel of Django. Additionally, I'd like to create a list of prepopulated migrations for my social media links that can be editable in a django admin page. My specific instance of this is for all of my social media links. I'd like to put my social media link in a model 'Facebook Url" = 'www.facebook.com/mypage. I would then like to put these links throughout the page using dot notation {{ project_settings.facebook.url }} for example. What is the easiest way to do this. I don't think I want to put the context in all of the views because I would have to do that for every page I want this to be available. In the case of my footer it is on every page. The background images are also on several different pages.

I've done what you're trying to do by creating CustomText and CustomImage models which look like the following:
class CustomText(models.Model):
name = models.SlugField()
plain_text = models.TextField("Plain/Markdown Text", blank=True)
html_text = models.TextField("HTML Text", blank=True)
auto_render = models.BooleanField("Render to HTML using Markdown (on save)", default=True)
(... implementation of text->html omitted )
class CustomImage(models.Model):
name = models.SlugField()
description = models.TextField("Description", null=True, blank=True)
image = models.ImageField("Custom Image", upload_to="custom_images/", null=True, blank=True)
Then I added myapp/templatetags/custom_resources.py, which are a pair of template tags to retrieve the text or image from those models:
from django import template
from django.utils.safestring import mark_safe
from myapp.models import CustomImage, CustomText
register = template.Library()
#register.simple_tag
def custom_image(image_name):
cimage = CustomImage.objects.filter(name=image_name).first()
return cimage.image.url if cimage else "custom_image_%s_not_found" % image_name
#register.simple_tag
#mark_safe
def custom_text(text_name):
text = CustomText.objects.filter(name=text_name).first()
return text.html_text if text else "Custom text <%s> not found." % text_name
Finally, in your templates, load the templatetags, and then use the template tag with the appropriate slug for the resource you want.
{% load custom_resources %}
...
{% custom_text 'custom_text_slug' %}

Related

How to display ForeignKey Data in Django Template

I have relation of Project between Tags and a Project can have multiple tags, But I am unable to display the tags data in my template, I am trying to display data according to tag slug. But I ma getting error, Please let me know how I can display Tags data in my Template.
Here is my urls.py file...
path('tag/<tag_slug>', views.projecttag, name='projecttag'),
here is my `models.py file...
class Tags(models.Model):
project = models.ForeignKey(Project, null=True, blank=True, related_name='ProjectTags', on_delete=models.CASCADE)
tag_name = models.CharField(max_length=64, null=True, blank=True)
tag_slug = models.SlugField(max_length=64, null=True, blank=True)
here is my views.py file...
def projecttag(request, tag_slug):
tag = get_object_or_404(Tags, tag_slug=tag_slug)
project = Project.objects.filter(ProjectTags=tag)
context = {'tag':tag, 'project':project}
template_name = 'pages/tags.html'
return render(request, template_name, context)
here is my tags.html file...
{% for property in project %}
<div class="single-property-box">
{{property.name}}
</div>
{% endfor %
According to my understandings, you want to display tags that are connected with your 'project' class. As you explain that a project can have multiple tags, so the 'ProjectTags' field from your 'Project' class must be multi-valued. But when you are filtering Projects in projecttag view, you are just checking ProjectTags=tag. Here tag is a single object. So instead you should check for ProjectTags__in=tag.
And if you already declared Tags class as ManyToManyRelation in Project class then there is no need to create Foreign Key constraint in tags class. As you didn't upload Project Class, so I don't have any idea about how you are relating tags class with it.

How to auto increment a model field in django admin form by having add another on the side?

I have this model:
class BlogPost(models.Model):
author = models.CharField(max_length=64, default='Admin')
image = models.ImageField(blank=True, null=True)
title = models.CharField(max_length=255)
caption = models.CharField(max_length=500)
content = RichTextUploadingField()
# todo support for tags
tags = models.CharField(max_length=255, default='travel') #todo
date_created = models.DateField()
Now in tags field, I want to give multiple strings like #tips, #travel, etc on the same field. What I want is there should be like an add or increment tag, which when I click will show another tag field appears on the admin form and the user can adder another tag.
My backend is not on the regular HTML page. I have customized the default Django admin page for the backend using the material package. That is I cant use button tag and all.
How can I achieve this?? I have an image attached which explains better.
Image here
You can create another model called Tag and connect it to your BlogPost like this:
class Tag(models.Model):
text = models.CharField(max_length=244, default='travel')
blog_post = models.ForeignKey(BlogPost, on_delete=models.CASCADE, related_name='tags')
Then if you want to acces tags of a certain post in a view you would use:
blog_post = BlogPost.objects.get(pk=pk) # query the blog post you want the tags to
tags = blog_post.tags.all() # get the tags
Then simply add a form to each blog post where you would add a tag and save it to the related post. I'm not sure how you would do it an an admin interface though.

How to use model methods in django templates with class based view

I've defined methods in my model, and I'm trying to use it in django template, which is rendered using ListView
My model looks like this:
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.IntegerField()
created_at = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
def get_total_sum(self):
return super().objects.all().filter(user=self.user).aggregate(models.Sum('price'))
My view:
from django.views.generic.list import ListView
from book.models import Book
class BookView(ListView):
template_name = 'book.html'
# I'm using this to order book by created date
def get_queryset(self):
return Book.objects.filter(user=self.request.user).order_by('-created_at')
And my template:
Total books: {{ object_list|length }}
Total price of all books: # I've no idea how to display them here, when using class based view
One thing you can do is to use custom templatetags:
Follow these steps:
Create a folder templatetags inside your app directory
Create a file inside e.g book_filter.py and __init__.py
Inside book_filter.py copy below filter.
book_filter.py
from django import template
egister = template.Library()
#register.filter
def total_price(amounts):
total = 0
for amount in amounts:
total += amount.price
return total
Now in your html file, do the following:
{% load book_filter %}
Total price of all books: {{object_list|total_price}}
Use this link for reference: custom-template-tags
Hope this helps.
If you want to use Book.get_total_sum in a template, you need to make it a property.
#property
def get_total_sum(self):
return super().objects.all().filter(user=self.user).aggregate(models.Sum('price'))
in the template
{{ book.get_total_sum }}
Another way is to inject the value you want by obtaining it with Python code in the view get_context method and injecting it into the context. For a computed value that is different for each Book instance, this obviously does not work, and a property is ideal. Custom template tags are ideal when the code is not naturally bound to one class as a property

Implementing one to many between an article and page models in Wagtail

I'm trying to setup a Wagtail site with an article to pages structure but I'm struggling. A review article for example may have an introduction page, a benchmark page and a conclusion page. I want to work out how to allow this relationship in wagtail and have it so that editors can add multiple pages to the same article on the same page. I can imagine the pages interface looking a bit like how you have content, promote and settings on pages but with the ability to add, rename and reorder pages. I've tried using a foreign key on a page model that links to an article but I can't get it to be shown in the admin the way I want.
Here is the django version of model layout I was looking to use. You have a parent article that is then made up of one or multiple pages. The pages should be editable, orderable and be created from within one panel in the admin with streamfields:
Class Article(models.Model)
STATE_DRAFT = 0
STATE_REVIEW= 1
STATE_PUBLICATION = 2
STATE_HIDDEN = 3
​
STATE = (
(STATE_DRAFT, 'draft'),
(STATE_REVIEW, 'pending review'),
(STATE_PUBLICATION, 'ready for publication'),
(STATE_HIDDEN, 'hide and ignore'),
)
title = models.CharField(_('title'), max_length=256)
slug = models.SlugField(
_('slug'), unique=True, blank=True, default='', max_length=256
)
description = models.TextField(
_('description'), max_length=256, blank=True, default=''
)
author = models.ForeignKey(
User, on_delete=models.CASCADE, related_name='article'
)
publication = models.DateTimeField(
null=True, blank=True, default=None, db_index=True, help_text='''
What date and time should the article get published
'''
)
state = models.PositiveIntegerField(
default=0, choices=STATE, help_text='What stage is the article at?'
)
featured = models.BooleanField(
default=False,
help_text='Whether or not the article should get featured'
)
​
class Page(Page):
article = models.ForeignKey(
'Article', on_delete=models.CASCADE, related_name='pages'
)
title = models.CharField(max_length=256)
number = models.PositiveIntegerField(default=1) # So pages are ordered
body = models.TextField(blank=True)
As per my comment I don't think you'll be able to achieve everything you're looking for short of implementing an entirely bespoke CMS - but if you're able to bend the UI and data modelling requirements, then Wagtail's RoutablePageMixin is one possible way of achieving the general pattern of editing an article as a single unit, while presenting it as multiple pages on the front-end.
In this approach, you'd make Article a Wagtail Page model, with all of the sub-page content defined as fields (or InlinePanel child models) on that model. (If you want to split the content entry into tabs within the editing interface, see Customising the tabbed interface, although this won't support dynamically adding / reordering them.) You'd then define a URL route and template for each subpage of the article:
from wagtail.core.models import Page
from wagtail.contrib.routable_page.models import RoutablePageMixin, route
class ArticlePage(RoutablePageMixin, Page):
intro = StreamField(...)
main_page = StreamField(...)
conclusion = StreamField(...)
#route(r'^$')
def intro_view(self, request):
render(request, 'article/intro.html', {
'page': self,
})
#route(r'^main/$')
def main_page_view(self, request):
render(request, 'article/main_page.html', {
'page': self,
})
#route(r'^conclusion/$')
def conclusion_view(self, request):
render(request, 'article/conclusion.html', {
'page': self,
})
In this example the three sub-pages are hard-coded, but with some more work (perhaps an InlinePanel child model with a slug field and a StreamField) you could make the subpages dynamic.
I saw gasman already provided an answer to you question, but I'm still going to write up an answer for two reasons:
I think you need some more pointers as to why gasmans' proposal is a better solution than yours, but it's way to much to write in a comment.
I have implemented a similar solution before, where there is a top level 'Article'-like object with multiple reorderable child objects, where the actual content resides.
Why you should make Article a Page subclass
You chose not to make Article a subclass of Page, and you said it was because the Article itself does not contain any content, only metadata about an article. That is not a very strange thought process, but I think you're looking at the wrong requirements for your Article model.
Let's look at Wagtail's own Page model. What kind of functionality does it provide out of the box?
It provides a tree structure with parent and child pages, so that your page can be placed somewhere in the hierarchy of your website
It provides a slug_field, so that Wagtail can automatically handle linking to your page.
It provides functionality for drafting, publishing and unpublishing.
Wagtail doesn't dictate anything about content, leaving you to decide what kind of content you want to put on your Page subclass, if any. Examples of Pages that do not have a body would be:
Contact forms.
Blog index pages.
Good questions you could ask when deciding whether you want a Model to be a subclass of a Page are:
Do I want this object to have it's own url?
Do I want to be able to place this object somewhere inside my website hierarchy?
Do I want to have SEO advantages for the object?
Do I want to be able to publish/unpublish this object or not?
In your case of the Article, you could say yes to almost al these question, so it'd be wise to make it a Page subclass. That way, you don't have to reinvent the wheel.
How you define the actual 'body' of your page is up to you.
You can place the actual content in either snippets, or subpages to that Article. Or you can even choose to create a list of StreamFields inside your model.
How to implement ordered subcontent.
I have implemented a structure like this before.
The way I did this was very similar to what gasman proposes.
In my case, I needed to create a website where you could find an object (like you article) and display different types of explanation modules for it. For each document, I created a ArticlePage, and for each explanation module, I created a snippet called ExplanationModule.
I then created a through model with an ordering, and added a RoutablePageMixin to the class like gasman explains.
The structure looks something like this:
#register_snippet
class ArticlePageModule(models.Model):
...
title = models.CharField(max_length=100)
body = StreamField(LAYOUT_STREAMBLOCKS, null=True, blank=True)
panels = [
FieldPanel('title'),
StreamFieldPanel('body'),
]
class ArticlePageModulePlacement(Orderable, models.Model):
page = ParentalKey('articles.ArticlePage', on_delete=models.CASCADE, related_name='article_module_placements')
article_module = models.ForeignKey(ArticlePageModule, on_delete=models.CASCADE, related_name='+')
slug = models.SlugField()
panels = [
FieldPanel('slug'),
SnippetChooserPanel('article_module'),
]
class ArticlePage(Page, RoutablePageMixin):
# Metadata and other member values
....
content_panels = [
...
InlinePanel('article_module_placements', label="Modules"),
]
#route(r'^module/(?P<slug>[\w\-]+)/$')
def page_with_module(self, request, slug=None):
self.article_module_slug = slug
return self.serve(request)
def get_context(self, request):
context = super().get_context(request)
if hasattr(self, 'article_module_slug'):
context['ArticlePageModule'] = self.article_module_placements.filter(slug = self.article_module).first().article_module
return context
What this does is the following:
Create a ArticlePageModule snippet, which is just some kind of content, like a title and a body.
Create a ArticlePageModulePlacement which links a ArticlePage to a module, and adds the following:
A slug
An Ordering (Because it subclasses the Orderable mixing)
Create a ArticlePage which does two things:
Define a ArticlePageModuleplacement panel, which allows you to add ArticlePageModulePlacements
Subclass RoutablePagemixin, as described in gasman's answer.
This provides you with a Wagtail-proof, reusable and robust way of creating Articles with SubContent.
The modules don't show up in tabs, but will be shown on the page's layout page under a panel called 'Modules'.

dynamic slug with permanent redirect or store slug on database

Which is the best option for urls on a news page:
Dynamically generate slugs. Load the page from the object id. If the slug doesn't match, permanent redirect to the correct slug.
myweb.com/542/my-news-item
Cons i see: If the news title is changed the slug changes, but the old slug will redirect to the new one, so i dont know if it is a problem for lookups.
OR:
Static slug that will never change, even if the news title is changed.
myweb.com/my-news-item
Cons i see: One more field on the db. If i change the news title radically, the slug will be very different
If you want slugs to update, without breaking the old urls, you could separate slugs and link the latest in your list views, something along these lines should do it:
class Article(models.Model):
title = models.CharField() # etc
class ArticleSlug(models.Model):
article = models.ForeignKey(Article)
slug = models.SlugField(unique=True)
date_created = models.DateTime(auto_now_add=True, editable=False)
class Meta:
get_latest_by = "date_created"
In your enlisting template you could simply call the latest slug, but you'll probably want to have some M/Y/D hierarchy in the urls aswell
{{ article.title }}
If your site gets a lot of traffic, you might want to add a celery task that retrieves the latest slug and copies it to a field on your article model now and then. That will save you some SQL JOINs.
How about a combination of using the redirects app and a post save signal like what this guy wrote.

Categories