Show post in django admin page but don't on site - django

I'm creating simple blog and face with problem. I need to have separate type of posts in Django admin page which would be saved, but not showed on site. For example, when somebody suggest post, I want at first read it and after that publish, or when I'm writing a post and want go on after some time I need to save it.
blog/models.py
class Post(models.Model):
author = models.ForeignKey(User, default=1)
title = models.CharField(max_length = 50)
pub_date = models.DateTimeField(default=timezone.now)
content = models.TextField(max_length = 50000)
published = models.BooleanField(default=False)
def __str__(self):
return self.title
def get_absolute_url(self):
return "/blog/%i/" % self.pk
blog/admin.py
class PostAdmin(admin.ModelAdmin):
fieldsets = (
('Title', {'fields' : ['title']}),
('Date', {'fields' : ['pub_date'], 'classes' : ['collapse']}),
('Content', {'fields' : ['content']}),
)
list_display = ('title', 'pub_date')
list_filter = ['pub_date']
search_fields = ['title']
admin.site.register(Post, PostAdmin)
blog/views.py
class PostsListView(ListView):
model = Post

You can modify your list view to only show published posts by overriding get_queryset.
class PostsListView(ListView):
model = Post
def get_queryset(self):
return super(PostsListView, self).get_queryset().filter(published=True)
If you have a detail view, you should override get_queryset in the same way.
In your model admin, you can add published to list_filter. This makes it easy to filter published/unpublished posts.
class PostAdmin(admin.ModelAdmin):
...
list_filter = ['pub_date', 'published']

Related

Set CharField to RTL in Django Admin site

The frontend of my Django site is in Persian language which is RTL and everything is ok except that the CharField model fields are in LTR direction when edited in the Admin site.
Here's my model:
class Post(models.Model):
STATUS_CHOICES = (('draft', 'Draft'), ('published', 'Published'))
title = models.CharField(max_length=100)
slug = models.SlugField(max_length=100, allow_unicode=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='blog_posts')
lead = RichTextField()
body = RichTextUploadingField()
created_on = models.DateTimeField(auto_now_add=True)
published_on = models.DateTimeField(default=timezone.now)
updated_on = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
is_featured = models.BooleanField(default=False, verbose_name='Featured Post')
objects = models.Manager()
published = PublishedManager()
featured = FeaturedManager()
class Meta:
ordering = ('-published_on',)
def __str__(self):
return self.title
I know I can set the site's language to Persian and solve this issue but I don't want to because the Persian translation of Django is dull.
Another solution is to use one of available Rich Text editors (tinymce or ckeditor) but those are overkill for a CharField field.
I also tried custom admin form like this:
class PostAdminForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'slug', 'author', 'lead', 'body', 'status', 'is_featured']
widgets = {'title': forms.TextInput(attrs={'dir': 'rtl'})}
#admin.register(Post, PostAdminForm)
class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'slug', 'created_on', 'published_on', 'status', 'is_featured')
list_filter = ('status', 'created_on', 'published_on', 'is_featured')
search_fields = ('title', 'body')
prepopulated_fields = {'slug': ('title',)}
raw_id_fields = ('author',)
date_hierarchy = 'published_on'
ordering = ('status', 'created_on', 'published_on')
But it gives me this error:
AttributeError: 'ModelFormOptions' object has no attribute 'abstract'
In your admin.py file for your app, you can create a custom form for your model. I don't know your model so I will use general names for this as an example:
from django.contrib import admin
from app_name.models import *
from django import forms
class CustomAdminForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ['mycharfield']
widgets = {'mycharfield':forms.TextInput(attrs={'dir':'rtl'})}
admin.site.register(MyModel,CustomAdminForm)
This should make the mycharfield text input render as being RTL on the admin page for the MyModel form. The line widgets = {'mycharfield':forms.TextInput(attrs={'dir':'rtl'})} will change the text input widget's dir attribute to the rtl value. If you have more than one CharField in your model and want RTL for all of them simply add each field to the fields attribute in the form and do the same thing with the widget attribute for each field.
As the answer provided by Nathan was partially correct, I did my own research and found that the correct way is this:
class CustomPostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'slug', 'lead', 'body']
widgets = {'title': forms.TextInput(attrs={'dir': 'rtl', 'class': 'vTextField'})}
and then:
#admin.register(Post)
class PostAdmin(admin.ModelAdmin):
form = CustomPostForm
What surprises me is that the above code removed vTextField class from the input field so I had to add it again.

