Need help writing a Unit Test in Django - python

Good day everybody.
I need to test a view, and I got stuck ( I am a django newbie).
I got through all other url and view tests, but I'm really not sure how to write this one.
I tried writing it on my own, I read through the testing docs, I even tried testing this using model_mommy ( but I got a custom HTML field in my models ) which is not supported by mommy. I tried with mommy Recipes, also without luck. I really gotta do this test today, it's a part of a task I was given.
here is the view :
class CommentCreateView(CreateView):
def get(self, request, *args, **kwargs):
context = {'form': CommentForm()}
return render(request, 'news/add_comment_to_article.html', context)
def post(self, request, *args, **kwargs):
form = CommentForm(request.POST)
if form.is_valid():
article = get_object_or_404(Article, pk=kwargs.get('pk'))
print(article)
comment = form.save(commit=False)
comment.post = article
comment.save()
return HttpResponseRedirect(reverse('news:article', kwargs={'article_id': article.pk}))
else:
form = CommentForm()
return render(request, 'news/add_comment_to_article.html', {'form': form})
and here are my models:
class Article(models.Model):
title = models.CharField('title', max_length=200, blank=True)
slug = AutoSlugField(populate_from='title', default="",
always_update=True, unique=True)
author = models.CharField('Author', max_length=200, default="")
description = HTMLField()
is_published = models.BooleanField(default=False)
article_text = HTMLField('Article text', default="")
pub_date = models.DateTimeField(default=datetime.now, blank=True)
article_category = models.ForeignKey(Category, on_delete="models.CASCADE", blank=True, null=True, default="")
my_order = models.PositiveIntegerField(default=0, blank=False, null=False)
class Meta(object):
ordering = ['my_order']
def __str__(self):
print(self.image.all())
return self.title
class ArticleImages(models.Model):
article = models.ForeignKey(Article, on_delete="models.CASCADE", related_name="image")
image = models.ImageField("image")
my_order = models.PositiveIntegerField(default=0, blank=False, null=False)
def image_tag(self):
return mark_safe('<img src="/media/%s" width="150" height="150" />' % (self.image))
image_tag.short_description = 'Image'
class Meta(object):
ordering = ['my_order']
def __str__(self):
return self.image.url
class Comment(models.Model):
post = models.ForeignKey('Article', on_delete=models.CASCADE, related_name='comments')
author = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(default=datetime.now, blank=True)
approved_comment = models.BooleanField(default=False)
def approve(self):
self.approved_comment = True
self.save()
def __str__(self):
return self.text
I would REALLY appreciate someone helping me out here.
Thank you, and have a good day !

Related

How to Filter out Django Models

How do I create a lesson in a course without it showing in another course. I have a foreign key which is the course and it is under the models Lesson. I want to only view the lesson that is created under the certain course. But my problem is when I create a lesson in course 1, the lesson also shows in course 2. (sorry for bad english)
views.py
def lessonpage(request):
lesson = Lesson.objects.all()
if request.user.is_authenticated:
return render(request, "lessons/lessons.html", {'lessons': lesson})
else:
return redirect('loginpage')
def addlesson(request):
if request.method == "POST":
form = AddLessonForm(request.POST)
if form.is_valid():
form.save()
return render(request, "lessons/successlessons.html", {'form1': form})
form = AddLessonForm()
return render(request, "lessons/addlessons.html", {'form': form})
def deletelessons(request, id):
lesson = Lesson.objects.get(id=id)
lesson.delete()
return redirect("lessonspage")
models.py
from django.db import models
class Section(models.Model):
nameofsection = models.CharField(max_length=50, default="")
def __str__(self):
return self.nameofsection
class Course(models.Model):
ctitle = models.CharField(max_length=50, default="")
cdescription = models.TextField(max_length=200, default="")
#csection = models.ForeignKey(Section, on_delete=models.CASCADE)
def __str__(self):
return self.ctitle
def __unicode__(self):
return self.ctitle
class Meta:
db_table="courses"
class Lesson(models.Model):
title = models.CharField(max_length=50, default="")
description = models.TextField(max_length=200, default="")
course = models.ForeignKey(Course, on_delete=models.CASCADE, blank=True, null=True)
def __str__(self):
return self.title
urls.py
path('course/', coursepage, name="coursepage"),
path('course/<int:pk>', CourseDetailView.as_view(), name='detailed'),
path('addcourse/', addcourse, name="addcoursepage"),
path('editcourse/<int:id>', updatecourse, name="editcoursepage"),
path('updatecourse/<int:id>', updatecourserecord, name="updatecourse"),
path('deletecourse/<int:id>', deletecourse, name="deletecourse"),
path('lessons', lessonpage, name="lessonspage"),
path('lessons/addlessons', addlesson, name="addlessonspage"),
path('deletelessons/<int:id>', deletelessons, name="deletelessons"),

