I try write tests.py to my views.
I have issue with write a good test to view with slug.
views.py:
def post_detail(request, slug):
post = Post.objects.get(slug=slug)
context = {'post': post}
template = 'post/post_detail.html'
return render(request, template, context)
Url looks like : post/slug_name, and slug is unique for every post.
I try:
tests.py
class PostDetailTestCase(TestCase):
def test_post_detail_(self):
test = Post(title='poost', description="posting", category="letstest", slug='django')
response = self.client.get(reverse('board_detail', args=(self.slug,)))
self.assertEqual(response.status_code, 200)
Run test error:
response = self.client.get(reverse('post_detail', args=(self.slug,
AttributeError: 'PostDetailTestCase' object has no attribute 'slug'
How I should repair it? Thanks in advance.
In tests.py self currently refers to the class PostDetailTestCase and that class has no slug. You've almost created a post in the db that django can access.
What you need to do however is to use the following. You need to use the objects.create method in the following way.
test = Post.objects.create(
title='poost',
description="posting",
category="letstest",
slug='django'
)
If you then replace self with test things should work out.
response = self.client.get(reverse('board_detail', args=(test.slug,)))
Related
I need to apply different permission on different methods of my View class which is inherited from APIView in a DRF application. To achieve this I am using #action decorator on my methods of view.
Here is views.py code
class UserView(APIView):
#action(methods=['post'], detail=False, permission_classes=[AllowAny])
def create(self, request):
serializer = UserRegSerializer(data=request.data)
user_service = UserService()
try:
serializer.is_valid(raise_exception=True)
serialized_data = serializer.validated_data
registered_user = user_service.create_user(serialized_data)
payload = registered_user.__dict__
response = ResponseGenerator(payload, constants.SUCCESS_KEY)
except Exception as e:
response = ResponseGenerator(e)
return Response(data={"Response": response.get_custom_response()})
I am not getting that how could I access this method in my urls.py file against the pattern '/user', here is my urls.py code.
urlpatterns = [
path('user', UserView.as_view()),
]
I was using ChatGPT to answer this query of mine. It suggested some ways to use a dictionary object passed {'post':'create'} in as_view() method of View in urls.py as following.
urlpatterns = [
path('user', UserView.as_view({'post':'create'})),
]
In this it told me that key of the dictionary should be the http method used to access that method against the url pattern and value of dictionary should be the method which you want to access against the given url.
But its not working, and gives me following error when I try to start my project after writing this code in my urls.py
TypeError: APIView.as_view() takes 1 positional argument but 2 were given
I didn't find any solution to solve the problem that I am facing anywhere on Internet and in django's documentation as well.
I recommend you using Generic(Some Method)APIView.
Because it can be changed to something good for your code scalability and reliability.
Use CreateAPIView, you don't need to decorator for basic create function.
# views.py
class UserRegView(CreateAPIView):
serializer_class = UserRegSerializer
permission_classes = [AllowAny]
If you need validation, write at the validate function.
Your Response could be change sometime. Then, you should change you
# serializers.py
class UserRegSerializer(serializers.Serializer):
somefield_1 = serializers.CharField()
somefield_2 = serializers.CharField()
newfield_1 = serializers.IntegerField(read_only=True) # example
def validate(self, attrs):
a = attrs["somefield_1"]
if a != "otherthing":
raise ValidationError({"error": "Your error description some case"})
return attrs
def create(self, validated_data):
instance = UserReg.objects.create(**validated_data)
# Make Logic for instance or just validated_data or custom response whatever you want.
# If you want to custom response, could write like this simple example.
return {
"somefield_1": "test1",
"somefield_2": "test1",
"newfield_1": "test1",
}
Now, you don't need any argument in as_view().
# urls.py
urlpatterns = [
path("user_new", UserRegView.as_view()),
]
What I need
I'm developing a Pull Notification System to an existing Django Project. With there begin over 100+ views I'm looking to find a way to incorporate a argument(notification queryset) into all the views, as this is rendered to my base.html which I can do by passing it into a view's arguments dictionary.
Problem
I want to do this without editing all of the views as this would take a long time and would be required for all future views to include this variable.
What I've tried
Creating a template filter and pass in request.user as variable to return notification for that user. This works, however when the user selects a 'New' notification I want to send a signal back to the server to both redirect them to the notification link and change the status of viewed to 'True' (POST or AJAX). Which would required that specific view to know how to handle that particular request.
What I've considered
• Editing the very core 'View' in Django.
I've tried my best to explain the issue, but if further info is required feel free to ask.
Thanks!
models.py
class NotificationModel(models.Model):
NOTIFICATION_TYPES = {'Red flag':'Red flag'}
NOTIFICATION_TYPES = dict([(key, key) for key, value in NOTIFICATION_TYPES.items()]).items()
notification_type = models.CharField(max_length=50, choices=NOTIFICATION_TYPES, default='')
user = models.ForeignKey(User, on_delete=models.CASCADE)
created = models.DateTimeField(blank=True, null=True)
text = models.CharField(max_length=500, default='')
viewed = models.BooleanField(default=False)
views.py Example
class HomeView(TemplateView):
template_name = 'app/template.html'
def get(self, request, *args, **kwargs):
notifications = NotificationsModel.objects.filter(user=request.user)
args={'notifications':notifications}
return render(request, self.template_name, args)
def notification_handler(self, request)
if 'notification_select' in request.POST:
notification_id = request.POST['notification_id']
notification = NotificationModel.objects.get(id=notification_id)
notification.viewed = True
notification.save()
return redirect #some_url based on conditions
def post(self, request, *args, **kwargs):
notifications = self.notification_handler(request, *args, **kwargs)
if notifications:
return notifications
return self.get(self, request)
With there begin over 100+ views I'm looking to find a way to incorporate a argument(notification queryset) into all the views, as this is rendered to my base.html which I can do by passing it into a view's arguments dictionary.
You don't have to put it in the views (and actually, you shouldn't - views shouldn't have to deal with unrelated responsabilities) - you can just write a simple custom template tag to fetch and render whatever you need in your base template. That's the proper "django-esque" solution FWIW as it leaves your views totally decoupled from this feature.
Have you considered mixins ?
class NotificationMixin:
my_var = 'whatever'
class MyDjangoView(NotificationMixin,.....,View)
pass
Better, Using django builtins..
from django.views.generic import base
class NotificationMixin(base.ContextMixin):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['notification'] = 'whatever'
return context
and use this mixin with all your views AS THE FIRST CLASS INHERITED, See this.
For your case, Typing it instead of applying it to the base class is better, The base view class is not intended to be altered, It's meant to be extended, That's why we can solve the issue by this...
from django.generic.views import View as DjangoBaseView
from .mixins import NotificationMixin
class View(NotificationMixin, DjangoBaseView):
pass
and use any IDE to change all the imported Views to your View and not the django one.
I would like to return to a specific page after I edit a record using Django "UpdateView", however this page url needs an argument passed to it as well (see urls.py below). I am pretty sure I need to use "get_absolute_url", which works when I am just redirecting to an unfiltered page, but can't seem to get the syntax to redirect to a filtered page.
Models.py
class DefaultDMLSProcessParams(models.Model):
device = models.ForeignKey(get_user_model(),on_delete=models.CASCADE,)
customerTag = models.CharField(max_length=50,)
processNotes = models.TextField(max_length=300,blank=True,default = "")
def __str__(self):
return str(self.defaultParamDescrip)
def get_absolute_url(self):
#self.object.pk? pass this below somehow?
return reverse('Default_Listview',)
views.py
class defaultUpdateView(LoginRequiredMixin,UpdateView):
model = models.DefaultDMLSProcessParams
fields = ['processNotes','customerTag']
template_name = 'default_edit.html'
login_url = 'login'
urls.py
path('<int:device>', DefaultsListView.as_view(), name='Default_Listview'),
Specify the parameter by args argument of reverse() function
def get_absolute_url(self):
# self.object.pk? pass this below somehow?
return reverse('Default_Listview', args=[self.id, ])
You could find more example in the Official Django doc .
I have urls that take a parameter called board_slug. Before getting the template the view will replace the slug if its name is wrong and redirect it. I have already made the code for fixing the slug but do not know how insert the fixed board_slug into the new url. This code is run across multiple views so it has to work with all the following kinds urls:
url(r'^boards/(?P<board_slug>[^/]+)/$', views.BoardView.as_view(), name='board'),
url(r'^/front-thing/boards/(?P<board_slug>[^/]+)/new/$', views.BoardView.as_view(), name='new_board'),
url(r'^boards/(?P<board_slug>[^/]+)/etc...$', views.BoardView.as_view(), name='anything_with_board'),
class BoardView(View):
template_name = 'forums/board.html'
def get(self, request, board_slug):
if wrong:
url = get_django_url
url.board_slug = 'new-slug'
return redirect(url)
else:
return template
I'm running Django 1.2.1 for my personal website with a blog. It's all fine and dandy, but I've found that all the browsers I've tried (Firefox, Chromium, Opera) are caching webpages, which of course is a problem for other users viewing my blog (being that it won't load new posts up unless they empty their cache or force refresh the page). I didn't have this problem when my site ran on PHP, so how would I go about fixing this seemingly Django-related problem?
I've only been working with Django for about a week or so, so I don't really know where abouts I should be looking to fix something like this. Thanks in advance!
The way I do each page (and each blog post) is as a Page/Post object respectively so I can use the admin interface without having to write my own. Although the issue is happening for both situations, I'll just give the Post class for now:
class Post(models.Model):
author = models.ForeignKey(User, default=User.objects.get(username='nathan'))
status = models.ForeignKey(Status, default=Status.objects.get(text='Draft'))
date = models.DateTimeField(default=datetime.datetime.now())
title = models.CharField(max_length=100)
post = models.TextField()
categories = models.ManyToManyField(Category)
def __unicode__(self):
return u'%s' % self.title
def link(self):
return u'/blog/post/%s' % self.title
class Meta:
ordering = ['-date']
And here's my urls.py:
from django.conf.urls.defaults import *
from django.views.generic import list_detail
from feeds import PostFeed
from models import Post
blog_posts = {
'queryset': Post.objects.filter(status__text__exact='Published'),
}
urlpatterns = patterns('getoffmalawn.blog.views',
(r'^$', list_detail.object_list, blog_posts),
(r'^archive/(\d{4})$', 'archive'),
(r'^rss/$', PostFeed()),
(r'^search/$', 'search'),
(r'^tag/(.+)/$', 'tag'),
(r'^post/(.+)/$', 'post'),
)
If you guys would like to see the code from views.py, just ask and I'll throw that up too.
Edit:
Here's the views.
view.py for the blog App:
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response, redirect
from django.core.context_processors import csrf
from django.db.models import Q
from models import Post, Category
def post(request, title):
post = Post.objects.get(title=title)
c = locals()
c.update(csrf(request))
return render_to_response('blog/post_detail.html', c)
def blog_detail(request, blog_id):
post = get_object_or_404(Post, pk=blog_id)
return list_detail.object_detail(request, queryset=Post.objects.all(), object_id=blog_id)
def archive(request, month, year):
pass
def search(request):
if request.method == 'GET':
query = request.GET['q']
object_list = Post.objects.filter(Q(post__icontains=query) | Q(title__icontains=query), status__text__exact='Published')
return render_to_response('blog/post_list_sparse.html', locals())
def tag(request, tag):
object_list = Post.objects.filter(categories__text__exact=tag, status__text__exact='Published')
return render_to_response('blog/post_list.html', locals())
The problem was that it really was browser-based caching, as I was told by a member on the Django-users mailing list. The reason I didn't see this problem in PHP is that it was sending cache suppression headers.
The solution was to add the #never_cache decorator to the relevant views.
Here is the documentation for caching in django.
https://docs.djangoproject.com/en/1.2/topics/cache/
Not ideal, but you can make all of the pages tell the browsers not to cache anything, to see if that helps.
https://docs.djangoproject.com/en/1.2/topics/cache/#controlling-cache-using-other-headers