Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Class-based views #22

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open

Class-based views #22

wants to merge 4 commits into from

Conversation

Miseracle
Copy link
Contributor

According to #20 , changed functional-based views to cb approach.

@Miseracle Miseracle self-assigned this Jan 28, 2018
blog/views.py Outdated
@@ -3,115 +3,136 @@
- post_list - returns post list;
"""

from django.shortcuts import render, get_object_or_404, redirect
from django.shortcuts import get_object_or_404, redirect
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You shouldn't need these shortcuts as well.

blog/views.py Outdated
template_name = 'blog/post_edit.html'

def post(self, request, *args, **kwargs):
"""Get author-field from request and save post to DB."""
form = PostForm(request.POST)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe, this check is already encapsulated into CreateView.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need this

blog/views.py Outdated
template_name = 'blog/post_edit.html'

def post(self, request, *args, **kwargs):
"""Get author-field from request and save post to DB."""
form = PostForm(request.POST)
if form.is_valid():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe, this check is already encapsulated into CreateView.

blog/views.py Outdated
template_name = 'blog/post_edit.html'

def post(self, request, *args, **kwargs):
"""Get author-field from request and save post to DB."""
form = PostForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can inner this via form_valid method or so

blog/views.py Outdated
template_name = 'blog/post_edit.html'

def post(self, request, *args, **kwargs):
"""Get author-field from request and save post to DB."""
form = PostForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.save()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's done automatically, you don't have to implement post method at all

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I quess, I have to use construction on 55-57 anyway - not in post, but in form_valid then.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, there should probably be a way to even encapsulate that into save method of form

blog/views.py Outdated
fields = ['title', 'text']
template_name = 'blog/post_edit.html'

def get_success_url(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better move this to model

blog/views.py Outdated
class PublishPost(TemplateView, Protected):
"""View for publishing post."""

def get(self, request, *args, **kwargs):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be post

blog/views.py Outdated
queryset = Post.objects.filter(published_date__isnull=True).order_by('created_date')


class PublishPost(TemplateView, Protected):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use updateview

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or so

blog/views.py Outdated
fields = ['author', 'text']
template_name = 'blog/add_comment.html'

def post(self, request, *args, **kwargs):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above: read the docs of what each of base classes implement/encapsulate

blog/views.py Outdated
comment = get_object_or_404(Comment, pk=kwargs['pk'])
post_pk = comment.post.pk
comment.delete()
return redirect('post_detail', pk=post_pk)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about get_success_url?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried, but didn't figure out, how to get post.pk.
get_success_url evaluates after the action is done, so I can't get it from self.object.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd save it in form_valid and then reused that to create success url

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I was wrong - we can get self.object.
https://code.djangoproject.com/ticket/19044

But right now it fails on template rendering (cuz post object is missing). I can write separate template for deleting or redefine get method (weird solution, I guess)...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright. Let's leave it as it. It would be cleaner in case of doing normal CRUD for some JS client.

blog/models.py Outdated

def get_absolute_url(self):
"""Redirect to view with detail info about parent post."""
return reverse('post_detail', args=[str(self.post.pk)])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think, pk=self.post.pk should work just fine

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't, reverse() accepts only args / kwargs for additional parameters.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh then you should pass kwargs, singe you use named group pk in that regexp

blog/models.py Outdated
@@ -59,3 +59,7 @@ def approve(self):
def __str__(self):
"""Represent a comment as a string by its text."""
return self.text

def get_absolute_url(self):
"""Redirect to view with detail info about parent post."""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a like. No redirect here at all.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's rendering/returning url, nothing more

blog/views.py Outdated
def form_valid(self, form):
"""Pass parent post pk to model."""
post = self.get_object(Post.objects.filter(pk=self.kwargs['pk']))
form.save(post)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is pointless: you get object from the db and save it back? That's weird

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get Post object and save it as a field of Comment.
Though, working with keys instead of objects should be simplier.

blog/views.py Outdated
"""Pass parent post pk to model."""
post = self.get_object(Post.objects.filter(pk=self.kwargs['pk']))
form.save(post)
return super(AddComment, self).form_valid(form)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Python 3, super is simpler

@@ -1,8 +1,10 @@
*.pyc
__pycache__
tvenv
djenv
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not just use pyenv's virtualenv plugin and forget about in-project env dir?

blog/forms.py Outdated
@@ -13,6 +13,14 @@ class Meta:
model = Post
fields = ('title', 'text',)

def save(self, user=None):
"""Save post to DB, assigning author field."""
post = super(PostForm, self).save(commit=False)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not py2

blog/urls.py Outdated
url(r'^post/(?P<pk>\d+)/comment/$', views.AddComment.as_view(), name='add_comment'),
url(r'^comment/(?P<pk>\d+)/approve/$', views.ApproveComment.as_view(), name='comment_approve'),
url(r'^comment/(?P<pk>\d+)/remove/$', views.RemoveComment.as_view(), name='comment_remove'),
url(r'^admin/', admin.site.urls),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't it already added in mysite?

blog/views.py Outdated
"""Publish post."""
post = self.get_object(Post.objects.filter(pk=kwargs['pk']))
post.publish()
return HttpResponseRedirect(reverse('post_detail', kwargs={'pk': post.pk}))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you use UpdateView, there's a plenty of logic encapsulated there. You should just inject a small change into some of already existing methods. It will get redirected automatically. BTW, there should be self.object available, which is handled so you don't have to do manual db lookup.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self.object assigns in BaseUpdateView.get(), so I should write smthg like:

super.get(...)
DoSmthg (self.object.publish etc.)
return HttpResponseRedirect(...)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you're missing the idea of pre-existing base classes. post/get/put etc. methods are low-level here. But those classes like UpdateView and similar encapsulate lots of logic and provide you with custom hook methods, which you should modify to inject some changes into existing flow.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think, I miss the idea, where should I implement logic in general - or just couldn't find an appropriate method to make an injection.

def save(self, user=None):
"""Save post to DB, assigning author field."""
post = super().save(commit=False)
if user:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why exactly do you forbid setting NULL for the author?

@@ -27,6 +28,10 @@ def publish(self):
self.published_date = timezone.now()
self.save()

def get_absolute_url(self):
"""Return url for view with detail info about post."""
return reverse('post_detail', args=[self.pk])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd do kwargs instead

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK


def form_valid(self, form):
"""Pass request.user to model."""
form.save(self.request.user)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, form.save() is already being called after form_valid() by the base view's logic. I think, you probably should only modify the instance like form.instance.author = self.request.user and that's it:
https://docs.djangoproject.com/en/2.0/topics/class-based-views/generic-editing/#models-and-request-user

fields = ['title', 'text']
template_name = 'blog/post_detail.html'

def get(self, request, *args, **kwargs):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's weird: why not just POST the change and let update view to handle all internal logic?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I remove publish() method from model then? And just pass published_date change?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, that method is handy


def form_valid(self, form):
"""Pass parent post pk to model."""
post = self.get_object(Post.objects.filter(pk=self.kwargs['pk']))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(same as above)

model = Comment
fields = ['author', 'text']

def get(self, request, *args, **kwargs):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

decide whether you use UpdateView or go for smth simpler.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants