A create view in another view django - django

I am new to django. I've created a basic posts app where users post messages. The project has posts app for posting messages. The app has two models- Post and Comment where one post can have many comments. My posts are shown in list view with comments for a particular post.
Now, i want to have an 'add comment' button for each post so i can directly add comment (stack exchange design!) . This can otherwise be implemented by a seperate createview for comments model. I want an textarea on listview itself to input comments for a post.
How can i do this?

In the most basic form, you can define different routes for your desired views (CreateComment, PostDetails) and send a POST request to the CreateComment view from the PostDetails route.
urls.py
urlpatterns = [
path('post/<pk>/', post_details, name='post-details'),
path('comment/new/', add_comment, name='create-comment'),
]
and in your post/<pk>/ route, set up a form like below:
<form method="POST" action="/comment/new/">
<input value="" name="description" type="text" />
<input value="/current/path/" name="redirect" type="hidden" />
{% csrf_token %}
</form>
You can then redirect the user to the page he was making the request from in the first place, using the redirect value which is passed by the form from the origin route.

Related

How can i add a "like" button in a Django class ListView

I am pulling my hair out trying to add a "like" button in my siteĀ“s post app, but as i want to add it in a ListView that contains the rest of the posts entries and everyone has the option to be commented I have added a Formixin to do so, so, now i cannot add another form for the like button as it would mean two posts requests....so I am not finding a clear solution... I have read here and there about using AJAX or Json techs but as im new programing im kind of stuck in it... has anyone any tip to offer?
While using AJAX (javascript XHR requests) would be the proper way so the page doesn't need to be refreshed when just clicking a like button, you can do it without AJAX.
HTML
On the HTML side of things, you can have multiple forms (<form>), one for each post, which have a hidden input field that's the post's id. You have set that explicitly in the HTML template, e.g.
{% for post in post_list %}
<h3>{{ post.title }}</h3>
<p>{{ post.summary }}</p>
<form method="post">
{% csrf_token %}
<input type="hidden" value="{{ post.id }}" name="{{ form.id.html_name }}">
<input type="submit">Like</input>
</form>
{% endfor %}
So basically you're reusing the form multiple times, changing the "value" attribute to match the post.
Django Form
Adding the FormMixin to your view is the right step, just use the form_class to a custom LikeForm with just one field that's an IntegerField called id.
View
By adding the FormMixin you get the form_valid() method, which you'll want to override to save the like:
def form_valid(self, form):
id = form.cleaned_data['id']
try:
post = Post.objects.get(id=id)
except Post.DoesNotExist:
raise Http404
post.likes.add(self.request.user) # assuming likes is a m2m relation to user
return redirect('post_list') # this list view
Hopefully I am not so late, I had similar challenges trying to implement the same functionalities on my website.
I came to realize that each button id should be unique (Preferably the post id if blog), but the classes can be the same.
I was able to solve it. Here is an article I wrote on medium recently on the steps I followed to so get this working you can check it out here

html - redirect to new url after form submission (django site)

I am trying to make a button redirect the user to a new url after they submit a form. This is how it is right now, and it works properly and all the data gets sent to the django database.
<form method='POST' action='' class="col-md-6 col-md-offset-7" style="background-color: lightgreen; border-radius: 10px">
However, when I change the action to
action="{% url 'ridesharing:request-success' %}",
the redirect works, but the data does not go to my django database.
What is going on here?
You seem to have some confusion here. The action of the form is where the browser will send the data. Obviously, if you don't point that at the view which actually processes the data, then it won't be saved.
To redirect after a post, your view should return a redirect.
When you declare a form with an empty action attribute:
<form method='POST' action=''>
the POST data will be sent to the same URL. This is useful because if there is some error in the form, it's easy to re-display it with all fields filled with values entered by the user. Then, when the form becomes valid, a redirect is done to the confirmation page.
When you declare your form that way:
<form method='POST' action='{% url 'ridesharing:request-success' %}'>
The data entered by the user in the form will be sent to the view request-success. But this view probably only render the template of the confirmation page. If you want to correctly handle data from the form, you have to set action attribute of your <form> to the same view, or easier, keep it empty.
I do not understand why Daniel Roseman's post isnt accepted as the answer. It helped me when I wanted to redirect a create form to its update form.
Basically in the view of the app I defined the get_success_url to reverse_lazy to the data-update.
def get_success_url(self):
return reverse_lazy('app_name:data-update')
Just replace the 'app_name:data-update' with the appropriate url.

Dynamic redirect url after login [duplicate]