How to create a view for nested comments in Django rest framework?

I want to have a nested comment system for my project. I have product model so I want to clients can comment on my products. I have my product and comment models and serializers and I related comments to products in product serializer so I can show product comments. what should i do to clients can write their comment for products??? the comments must be nested. this is my code:
#models
class Comment(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='comments')
parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True,blank=True, related_name='replys')
body = models.TextField()
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f'{self.user} - {self.body[:30]}'
class Meta:
ordering = ('-created',)
#serializers:
class CommentSerializer(serializers.ModelSerializer):
class Meta:
model = Comment
fields = ['id', 'user', 'product', 'parent', 'body', 'created']
class ProductSerializer(serializers.ModelSerializer):
comments = CommentSerializer(many=True, read_only=True)
class Meta:
model = Product
fields = ['id', 'category', 'name', 'slug', 'image_1',
'image_2', 'image_3', 'image_4', 'image_5',
'description', 'price', 'available', 'created', 'updated', 'comments']
lookup_field = 'slug'
extra_kwargs = {
'url': {'lookup_field': 'slug'}
}
#views:
class Home(generics.ListAPIView):
queryset = Product.objects.filter(available=True)
serializer_class = ProductSerializer
permission_classes = (permissions.AllowAny,)
filter_backends = [filters.SearchFilter]
search_fields = ['name', 'category__name', 'description']
class RetrieveProductView(generics.RetrieveAPIView):
queryset = Product.objects.all()
serializer_class = ProductSerializer
permission_classes = (permissions.AllowAny,)
lookup_field = 'slug'
In this case, better keep your db normalized, it means that you can't have a field that has many fields (Rule of Normalization 2).
Based on Rest paradigm, you can make comments as another sub-app where it is referenced by its own url (ex localhost:8000/comments)
this will be consumed by the frontend, where the SPA will show for users in one site the product section with the comment section that will be autmotaically reversed to the model of Product at the Backend
Long Story short:
two independent apps communicating together.
N.B: Stocking that way can also help you after for Data Engineering and Data Collection, it optimizes the process of grabbing, stocking and cleaning.

Displaying ManyToManyField correctly in DjangoAdmin

I'm trying to add a Likes model to a Posts application so that it records every time a User 'likes' a determined post. I have already added the likes field to the Posts model as a ManyToManyField and have tried to register it to display in the Django Admin, more exactly in the Post detail, but the result of the code I have only displays a list of all users where it should only be a list of the users that have liked the corresponding post.
Here's the code for my Posts model:
from django.db import models
from django.contrib.auth.models import User
class Post(models.Model):
# ForeignKey that relates the post to the user that published it and their corresponding profile.
user = models.ForeignKey(User, on_delete=models.PROTECT)
profile = models.ForeignKey('users.Profile', on_delete=models.PROTECT)
title = models.CharField(max_length=255)
photo = models.ImageField(upload_to='posts/pics')
description = models.TextField(max_length=2000, blank=True)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
# ManyToManyField that translates to the users that have liked the post
likes = models.ManyToManyField(User, blank=True, related_name='post_likes')
def __str__(self):
return '{} by {}'.format(self.title, self.user.username)
def get_likes(self):
return '\n'.join([l.likes for l in self.likes.all()])
Also this is the code for the admin.py file.
#admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = (
'pk',
'user',
'title',
'photo',
'created',
'modified',
'get_likes',
)
list_display_links = ('pk', 'title',)
list_editable = ('photo',)
search_fields = (
'post__user',
'post__title'
)
list_filter = (
'created',
'modified'
)
fieldsets = (
('Profile', {
'fields' : (
'user',
)
}),
('Post', {
'fields' : (
'title',
'photo',
'likes',
)
})
)
How can I get the Django admin to display the ManyToManyField correctly in the post detail (i.e. display the users that have actually liked the post instead of a list of all users)?

Modifying django object model for better admin CRUD management