Django, generic view dynamic filtering

i'm starting out with Django and trying to render all Shows(screenings) that selected Movie had. Here's the code:
url
path('movie/<int:pk>/', MovieDetails.as_view(), name='movie'),
Models
class Movie(models.Model):
title = models.CharField(max_length=200)
description = models.CharField(max_length=255, blank=True)
def __str__(self):
return f'{self.title}'
class Show(models.Model):
show_date = models.DateField()
start_time = models.TimeField()
movie = models.ForeignKey(Movie, on_delete=models.CASCADE, null=True, blank=True)
city = models.ForeignKey(City, on_delete=models.CASCADE, null=True, blank=True)
title = models.CharField(max_length=200, blank=True)
def __str__(self):
return f'{self.show_date}'
View
class MovieDetails(DetailView):
model = Movie
context_object_name = 'movie'
def get_queryset(self):
self.movie = get_object_or_404(Movie, id=self.kwargs['pk']) #find movie by id from url
shows_played = Show.objects.filter(movie=self.movie)
print(shows_played) #prints out some shows
return shows_played
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['shows_played'] = Show.objects.filter(movie=self.movie)
return context
The shows_played prints out some shows, so it seems like everything is fine but when the url: /movies/1
is called I get a 404, No show found matching the query rendered in browser and
Not Found: /movie/1/ printed in console
What am i doing wrong?
Thank you
I figured it out. My mistake was that i was using DetailView instead of ListView(which has get_queryset method) for "MovieDetails".

IsOwnerOrReadOnly permission

I'm trying to do crud API with IsOwnerOrReadOnly permission but other users can still delete posts from the others. Could you please have a look? I have no clue what goes wrong. My guess is that it has something to do with this line
return obj.author == request.user.userprofile
// permissions.py
from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission(self,request,view, obj):
if request.method in permissions.SAFE_METHODS:
return True
return obj.author == request.user.userprofile
// views.py
class PostDetail(APIView):
permission_classes = [
permissions.IsAuthenticatedOrReadOnly,
IsOwnerOrReadOnly,
]
def get_obj(self, pk):
try:
return Post.objects.get(id=pk)
except Post.DoesNotExist:
raise Http404
def get(self, request, pk, format=None):
post = self.get_obj(pk)
serializer = PostSerializer(post)
return Response(serializer.data)
def put(self, request, pk, format=None):
post = self.get_obj(pk)
serializer = PostSerializer(post, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk, format=None):
post = self.get_obj(pk)
post.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
// models.py
class Post(models.Model):
id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False)
author = models.ForeignKey(Profile,on_delete=models.CASCADE)
title = models.CharField(max_length=200, blank=True, null=True)
content = models.TextField(blank=True, null=True)
tags = models.ManyToManyField('Tag',blank=True)
answers = models.IntegerField(default=0)
last_modified = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
class Profile(models.Model):
id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False)
user = models.OneToOneField(User, related_name='userprofile', on_delete=models.CASCADE)
name = models.CharField(max_length=200, blank=True, null=True)
email = models.EmailField(max_length=200, blank=True, null=True)
location = models.CharField(max_length=200, blank=True, null=True)
intro = models.CharField(max_length=200, blank=True, null=True)
bio = models.TextField(blank=True, null=True)
profile_image = models.ImageField(default=None, upload_to='profile/', blank=True, null=True)
github = models.CharField(max_length=200, blank=True, null=True)
linkedin = models.CharField(max_length=200, blank=True, null=True)
created = models.DateTimeField(default=timezone.now)
def __str__(self):
return str(self.user.username)
I think the object permission is never called, Try to explicitly call the APIVIew check_object_permissions in the get_obj method.
def get_obj(self, pk):
obj = get_object_or_404(Post, pk=pk)
self.check_object_permissions(self.request, obj)
return obj
https://www.django-rest-framework.org/api-guide/permissions/#object-level-permissions

Getting error during adding a comment as notnull

I don't understand why I am getting this one I tried making null=True, blank=True but still, it does not solve my error, at last, I thought of sending it here ...!! please tell me where I am going wrong
Models.py
class Certification(models.Model):
id = models.UUIDField(default=uuid.uuid4,
unique=True, primary_key=True, editable=False)
course_name = models.CharField(max_length=255)
course_image = models.ImageField()
course_taken = models.CharField(max_length=255)
mentor_name = models.CharField(max_length=20, blank=True, null=True)
slug = models.SlugField(unique=True, null=True)
#body = RichTextField()
body = RichTextUploadingField()
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.course_name
class Comment(models.Model):
certificate = models.ForeignKey(Certification, on_delete=models.CASCADE)
name = models.CharField(max_length=200)
body = models.TextField(null=True, blank=True)
forms.py
class CommentForm(ModelForm):
class Meta:
model = Comment
fields = '__all__'
exclude = ['certificate']
def __init__(self, *args, **kwargs):
super(CommentForm, self).__init__(*args, **kwargs)
self.fields['name'].widget.attrs.update(
{'class': 'form-control form-control-sm',})
self.fields['body'].widget.attrs.update(
{'class': 'form-control form-control-sm',})
Views.py
def certificatePage(request,pk):
certi = Certification.objects.get(id=pk)
count = certi.comment_set.count()
comments = certi.comment_set.all()
form = CommentForm()
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.certi = certi
comment.save()
context = {
"certi": certi,
'count':count,
'comments':comments,
'form':form
}
return render (request, 'base/certificate.html',context)
Click On The Image To See The Error

Django get_absolute_url() returning user to homepage

When a user creates a post using the CreateView I want it so when a user submits the Post, they then see the post they just made. But for some reason my get_absolute_url() is not working.
Prior to this I started to work on slugifying the Post and Category models and haven't been able to see if they work due to the fact get_absolute_url won't work.
Models:
class Category(models.Model):
title = models.CharField(max_length=200)
colorcode = models.CharField(max_length=20, blank=True, null=True)
description = models.TextField()
image = models.ImageField(blank=True, null=True)
slug = models.SlugField(unique=True)
def __str__(self):
return self.title
class Post(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
category = models.ForeignKey(Category, on_delete=models.CASCADE, blank=True, null=True)
image = models.ImageField(blank=True, null=True)
live = models.BooleanField(default=False)
slug = models.SlugField(unique=True)
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={'slug': self.slug})
def create_slug(instance, new_slug=None):
slug = slugify(instance.title)
if new_slug is not None:
slug = new_slug
qs = Post.objects.filter(slug=slug).order_by("-pk")
exists = qs.exists()
if exists:
new_slug = "%s-%s" %(slug, qs.first().pk)
return create_slug(instance, new_slug=new_slug)
return slug
def pre_save_post_reciever(sender, instance, *args, **kwargs):
if not instance.slug:
instance.slug = create_slug(instance)
pre_save.connect(pre_save_post_reciever, sender=Post)
Views:
class IndexView(ListView):
model = Post
queryset = Post.objects.filter(live=True)
template_name = "public/index.html"
class PostEdit(object):
model = Post
fields = '__all__'
success_url = '/'
class PostCreateView(LoginRequiredMixin, PostEdit, CreateView):
fields = ['title', 'text', 'category', 'image']
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
class PostUpdateView(LoginRequiredMixin, PostEdit, UpdateView):
fields = ['title', 'text', 'category', 'image']
Anyone has any idea on how to fix this?
If behaves according to this definition:
class PostEdit(object):
model = Post
fields = '__all__'
success_url = '/' # <<<---
In your case success_url is not static and cannot be defined as attribute. You have to override get_success_url instead like that:
def get_success_url(self):
return self.get_object().get_absolute_url()
also have a look at this answer.
upd
If the redirect is that simple then, as Daniel Roseman mentioned, you don't need to specify success_url at all - what you want is the default behavior.
You don’t even need to provide a success_url for CreateView or UpdateView - they will use get_absolute_url() on the model object if available.

Categories