I'm trying to build a simple website with login functionality very similar to the one here on SO.
The user should be able to browse the site as an anonymous user and there will be a login link on every page. When clicking on the login link the user will be taken to the login form. After a successful login the user should be taken back to the page from where he clicked the login link in the first place.
I'm guessing that I have to somehow pass the url of the current page to the view that handles the login form but I can't really get it to work.
EDIT:
I figured it out. I linked to the login form by passing the current page as a GET parameter and then used 'next' to redirect to that page. Thanks!
EDIT 2:
My explanation did not seem to be clear so as requested here is my code:
Lets say we are on a page foo.html and we are not logged in. Now we would like to have a link on foo.html that links to login.html. There we can login and are then redirected back to foo.html.
The link on foo.html looks like this:
<a href='/login/?next={{ request.path }}'>Login</a>
Now I wrote a custom login view that looks somewhat like this:
def login_view(request):
redirect_to = request.REQUEST.get('next', '')
if request.method=='POST':
#create login form...
if valid login credentials have been entered:
return HttpResponseRedirect(redirect_to)
#...
return render_to_response('login.html', locals())
And the important line in login.html:
<form method="post" action="./?next={{ redirect_to }}">
So yeah thats pretty much it, hope that makes it clear.
You do not need to make an extra view for this, the functionality is already built in.
First each page with a login link needs to know the current path, and the easiest way is to add the request context preprosessor to settings.py (the 4 first are default), then the request object will be available in each request:
settings.py:
TEMPLATE_CONTEXT_PROCESSORS = (
"django.core.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
"django.core.context_processors.request",
)
Then add in the template you want the Login link:
base.html:
Login
This will add a GET argument to the login page that points back to the current page.
The login template can then be as simple as this:
registration/login.html:
{% block content %}
<form method="post" action="">
{{form.as_p}}
<input type="submit" value="Login">
</form>
{% endblock %}
To support full urls with param/values you'd need:
?next={{ request.get_full_path|urlencode }}
instead of just:
?next={{ request.path }}
This may not be a "best practice", but I've successfully used this before:
return HttpResponseRedirect(request.META.get('HTTP_REFERER','/'))
Django's built-in authentication works the way you want.
Their login pages include a next query string which is the page to return to after login.
Look at http://docs.djangoproject.com/en/dev/topics/auth/#django.contrib.auth.decorators.login_required
I linked to the login form by passing the current page as a GET parameter and then used 'next' to redirect to that page. Thanks!
I encountered the same problem. This solution allows me to keep using the generic login view:
urlpatterns += patterns('django.views.generic.simple',
(r'^accounts/profile/$', 'redirect_to', {'url': 'generic_account_url'}),
)
In registration/login.html (nested within templates folder) if you insert the following line, the page will render like Django's original admin login page:
{% include "admin/login.html" %}
Note: The file should contain above lines only.
See django docs for views.login(), you supply a 'next' value (as a hidden field) on the input form to redirect to after a successful login.
You can also do this
<input type="hidden" name="text" value="{% url 'dashboard' %}" />

Django how redirect to other site by post query string

How can I redirect from first site to second site.
Second site have form:
<form action="http://example.com/authAs" method="POST">
<input id="login" type="text" name="login"></td>
<input id="password" type="password" name="password"></td>
<button type="submit">login</button>
</form>
I want to authenticate the user at the first site and redirect it to a second site already authorized by POST request
How can I do it?
I have tried do it:
import urllib2,urllib
post_data = [('login', login), ('password', password)]
result = urllib2.urlopen('http://example.com/authAs', urllib.urlencode(post_data))
content = result.read()
But how redirect user to authorized page on second site?
It is not possible to redirect through POST, if you want the client to post to another site the only option is to use javascript to make a browser based redirection.
Instead of redirecting to example site, you can redirect to a local page with the form html and add this JS:
document.forms['form_id'].submit();
Note that the client will see the page for a few seconds before redirection and it won't work if JS is not enabled.

How do I get variables not submitted by the user back from a template

I'm new to django and for practice I'm trying to program my own version of the all familiar 'todo list' app.
I have some page that displays all todo list items the user has entered, along with a button to edit each one. The edit button sends the user to another page with a form to enter in the changes to the item.
It's possible for the user to change everything about the item. Obviously request.POST gives me all the information the user just put into the form, but I want this information to rewrite the info of the item they originally clicked on. So how do I write the view code to find out what that original item was?
I guess I could format my form submit button to:
<button type="submit" name="save" value={{ item.pk }}>Save</button>
and get the primary key that way
but lets say I had passed two items to the edit page and I wanted to give the user the ability to combined them. Again, I could figure out what those items were by doing:
<button type="submit" name="save" value='{{ item1.pk }} {{ item2.pk }}'>Save</button>
then
request['save'].split(' ')
this seems kinda stupid though. Is there some other, less brute force, way?
like a:
request.tell_me_all_items_passed_to_the_template
kind of thing?
In case someone else has the same question
So instead of doing this:
template
<form method="post" action="/list/saving/">
<!--- form fields --->
<button type="submit" name="save" value='{{ item.pk }}'>Save</button>
</form>
url.py
(r'^list/saving/$', save)
views.py
def save(request):
....
item = Item.objects.get(pk=request.POST['save'])
....
do this:
template
<form method="post" action="{% url todolist.views.save item.pk %}">
<!--- form fields --->
<button type="submit" name="save">Save</button>
</form>
url.py
(r'^list/saving/(\d+)/$', save)
views.py
def save(request, pk):
....
item = Item.objects.get(pk=pk)
....
More info on url reversing
If you really need to, just use hidden inputs. But, this is unnecessary anyways. The user may be able to change "everything" about the item, but they can't change the pk (or at least they shouldn't be able to... don't give them the option to). The pk is what Django uses to identify an object, so this is already handled for you. Not sure what the issue here is.