I am writing a blog app using django 1.10
This is a snippet of my object model:
model.py
class Attachment(models.Model):
title = models.CharField(max_length=50)
image = models.ImageField(upload_to='attachments')
class FileAttachments(models.Model):
title = models.CharField(max_length=50)
attachments = models.ManyToManyField(Attachment)
class Post(models.Model):
title = models.CharField(max_length=200)
text = models.CharField(max_length=2000)
file_attachments = models.ForeignKey(FileAttachments, blank=True, null=True)
slug = models.SlugField(max_length=40, default='', unique=True)
author = models.ForeignKey(User, default=1)
pub_date = models.DateTimeField(blank=True, null=True)
def get_absolute_url(self):
return "/blog/%s/%s/%s/%s/" % (self.pub_date.year, self.pub_date.month, self.pub_date.day, self.slug)
def __unicode__(self):
return self.title
class Meta:
verbose_name = "Blog Post"
verbose_name_plural = "Blog Posts"
ordering = ["-create_date"]
permissions = (
( "create", "Create Post" ),
( "modify", "Modify Post" ),
( "delete", "Delete Post" ),
)
(simplified) admin.py:
class PostAdmin(admin.ModelAdmin):
prepopulated_fields = {"slug": ("title",)}
exclude = ('author',)
def save_model(self, request, obj, form, change):
obj.author = request.user
obj.save()
# Register your models here.
admin.site.register(Post, PostAdmin)
when I try to access the Post object via the admin page - in the list view, I only see 'Post object' - whereas I want to see the title of the post (and possibly, a few other attributes of the Post object) - how do I modify the admin view to achieve this?
For your first problem - you need to define list_display in your PostAdmin, like that:
class PostAdmin(admin.ModelAdmin):
prepopulated_fields = {"slug": ("title",)}
exclude = ('author',)
list_display = ('title', 'pub_date')
As for your second problem - please stick to the 'One post, one problem' rule; hint - ForeignKey means only one FileAttachment can be related to your Post.
Change __unicode__ for __str__ in your Post class and print whatever you want. For example: return "Blog %s published on %s" %(self.title, self.pub_date).
Your Post model only includes one attachment through a foreign key. That way it will be impossible to upload more than one file. In other words, you have to change your models, for example including a key in FileAttachments relating to a Post and removing the key from Post model.
Hope this helps.

Adding multiple records into django admin

I would like to be able add multiple records at a time in django admin.
models.py
class Photo(models.Model):
pub_date = models.DateTimeField('date published')
sort = models.IntegerField()
photo_category = models.ForeignKey(Photocategory)
title = models.CharField(max_length=200)
title_url = models.SlugField(max_length=200)
main_image = models.ImageField(blank=True, null=True, upload_to='images/photo/')
# size is "width x height"
cropping = ImageRatioField('main_image', '350x350')
def image_thumbnail(self):
return '<img width="160px" src="/media/%s"/>' % (self.main_image, self.main_image)
image_thumbnail.allow_tags = True
image_thumbnail.short_description = 'main_image'
def __unicode__(self):
return self.title
admin.py
class PhotoAdmin(ImageCroppingMixin, admin.ModelAdmin):
prepopulated_fields = {'title_url': ('title',)}
list_display = ('title', 'photo_category', 'image_thumbnail', 'sort')
list_filter = ['photo_category']
admin.site.register(Photo, PhotoAdmin)
Screenshot:
Is there a way I could do lets say 5 at a time on the 1 screen, it is very slow filling that out 1 by 1. I can do it in mysql with SQL query but I would like to achieve this here.
Thanks
Hey Yes this is possible but Out of the Box,,
Here is what you will have to do:
Define a Formset (to create multiple photo forms) in form Attribute of PhotoAdmin
You will see a formset on the add photo Admin page, and should work correctly. If you don't then you can over-ride the templates by providing add_form_template and change_form_template attributes in Admin and display that form-set templates.
Handle Saving of Multiple objects in the Formset
For example:
# admin.py
#admin.register(Photo)
class PhotoAdmin(ImageCroppingMixin, admin.ModelAdmin):
prepopulated_fields = {'title_url': ('title',)}
list_display = ('title', 'photo_category', 'image_thumbnail', 'sort')
list_filter = ['photo_category']
form = MyFormset
add_form_template = "photo/admin/my_add_form.html"
change_form_template = "photo/admin/my_change_form.html"
This is a rough workflow, you will have to try this and make modification if required.
You can refer to this documentation: https://docs.djangoproject.com/en/1.6/ref/contrib/admin/#modeladmin-options