How to allow auth users to send newsletters from django admin - django

I'm implementing a newsletter app for a company website. My goal is to allow the 'future' website administrator to fire a newsletter directly from the admin.
For doing so, I wrote the following code:
models.py
from django.db import models
from ckeditor.fields import RichTextField
class NewsletterSubscription(models.Model):
datetime = models.DateTimeField(auto_now_add = True)
email = models.EmailField(max_length=128)
class Meta:
verbose_name = 'Iscritto Newsletter'
verbose_name_plural = 'Iscritti Newsletter'
def __unicode__(self):
return self.email
class Newsletter(models.Model):
EMAIL_STATUS_CHOICES = (
('Draft', 'Draft'),
('Pubblicata', 'Pubblicata')
)
subject = models.CharField(max_length=250)
body = RichTextField()
email = models.ManyToManyField(NewsletterSubscription)
status = models.CharField(max_length=10, choices=EMAIL_STATUS_CHOICES)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.subject
I'd like to know if is possible to add to the NewsletterAdminForm a sort of button which allows to fire the email.
admin.py
from django import forms
from django.contrib import admin
from .models import NewsletterSubscription, Newsletter
from ckeditor.widgets import CKEditorWidget
class NewsletterSubscriptionAdmin(admin.ModelAdmin):
list_display = ('email', 'datetime', )
class NewsletterAdminForm(forms.ModelForm):
body = forms.CharField(widget=CKEditorWidget())
class Meta:
model = Newsletter
fields = '__all__'
class NewsletterAdmin(admin.ModelAdmin):
form = NewsletterAdminForm
admin.site.register(NewsletterSubscription, NewsletterSubscriptionAdmin)
admin.site.register(Newsletter, NewsletterAdmin)
Thank you in advance for any help you can provide.

To get a button in the admin panel you can simply create a method which will return the html:
class NewsletterAdmin(admin.ModelAdmin):
...
readonly_fields = ['send_mails']
def send_mails(self, obj):
url_red = 'url_of_your_view_to_send_mails'
return format_html(
'<a class="button" href="{}">Send</a> ',
url_red,
)
This will then get rendered as a button in the admin page which will send a GET request to the url supplied of the view, where you can define all the logic and send mails . Do include this custom field in the fields attribute.
Hope it helps.

Related

making an API that adds instances to ManyToMany fields of a model in django rest framework

I am making a movie watching website in which there are users and films and the user model has a ManyToMany Field that references the film model. it's called WatchList and an authenticated user can add any movie they want to this watchlist.
My problem is that I want an API that only gets the ID of a film and adds it to the user's watch list.
these are my models and serializers and I am trying to make a view to implement this API.
# models.py
class Film(models.Model):
filmID = models.AutoField(primary_key=True)
title = models.CharField(max_length=150)
# ...
class User(AbstractBaseUser, PermissionsMixin):
userID = models.AutoField(primary_key=True)
username = models.CharField(max_length=100, unique=True, validators=[RegexValidator(regex="^(?=[a-z0-9._]{5,20}$)(?!.*[_.]{2})[^_.].*[^_.]$")])
email= models.EmailField(max_length=100, unique=True, validators=[EmailValidator()])
name = models.CharField(max_length=100)
watchList = models.ManyToManyField(Film)
objects = UserManager()
USERNAME_FIELD = 'username'
# serializers.py
class WatchListSerializer(serializers.ModelSerializer):
class FilmSerializer(serializers.ModelSerializer):
model = Film
fields = ('filmID', 'title',)
read_only_fields = ('filmID', 'title')
film_set = FilmSerializer(read_only=True, many=True)
class Meta:
model = get_user_model()
fields = ('userID', 'film_set')
read_only_fields = ('userID',)
# views.py
class WatchListAddView(...):
pass
The serializer can be changed. but this kind of shows what I want the api to be. the authentication validation part is already taken care of, so imagine that any request to the view is from an authenticated user.
I would not recommend patching this directly and instead create a separate endpoint for adding removing data to this field.
In your case it would look like this. I show just a small working example, you can adjust it to your needs
from django.shortcuts import get_object_or_404
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
#action(detail=True,
methods=['POST'])
def add_film_to_watch_list(self, request, **kwargs):
film = get_object_or_404(klass=Film, filmID=kwargs.get('filmID'))
user = self.get_object()
user.watchList.add(film)
return Response("Success")

My views.py is returning null from django admin object

I would really appreciate some help on this because I'm completely stuck. I've started up a simple django app (trying to make an instagram clone). However, when I try to display the post objects (which I created in the django admin page) nothing is displayed in index.html, so I tried printing out the objects in the views.py and it's returning to me an empty query set. I don't quite understand what I'm doing wrong and why I can't access the objects? When I print out the username I am able to get that, but then nothing for both post and stream objects. Please I'm so stuck any advice would be appreciated.
views.py
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from django.template import loader
from django.http import HttpResponse
# Create your views here.
from post.models import post, stream
#login_required
# we are getting all of the string objects that are created for the user
def index(request):
user = request.user
print(user)
posts = stream.objects.filter(user=user)
print(posts)
group_ids = []
#then looping through and getting post id to a list
for posted in posts:
group_ids.append(posted.post_id)
print(group_ids)
#then filtering them so that you can display it in the index
#selecting a specific post by id
post_items = post.objects.filter(id__in=group_ids).all().order_by('-date')
template = loader.get_template('index.html')
context = {'post_items' : post_items}
return(HttpResponse(template.render(context, request)))
models.py
from django.db import models
from django.contrib.auth.models import User
import uuid
# Create your models here.
from django.db.models.signals import post_save
from django.utils.text import slugify
from django.urls import reverse
def user_directory_path(instance,filename):
# this file is going to be uploaded to the MEDIA_ROOT /user(id)/filename
return('user_{0}/{1}'.format(instance.user.id,filename))
class tag(models.Model):
title = models.CharField(max_length = 80, verbose_name = 'tag')
slug = models.SlugField(null = False, unique = True)
class Meta:
verbose_name = 'tag'
verbose_name_plural = 'tags'
# for when people click on the tags we can give them a url for that
# def get_absolute_url(self):
# return(reverse('tags', args = [self,slug]))
def __str__(self):
return(self.title)
def save(self,*args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
return(super().save(*args, **kwargs))
class post(models.Model):
# will create a long id for each post
id = models.UUIDField(primary_key=True, default = uuid.uuid4, editable = False)
image = models.ImageField(upload_to = user_directory_path, verbose_name= 'image', null = True)
caption = models.TextField(max_length = 2000, verbose_name = 'caption')
date = models.DateTimeField(auto_now_add = True)
tags = models.ManyToManyField(tag, related_name='tags')
user = models.ForeignKey(User, on_delete=models.CASCADE)
likes = models.IntegerField()
def get_absolute_url(self):
return reverse('postdetails', args=[str(self.id)])
# def __str__(self):
# return(self.user.username)
class follow(models.Model):
follower = models.ForeignKey(User, on_delete=models.CASCADE, related_name='follower')
following = models.ForeignKey(User, on_delete=models.CASCADE, related_name='following')
class stream(models.Model):
following = models.ForeignKey(User, on_delete=models.CASCADE, related_name='stream_following')
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(post, on_delete=models.CASCADE)
date = models.DateTimeField()
def add_post(sender, instance,*args, **kwargs):
# here we are filtering all the users that are following you
post = instance
user = post.user
followers = follow.objects.all().filter(following=user)
for follower in followers:
streams = stream(post=post, user=follower.follower, date = post.date, following = user)
streams.save()
post_save.connect(stream.add_post, sender=post)
output from print statements
user
<QuerySet []>
[]
I figured it out. It wasn't an issue with the code, but the way that I was creating posts in the admin panel. So because you can only view posts from users that you are following, the posts that I was creating weren't showing up. So I had to create another user, and follow that user, then have the new user post something. Then the post shows up in the page!

how to create tag field in django form like youtube have

i want to create a tag field like youtube give tage field while uploading a vedio this is what i tried in in my blog form
my models.py
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
# Create your models here.
class Blog(models.Model):
author = models.OneToOneField(User, on_delete=models.CASCADE,)
title = models.CharField(max_length=200,blank=False,)
thumbnail = models.ImageField(upload_to='blogs_thumbnail',default='blogdefa.png')
tags = models.CharField(max_length=500, blank=False, default='Blog')
data = models.TextField(blank=False,)
published_date = models.DateTimeField(default=timezone.now,editable=False)
update_at = models.DateTimeField(auto_now=True,editable=False)
def __str__(self):
return self.title
any idea how to do it i don,t know how to do it
my forms.py
from django import forms
from django.forms import ModelForm, Textarea
from django.contrib.auth.models import User
from .models import Blog, comment, report
forms here
class BlogForm(forms.ModelForm):
class Meta:
model = Blog
fields = '__all__'
widgets = {'data': Textarea(attrs={'cols': 80, 'rows': 20, 'placeholder':'Write Here'}),
'title':forms.TextInput(attrs={'placeholder':'Your Blog Title Here'}),
'tags': forms.TextInput(attrs={'placeholder':'Please enter you content related tags'}),
}
exclude = ['author','published_date','update_at']
all i want is user can create his own tag for blogs like in youtube and not like stackoverflow where you have use to choose you tag
please help
currently it look like this
which is not cool
First thing is that tags work. So to get them working you should relate it to your post.
So you should create a Tag model and use a ManytoManyRelated field to relate tags because you need to get to the post/result at the end using tags.
from django.db import models
from django_extensions.db.fields import AutoSlugField
from django.db.models import CharField, TextField, DateField, EmailField, ManyToManyField
class Tag(models.Model):
name = CharField(max_length=31, unique=True, default="tag-django")
slug = AutoSlugField(max_length=31, unique=True, populate_from=["name"])
def __str__(self):
return self.name
class YourPost(models.Model):
name = CharField(max_length=31, db_index=True)
slug = AutoSlugField(max_length=31, unique=True, populate_from=["name"])
description = TextField()
date_founded = DateField(auto_now_add=True)
contact = EmailField()
tags = ManyToManyField(Tag, related_name="tags")
class Meta:
get_latest_by = ["date_founded"]
def __str__(self):
return self.name
Go on from here.
Create serializers, Viewsets. Relate your tags to your post.

Add User full_name in list_filter admin site

I can't figure out how to add the User full_name in the list_filter.
My Blog model is as follows:
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.utils import timezone
class User(AbstractUser):
pass
class Post(models.Model):
POST_STATUS = (('borrador', 'Borrador'), ('publicado', 'Publicado'))
title = models.CharField('titulo', max_length=100)
body = models.TextField('cuerpo')
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='blog_posts', verbose_name='autor')
created = models.DateTimeField('creado', auto_now_add=True)
published = models.DateTimeField('publicado', auto_now=True)
updated = models.DateTimeField('actualizado', auto_now=True)
slug = models.SlugField(max_length=100, unique_for_date='published')
status = models.CharField(max_length=10, choices=POST_STATUS, default='borrador')
class Meta:
ordering = ('-published',)
def __str__(self):
return self.title
As you can see, I have created a custom user model just in case I have to change it in the future.
In the Blog model, there is a 'author' field which uses the User as FK.
I want to add the posibility to filter by 'author' in the Blog's admin site. To do this I tried the following:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import User, Post
admin.site.register(User, UserAdmin)
#admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'author', 'status', 'published')
list_filter = ('author' , 'status', 'published')
search_fields = [('title',), ('body',)]
prepopulated_fields = {'slug': ('title',)}
raw_id_fields = ('author',) # Reemplaza el drop-down para que parezca una lupa (para FKs)
date_hierarchy = 'published'
ordering = ('status', 'published')
The problem is that the filter by 'author' doesn't appear in the admin site:
If I do this: list_filter = ('author__last_name' , 'status', 'published') the filter shows up, but it looks like this ('appellido' means last_name in Spanish:
I would like the filter's text to be 'por autor (by author)' and be able to filter by the author's full name.
Is that possible?
Thanks in advance!!
Probably you can do that with django.contrib.admin.SimpleListFilter:
from datetime import date
from django.contrib import admin
from django.utils.translation import gettext_lazy as _
class PerAuthorListFilter(admin.SimpleListFilter):
title = _('Per Author')
parameter_name = 'per_author'
def lookups(self, request, model_admin):
authors = []
for u in User.objects.all():
authors.append((u.pk, '{} {}'.format(u.first_name, u.last_name)))
return authors
def queryset(self, request, queryset):
queryset = super().queryset(request, queryset)
return queryset.filter(author=self.value())
#admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_filter = [PerAuthorListFilter, ...]

django not add auto increment primary key id when save an article

I hava an article app installed in django admin site,when i finish editing one article,I click the save button,but an error page:
article/models.py
# blog category models
class Category(models.Model):
id = models.IntegerField(primary_key=True,help_text='primary key')
name = models.CharField(max_length=50,help_text='category name')
description = models.TextField(default='',help_text='category description')
createtime = models.DateTimeField(auto_now_add=True)
modifytime = models.DateTimeField(auto_now=True)
categories = models.Manager()
class Meta:
db_table = 'article_category'
def __str__(self):
return self.name
#blog article models
class Article(models.Model):
STATUS = (
(0,'on'),
(1,'off')
)
id = models.IntegerField(primary_key=True,help_text='primary key')
category = models.ForeignKey(Category,help_text='foreigner key reference Category')
title = models.CharField(max_length=100,help_text='article title')
content = models.TextField(help_text='article content')
like = models.IntegerField(default=0,help_text='like numbers')
secretcode = models.CharField(max_length=512,help_text='who has the code can scan')
status = models.IntegerField(choices=STATUS,help_text='status of the article')
createtime = models.DateTimeField(auto_now_add=True,help_text='time that first created')
modifytime = models.DateTimeField(auto_now=True,help_text='time when modified')
articles = models.Manager()
class Meta:
db_table = 'article'
article/widgets.py
from pagedown.widgets import AdminPagedownWidget
from django import forms
from .models import Article
class ArticleModelForm(forms.ModelForm):
content = forms.CharField(widget=AdminPagedownWidget())
class Meta:
model = Article
fields = ('title','category', 'content', 'secretcode', 'status')
article/admin.py
from django.contrib import admin
from .widgets import ArticleModelForm
from .models import Article,ArticleImage,Category
class MMBArticleAdmin(admin.ModelAdmin):
form = ArticleModelForm
admin.site.register(Article,MMBArticleAdmin)
admin.site.register(Category)
admin.site.register(ArticleImage)
the page in the admin site looks likeļ¼š
and then I click save ,the error page show up like above!why did this happen?and how to fix it?
You've overridden the default automatic field with a manual non-autoincrementing ID. Don't do that. Remove your id fields altogether.