i'm trying to build a mini reply system, based on the user's posts on a mini blog.
Every post has a link named reply. if one presses reply, the reply form appears, and one edits the reply, and submits the form.The problem is that i don't know how to take the id of the post i want to reply to. In the view, if i use as a parameter one number (as an id of the blog post),it inserts the reply to the database.
But how can i do it by not hardcoding?
The view is:
def save_reply(request):
if request.method == 'POST':
form = ReplyForm(request.POST)
if form.is_valid():
new_obj = form.save(commit=False)
new_obj.creator = request.user
new_post = New(1) #it works only hardcoded
new_obj.reply_to = new_post
new_obj.save()
return HttpResponseRedirect('.')
else:
form = ReplyForm()
return render_to_response('replies/replies.html', {
'form': form,
},
context_instance=RequestContext(request))
i have in forms.py:
class ReplyForm(ModelForm):
class Meta:
model = Reply
fields = ['reply']
and in models:
class Reply(models.Model):
reply_to = models.ForeignKey(New)
creator = models.ForeignKey(User)
reply = models.CharField(max_length=140,blank=False)
objects = NewManager()
mentioning that New is the micro blog class
thanks
heyy there. i solved the problem,using your advices, but I've created another.
I was thinking that as the reply form is in another page, simply clicking on that reply link ain't gonna help me retain the post id anyhow, because the blog page is gone, after i push thet reply button. So, in my view, i 've created a function that holds the id of the blog post as a parameter. It saves just as it should, no problem, but now my problem is: HOW CAN I PASS A LINK LIKE
url(r'^save_reply/(?P<id>\d+)/$',
save_reply,
name='save_reply'),
(this is what i hold in my urls.py)
to the reply under each post? I mean, until now, my reply link was simply calling the function replies/save_reply(i had Reply) but now, when i have the id as a parameter, how can i put it in my a href = 'what here'?
here is my views.py that works right:
def save_reply(request, id):
if request.method == 'POST':
form = ReplyForm(request.POST)
if form.is_valid():
new_obj = form.save(commit=False)
new_obj.creator = request.user
u = New.objects.get(pk=id)
new_obj.reply_to = u
new_obj.save()
return HttpResponseRedirect('.')
else:
form = ReplyForm()
return render_to_response('replies/replies.html', {
'form': form,
},
context_instance=RequestContext(request))
and i'm callin it by typing in my browser:
http://127.0.0.1:8000/replies/save_reply/1/ (for instance)
of course, i've removed my foreign key field, as now it is unnecessarry
Thank you!
You need to have a hidden field in your form to capture the PK of whichever instance of New the comment is related to.
Since you're using a ModelForm, your Reply model already has the ForiegnKey relationship established. You can set the widget type to be hidden, so your users don't see it..
# forms.py
class ReplyForm(ModelForm):
class Meta:
model = Reply
fields = ['reply', 'reply_to']
widgets = {
'reply_to': forms.HiddenInput),
}
When you initialize the ReplyForm, you can populate the reply_to field like form = ReplyForm({'reply_to': new.pk}) - where new is an instance of New
BTW you might consider changing the name of your New model to something like Post. 'New' is a bit hard to talk about, and a little confusing since 'new' usually means something completely different in a programming context.
if one presses reply, the reply form appears,
I think this is the part you need to work on. When the reply form is rendered it needs to have the id of the post being replied to with it (the instance of New). This presumably has to come via the request unless you have some other way of keeping track of it?
Something along the lines of:
def save_reply(request):
...
else:
form = ReplyForm()
form.reply_to = New.objects.get(id=request.REQUEST["post_id"])
Thus you'll need to ensure that the link which causes the form to be rendered includes a 'post_id' param (or similar - presumably you already have an equivalent, used for displaying the post in question?).
Alongside the
widgets = {
'reply_to': forms.HiddenInput),
}
code this should render the form as you need it.
The post id has to be passed all the way along the chain
--post_id-> Render Post --post_id-> Render Reply Form --post_id-> Store Reply
Related
I making a feedback form on website. I made model called 'globalapp' with all settings for future admin, it have email,address and phone fields without permissions for add or delete this objects.
In my views i have a simple code:
def index(request):
seos = SEO.objects.get(id__exact=1)
socs = Social_networks.objects.get(id__exact=1)
globs = globalapp.objects.get(id__exact=1)
index = Index.objects.get(id__exact=1)
form = ContactForm(request.POST)
if form.is_valid():
subject = form.cleaned_data['subject']
sender = form.cleaned_data['sender']
message = form.cleaned_data['message']
fille = form.cleaned_data['fille']
recepients = ['test#test.ru']
from_email, to = sender, recepients
html_content = loader.render_to_string('globalapp/chunks/email_tpl.html',
{'subject': subject, 'sender':sender, 'message':message, 'fille':fille})
msg = EmailMultiAlternatives(subject, html_content, from_email, to)
msg.send()
return render(request, 'globalapp/index.html', {'seos': seos,
'socs': socs,
'globs': globs,
'index': index,
'form': form })
Right now mail sending on test#test.ru. I want to take email field from globalapp object, and put it in 'recepients', to give admin ability to change email address when he needs it.
The best thing that i get yet, i get email value by queryset with:
email = globalapp.objects.filter(id=1).values('email')
by in mail ive got only To: {'email': 'test#gmail.com'}
So question is how to get string from queryset object for dynamic email recepients changing? Or maybe i have option how to do it other way?
Also i have another little problem, that i cant deal with yet: after i push submit button, my page reloading, and i dont need it, can i disable it somehow?
Well there are two problems here:
you use .filter(..), and a filter means you do not get a single dictionary, but a QuerySet of dictionaries. This can be empty, contain one, or multiple elements. Since you filter on id=..., it will contan at most one element, but still it will require some extra logic to unwrap it out of the QuerySet, so we better use .get(..) here; and
we obtain a dictionary, we can retrieve the element associated with the key, by performing an element lookup, so the_dict['email'].
We can tus obtain the email address with:
email = globalapp.objects.values('email').get(id=1)['email']
Or perhaps more elegant:
email = globalapp.objects.values_list('email', flat=True).get(id=1)
Also i have another little problem, that i cant deal with yet: after i push submit button, my page reloading, and i dont need it, can i disable it somehow?
Not with a form, since that is exactly the task the browser is supposed to carry out: send a HTTP request, and load the response. But you can use an AJAX call to perform a HTTP request while the webpage still remains the same.
I have a model named Book that I send to an html to display data from like this:
books = Book.objects.all()
return render(request, 'index.html', {'books':books})
I then show all the information I want of the book in the front-end (which doesn't need to be shown here).
Other than showing the information of the book in the front-end I also want to introduce a small form that will have two buttons let's say "Submit" and "Decline" that will update an attribute of the Book object depending on the button clicked.
I am trying to find a good way to achieve this. My thought is to POST the entire object to a view to process later but I am not sure if is a good practice to submit an entire object from client to server as this may be affected in some way.
This may help you :
If you want to update database with other values related with Book's object then you can achieve it by doing the following:
if request.POST:
book_form = BookForm(request.POST)
if book_form.is_valid():
book = Book.objects.get(pk=book_id)
book_form = BookForm(request.POST, instance = book)
book_form.save()
It will update the existing bookObject in Database by filtering on the basis of book_id.
You don't need to send any form data if it's just an attribute you'll update. You can do something like this (I'm using uuid just as an example you can use id or whatever unique field you want):
# url for your update view. For example: decline
url(r'^decline/book/(?P<book_uuid>[\w\-]+)$',
YourView.as_view(),
name="book-decline"),
# views.py
class YourView(View):
def get(self, request, *args, **kwargs):
book_uuid = kwargs.get('book_uuid', None)
book = get_object_or_404(Book, uuid= book_uuid)
# UPDATE YOUR BOOK HERE
# in your templates for each book's decline button link
<a href={% "book-decline" book.uuid %} ....>
Tiny Instance provided a generic solution. If you want a more specific solution for the case of updating an object of a model by getting a form filled from the user, then Django has something inbuilt which does this for you. FormView is what you are looking for.
See the official documentation here -> https://docs.djangoproject.com/en/1.9/ref/class-based-views/generic-editing/#formview
I would like to display an alert box after a form has been submitted.
The box would be hidden when a user first visits the page and will display "new category created" or "category already exists" upon submission.
I think I know would I can do this in the template but I'm not sure how to pass the variable into the template on the redirect.
Below is the view. Any thoughts how I can accomplish this?
I appreciate the feedback.
#login_required
#locationed
def manage_cat_subcat(request, location):
form = AddCategory()
if request.method == 'POST':
form = AddCategory(request.POST)
if form.is_valid():
submitted_cat_name = form.cleaned_data['category_name']
_, was_created = Category.objects.get_or_create(name=submitted_cat_name)
return HttpResponseRedirect(reverse('manage_cat_subcat', args=(location.slug,)))
return render(request, 'inventory/manage_cat_subcat.html', {'location': location, 'form': form})
You don't have to use any hidden data, just use this:
https://docs.djangoproject.com/en/dev/ref/contrib/messages/#using-messages-in-views-and-templates
It looks like you're talking about rendering a dialog based upon a user submitting certain information. If so, I strongly recommend using JQuery to pull the value of the category field once the field loses focus, then pass that category information right away via an AJAX call to a dedicated method in your views file. Depending on the response, you'll show the appropriate dialog. So it would be something like this in your views.py:
#render_json
def ajax_category_check(request){
if request.method == 'POST' and 'category_name' in request.POST:
#insert your code that checks new or existing categories
#if the category exists...
return {'exists': True}
return {'exists': False}
}
One advantage of AJAX is that it makes the user experience a lot smoother by removing the burden of having them deal with form submission/browser page refreshing.
On the other hand, if you're talking about simply showing an alert dialog before the form is even submitted, intercept the form submission and show the dialog using JQuery:
$('form').click(function(event){
$('#dialog').show();
/* after a delay or after dialog confirmation, etc... */
$('form').submit();
});
I've posted about this problem before, but I still haven't found a solution so I'm hoping I'll have better luck this time.
I have a form that takes inputted data by the user. In another page, I am creating the identical form that the user has populated (pre-filled with that information) for editing purposes. Users will come to this page to EDIT the information they have already put in. My problem is that it isn't overwriting the instance.
def edit(request):
a = request.session.get('a', None)
if a is None:
raise Http404('a was not found')
if request.method == 'POST':
form = Name_Form(request.POST, instance=a)
if form.is_valid():
j = form.save( commit=False )
j.save()
else:
form = Name_Form( instance = a )
For this form, I'm using "unique_together" for some of the values. I'm also calling on `{{ form.non_field_errors }} in the template.
What is happening is when I make changes in the editing view, if the fields changes involves those defined in "unique_together" then an error is returned telling me that the instance already exists. Otherwise it saves a new instance. It isn't OVERWRITING.
Note that the reason i am using unique_together is that I want to prevent users from initially inputting the same form twice (before the editing stage, in the initial inputting view).
Any ideas?
EDIT: note that "a" refers to a session that includes a drop down box of all the available instances. This carried forward will indicate which instance the user wants to edit.
`
Why not do a database lookup of the model your trying to save and pull the fields from the form to the model then save the model?
Instead to store model a in session you should store it on database. Then edit it:
def edit(request, pk):
a = A.objects.get( pk = pk)
...
pk it the a identifier, you can send it to view via urls.py. I encourage to you to use POST/Redirect/GET pattern.
You can add a 'state' field on your model to control workflow (draft, valid)
You should not save objects in the session. If you really need to use a session - save a PK there and retrieve object right before giving it to Form. But the better solution is to send it in GET or POST parameters or included in url. Sessions are unreliable, data inside it can be destroyed between user's requests.
And you can retrieve value from a session in a more pythonic way:
try:
a = request.session['a']
except KeyError:
raise Http404('a was not found')
I have a simple form, that when submitted redirects to a success page.
I want to be able to use the data that was submitted in the previous step, in my success page.
As far as I know, you can't pass POST data when redirecting, so how do you achieve this?
At the moment I'm having to just directly return the success page from the same URL, but this causes the dreaded resubmission of data when refreshed.
Is using request.session the only way to go?
I do this all the time, no need for a session object. It is a very common pattern POST-redirect-GET. Typically what I do is:
Have a view with object list and a form to post data
Posting successfully to that form saves the data and generates a redirect to the object detail view
This way you save upon POST and redirect after saving.
An example view, assuming a model of thingies:
def all_thingies(request, **kwargs):
if request.POST:
form = ThingieForm(request.POST)
if form.is_valid():
thingie = form.save()
return HttpResponseRedirect(thingie.get_absolute_url())
else:
form = ThingieForm()
return object_list(request,
queryset = Thingie.objects.all().order_by('-id'),
template_name = 'app/thingie-list.html',
extra_context = { 'form': form },
paginate_by = 10)
You can:
Pass the data (either full data or just id to object) in request.session
Redirect with something like ?id=[id] in URL - where [id] points to your object.
Update:
Regarding pt. 1 above, I meant that you could do (in POST handler):
my_object = MyModel.objects.create(...)
request.session['my_object_id'] = my_object.id
Or you could try passing the whole object (it should work but I'm not 100% certain):
my_object = MyModel.objects.create(...)
request.session['my_object'] = my_object