RequestContext on django redirect() - django

I'm wondering if there is any way to include the RequestContext in the django redirect function or any other context.
The thing is that I need to add a message after an object is created, but the messages framewotk requires a RequestContext to work or another context that returns the messages. How can I do to return a context?
My view:
#permission_required('spaces.add_space')
def create_space(request):
"""
Returns a SpaceForm form to fill with data to create a new space. There
is an attached EntityFormset to save the entities related to the space. Only
site administrators are allowed to create spaces.
:attributes: - space_form: empty SpaceForm instance
- entity_forms: empty EntityFormSet
:rtype: Space object, multiple entity objects.
:context: form, entityformset
"""
space_form = SpaceForm(request.POST or None, request.FILES or None)
entity_forms = EntityFormSet(request.POST or None, request.FILES or None,
queryset=Entity.objects.none())
if request.user.is_staff:
if request.method == 'POST':
space_form_uncommited = space_form.save(commit=False)
space_form_uncommited.author = request.user
if space_form.is_valid() and entity_forms.is_valid():
new_space = space_form_uncommited.save()
space = get_object_or_404(Space, name=space_form_uncommited.name)
ef_uncommited = entity_forms.save(commit=False)
for ef in ef_uncommited:
ef.space = space
ef.save()
# We add the created spaces to the user allowed spaces
request.user.profile.spaces.add(space)
# This message does not work since there's no context.
messages.info(request, 'Space %s created successfully.' % space.name)
return redirect('/spaces/' + space.url)
return render_to_response('spaces/space_add.html',
{'form': space_form,
'entityformset': entity_forms},
context_instance=RequestContext(request))
else:
return render_to_response('not_allowed.html',
context_instance=RequestContext(request))

Storing a message doesn't require a RequestContext, it's only displaying it that does. In what way doesn't your code work? Your message should be added to the database and available to be displayed after the redirect.

I had the same question and just want to clarify that it 'just works'
def first_view(request)
...
messages.info(request, "Some info message")
...
return redirect('second_view')
def second_view(request)
...
return render_to_response('template.html',{},context_instance=RequestContext(request))
-> will correctly display the message

Related

Create Form and update using same view in django

I am trying to use same view for creating form and updating any object.
My code is as below, I tried in many ways nothing is working, since I am excluding the shof from form and adding it after form.is_valid() it makes lot of confusion. If I update it creates new object. I have two urls one without ql (create new) and one with ql (update existing), I have a class vdview which provides v.shof which needs to applied in the f.shop in form. please help fix this,
#csrf_protect
#login_required
def addmenu(request, qs, ql=None):
v = vdview(request, qs)
ctgobj = get_object_or_404(v.shopcategs, pk=ql) if ql else None # ctgobj = ShopCtg(shop=v.shof)
if ql:
form = ShopCtgForm(instance=ctgobj) # Tried ShopCtgForm(instance=ctgobj, data=request.POST)
else:
form = ShopCtgForm(data= request.POST)
if request.method == 'POST':
if form.is_valid():
f=form.save(commit=False)
f.shop = v.shof
f.save()
#form.save_m2m()
return redirect('vendor-shop', qs) #thing='%s added' %f.name)
else:
pass
#else:
# form = ShopCtgForm()
return render(request,'vendorshop.html', {'shop':v.shof, 'shopcategs':v.shopcategs, 'form': form,
'heading':'Create New Category', 'createcateg': 'createcateg', 'pkaddmenupk':'y' } )
Use try blocks to handle both scenarios. The simplified example below will look for a given model instance pk and if it doesn't find it, will assume you want to create it. try will prevent django from throwing an error if the model instance doesn't exist. Rather, it will just return the empty model form.
It does this first to render the correct form in the template (the first try block) then again in the second try block after request.method == 'POST': to submit new data or update existing data.
Views.py
from .models import Books
from .forms import BookForm
def create_and_update_book_view(request, pk):
books = Books.objects.get(id=pk)
try: # get pre-populated form with model instance data (for update)
form = BookForm(instance=books.id)
except: # If it doesn't exist, show an empty form (for create)
form = BookForm(request.POST or None)
if request.method == 'POST':
try: # Do the same as above
form = BookForm(instance=books.id)
except: # Same as above
form = BookForm(request.POST or None)
if form.is_valid():
form.save()
return render(request, "create_and_update_book_page.html", {'form':form})

Django CustomTags Using Session

I'm trying to use Django to output an HTML page based on whether the session is set or not.
when I submit my Django Form (via my view) I set the session like this:
def index(request):
users = Users.objects.all()
totalUsers = len(users)
form = CreateUserForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
form = CreateUserForm()
context = {
"form": form,
'users': users,
"totalUsers": totalUsers,
}
request.session.set_expiry(300)
request.session['loggedIn'] = True
return render(request, 'SmartCity/index.html', context)
I know this is successful because I can see the value set in the DB.
In my CustomTags.py file, I want to more or less check the session variable "loggedIn" is set, and if it is, return one thing, otherwise, return something else. This is how I thought to achieve it, but it's not working:
from Django import template
register = template.Library()
#register.inclusion_tag('SmartCity/index.html', takes_context=True)
def hello_world(context):
request = context['request']
loggedInStatus = request.session.get('logged_in', 'False')
if loggedInStatus == True:
return "Hello world"
The error I receive is:
https://preview.ibb.co/dqAe8k/2017_09_19_18_06_57.png
I could totally be on the wrong track... I would appreciate any advice you might be able to give a Django beginner :)

Can't figure out why form.has_changed() is always true?

I'm trying to learn Django and have come up with a situation I can't figure out. I have the following code:
def contact_add(request):
if request.method == 'POST':
form = ContactManageForm(request.POST)
if form.is_valid():
if form.has_changed(): # <-- ALWAYS RETURNS TRUE!
form.clean()
...
elif 'id' in request.GET: # Request to show an existing contact
new_contact_dynamic = contacts.models.PersonDynamic.objects.get(person_static = request.GET['id'],
current_record_fg = True)
form = ContactManageForm(new_contact_dynamic.__dict__, initial=new_contact_dynamic.__dict__)
else: # This must be to add a new contact
form = ContactAddForm()
return render(request, 'contact_manage.html', {'form': form})
So, if I'm sent an ID number, I read a record and display it on the screen. My template gives the user a 'submit changes' button. My problem, as noted above, is that Django always shows that the form has changed, even if the user hasn't changed any data on the screen (i.e. he just hit the submit changes button without changing anything).
So, am I doing something obviously wrong in my code that's creating this situation? Am I misinterpreting how the form.has_changed() method works?
It's my assumption that when I use the initial=parameter after a GET request, Django is storing that data somewhere and knows the context when the user then hits the 'submit data' button, is this wrong?
Yes you need to initialize your Form with initial data.
In your view the GET and POST requests have no common context. You may want to use sessions for that.
But in this case, it is not necessary. You can retrieve the instance on each request:
def contact_add(request):
if 'id' in request.GET:
new_contact_dynamic = contacts.models.PersonDynamic.objects.get(
person_static = request.GET['id'],
current_record_fg = True
)
if request.method == 'POST':
form = ContactManageForm(request.POST, initial=new_contact_dynamic.__dict__)
...
else: # Show an existing contact
form = ContactManageForm(initial=new_contact_dynamic.__dict__)
else:
form = ContactAddForm()
return render(request, 'contact_manage.html', {'form': form})

Django - Page not fully loaded after exception in form

In my django project, I have a view that displays details of an event. In that view there is a link to another view that contains the form to register people to that event.
If the maximum number of participants is reached and someone still tries to register, my view throws an exception. And returns from the formular-site back to the event-site. But the event-site is not fully loaded, I think the queries are no performed.
I don't know how to write the return function.
Additionally, is there a syntax error in my exception? When I create new instances of registration in the shell, I can save as many as I want.
def validate_category_full(category_id):
cat = Category.objects.get(id=category_id)
regs = cat.registration_set.all()
if len(regs) >= cat.max_people:
raise ValidationError('Category is already full.')
def registration(request, category_id, event_id):
"""Add a new registration to a category."""
cat = Category.objects.get(id=category_id)
myevent = Event.objects.get(id=event_id)
if request.method != 'POST':
form = RegistrationForm()
else:
form = RegistrationForm(request.POST)
try:
validate_category_full(cat.id)
except(ValidationError):
return render(request, 'events/event.html',
{'myevent': myevent,
'error_message': 'Event is full.',})
else:
if form.is_valid():
reg = form.save()
return HttpResponseRedirect(reverse('events:category',
args=(cat.id,)))
context = {'form': form, 'cat': cat, 'myevent': myevent}
return render(request, 'events/registration.html', context)`
Mostly a wild guess since I don't know what you mean by "the event-site is not fully loaded" (and assuming "event-site" and "formular-site" really mean "event page" and "formular page"):
First: you shouldn't render the template from another view but redirect to that view instead. If you want to display a message to the user (the "event is full" message in this case) when he gets redirected back to the other view, use the messages framework:
from django.contrib import messages
def registration(request, category_id, event_id):
# snip a lot of code
try:
validate_category_full(cat.id)
except(ValidationError):
messages.error(request, 'Event is full.')
return redirect(your_event_view_name, whatever_args_it_takes)
A few notes why we're at it:
=> Use queryset.count() instead of len(queryset.all())
def validate_category_full(category_id):
cat = Category.objects.get(id=category_id)
regs = cat.registration_set.count()
if regs >= cat.max_people:
raise ValidationError('Category is already full.')
Also since you already have the category, you may want to pass it instead of the category.id

int() argument must be a string or a number, not 'SimpleLazyObject'

I got, following Error messages,
TypeError at /save/ int() argument must be a string or a number, not
'SimpleLazyObject'
While executing following form.
views.py
def bookmark_save_page(request):
if request.method == 'POST':
form = BookmarkSaveForm(request.POST)
if form.is_valid():
# create or get link
link, dummy = Link.objects.get_or_create(
url = form.cleaned_data['url']
)
# create or get bookmark
bookmark, created = Bookmark.objects.get_or_create(
user=request.user,
link=link
)
# update bookmarks title
bookmarks.title = form.cleaned_data['title']
# if the bookmark is being updated, clear old tag list.
if not created:
bookmark.tag_set.clear()
# create new tag list
tag_names = form.cleaned_data['tags'].split()
for tag_name in tag_names:
tag, dummy = Tag.objects.get_or_create(name=tag_name)
bookmark.tag_set.add(tag)
# save bookmark to database.
bookmark.save()
return HttpResponseRedirect(
'/user/%s/' % request.user.username
)
else:
form = BookmarkSaveForm()
variables = RequestContext(request, {
'form': form
})
return render_to_response('bookmark_save.html', variables)
I thought I got error because I passed link at
bookmark, created = Bookmark.objects.get_or_create(
user=request.user,
link=link
)
But I can not figure out how to fix it.
How can I fix it?
The likely cause is that you're setting user = request.user, where request.user is not a real User object, but a SimpleLazyObject instance. See django: Purpose of django.utils.functional.SimpleLazyObject? for more details, but using request.user.id should fix your issue.
You have to login when running this piece of code on localhost. Otherwise the request.user will be a SimpleLazyObject, then the errors comes out.
Here you trying to create a Bookmark object based on request.user , but request.user is a SimpleLazyObject , so we can get a more secure user object by :
from django.contrib import auth
current_user = auth.get_user(request)
and further your query should be
bookmark, created = Bookmark.objects.get_or_create(
user=current_user,
link=link
)
Most likely the user who is loading the page is not authenticated. Therefor the error is thrown. If you want to save a request.user reference to the database, you obviously have to ensure that only authenticated users are able to call the function.
In your case there are two possibilities - add the "#login_required" decorator to the function or check if the user is authenticated inside the code. Here are the snippets:
With Decorator:
from django.contrib.auth.decorators import login_required
#login_required
def bookmark_save_page(request):
if request.method == 'POST':
form = BookmarkSaveForm(request.POST)
if form.is_valid():
# Do something
OR - checking inside the code if the user is authenticated:
def bookmark_save_page(request):
if request.method == 'POST' and request.user.is_authenticated():
form = BookmarkSaveForm(request.POST)
if form.is_valid():
# Do something
Thats strange, I had the same problem and the same solution. After trying a bunch of alternatives I went back to user = request.user and it worked
if you want to set an addition request attr, based on user -> you need to use lazy Django function which is correctly handled by Field.get_prep_value
from django.utils.functional import lazy
request.impersonator = lazy(lambda: request.user.id, int)()