I wrote simple plugin to add comments onto page using form.
Here is the plugin code:
class KomentarzePlugin(CMSPluginBase):
model = CMSPlugin
name = _("Komentarze plugin")
render_template = "komentarze/komentarze_wtyczka.html"
def render(self, context, instance, placeholder):
request = context['request']
print 'weszlo1'
print request.method
if request.method == 'POST':
form = KomentarzForm(request.POST)
print 'weszlo2'
if form.is_valid():
user = form.cleaned_data['user']
tresc = form.cleaned_data['tresc']
strona = request.current_page
data = timezone.datetime.now()
k = Komentarz(autor=user, data=data, tresc=tresc, strona=strona)
k.save()
context.update({
'instance': instance,
'placeholder': placeholder,
'komentarze': Komentarz.objects.all().filter(strona=request.current_page).order_by('-data'),
'forma': KomentarzForm()
})
return context
plugin_pool.register_plugin(KomentarzePlugin)
When I restart server, fill the form with data, hit submit, then if statement with POST method is satisfied and function enters it, post is added to database and shown. But, when I try to do it again, it don't even print request.method to console, which means it is empty. Restarting server fixes the problem. Also it doesn't work when I restart the server, do some random menu clicks, and then try to fill and send the form.
Any guess?
I finally solved my problem. In KomentarzePlugin class I added:
cache = False
Related
I have a Django function-based form view that initializes a form with default data on a GET request, and saves the model object on a POST request:
def copy(request, ann_id):
new_ann = get_object_or_404(Announcement, pk=ann_id)
new_ann.pk = None # autogen a new primary key (quest_id by default)
new_ann.title = "Copy of " + new_ann.title
new_ann.draft = True
new_ann.datetime_released = new_ann.datetime_released + timedelta(days=7)
form = AnnouncementForm(request.POST or None, instance=new_ann)
if form.is_valid():
new_announcement = form.save(commit=False)
new_announcement.author = request.user
new_announcement.datetime_created = timezone.now()
new_announcement.save()
form.save()
return redirect(new_announcement)
context = {
"title": "",
"heading": "Copy an Announcement",
"form": form,
"submit_btn_value": "Create",
}
return render(request, "announcements/form.html", context)
I can't figure out how to test the form.is_valid() branch when the form is posted, without manually providing the form data to self.client.post(url, form_data) in my view.
Here' what I'm trying:
test_views.py
class AnnouncementViewTests(TestCase):
def setUp(self):
self.client = ...
... etc
def test_copy_announcement(self):
# log in a teacher
success = self.client.login(username=self.test_teacher.username, password=self.test_password)
self.assertTrue(success)
# hit the view as a get request first, to load a copy of the announcement in the form
response = self.client.get(
reverse('announcements:copy', args=[self.test_announcement.id]),
)
self.assertEqual(response.status_code, 200)
# The form in this response should be valid, and should bw
# accepted on a post request,
# that is what I am testing in this integration test.
form_data = response.how_do_get_the_form_data() # ???????
response = self.client.post(
reverse('announcements:copy', args=[self.test_announcement.id]),
data=form_data
)
# Get the newest announcement just made in the post request
new_ann = Announcement.objects.latest('datetime_created')
self.assertRedirects(
response,
new_ann.get_absolute_url()
)
What I want to actually test is that the result of the get provides valid default data for the form that can then be submitted via post request.
But I can't figure out how to access the form data resulting from the get request, so I can then feed it into the form_data provided to the post request.
EDIT
I found the location of the form in the get response, but I have no idea how to get that in code.
You can access the response form in this way:
response.context['form']
From here you can build your payload in this way:
retrieved_instance = response.context['form'].instance
form_data = dict(title=retrieved_instance.title, ... <all the other fields>)
response = self.client.post(
reverse('announcements:copy', args=[self.test_announcement.id]),
data=form_data)
)
This is not like resubmitting the page but is very similar because you're resubmitting the same form.
Actually, your test seems more like an e2e test (when speaking about integrations and e2e there is some ambiguity let's say), for this reason, if I were you, I would switch "tool" and use selenium to simulate a user interaction from the beginning (open an existing announcement) to the end, pressing the submit button on your web page.
Only in this way what you're submitting is the "real" response of the "get"
If you are new to this kind of test, you can find here a simple tutorial https://lincolnloop.com/blog/introduction-django-selenium-testing/ to understand the main concepts.
Your question is bit confusing but I will try to head you in right direction.
To clean-up the code you should use Class Based View where you can use your form easily anywhere. A sample code I just wrote:
class TestView(View):
template_name = 'index.html'
success_url = 'home' # dummy view
context = {"form": myform()}
# myform is the definition/class of your form which contains all attrs.
def get(self, request):
context = self.context
context['form'] = form # fill out your data here for get request
return render(request, self.template_name, context)
def post(self, request):
context=self.context
# self.context certain that you're using exact form which you defined in class-scope
form=context['form']
# Form Validation
if form.is_valid():
#perform any logical validations here and save the form if required
return redirect(self.success_url)
context = self.context
context['form'] = form # just to show you that you can access that form anywhere
return render(request, self.template_name, context)
You coul manually pass data to you form like this and test the is_valid function in a unit test:
form_data = {'my': 'value', 'form': 'value', 'fields': 'value'}
form = AnnouncementForm(form_data)
self.assertFalse(form.is_valid)
I'm trying to test an django ajax view that saves a field. Here's the test:
def test_ajax_save_draft(self):
self.client.force_login(self.test_user) # view requires login
sub = mommy.make(QuestSubmission, quest=self.quest2)
draft_comment = "Test draft comment"
# Send some draft data via the ajax view, which should save it.
ajax_data = {
'comment': draft_comment,
'submission_id': sub.id,
}
self.client.post(
reverse('quests:ajax_save_draft'),
data=ajax_data,
HTTP_X_REQUESTED_WITH='XMLHttpRequest',
)
self.assertEqual(draft_comment, sub.draft_text) # sub.draft_text = None, as if the ajax view was never called!
And here's the view:
#login_required
def ajax_save_draft(request):
if request.is_ajax() and request.POST:
submission_comment = request.POST.get('comment')
submission_id = request.POST.get('submission_id')
sub = get_object_or_404(QuestSubmission, pk=submission_id)
sub.draft_text = submission_comment
sub.save()
response_data = {}
response_data['result'] = 'Draft saved'
return HttpResponse(
json.dumps(response_data),
content_type="application/json"
)
else:
raise Http404
When I run the test, I get into the if block, and it can retrieve the comment and submission object, but when it returns to the test at the end, it's like the save never happened.
What am I doing wrong here?
Try calling sub.refresh_from_db()
Changes made to a model instance will only affect the instance being modified. Any existing model instances will not be updated, refresh_from_db will get the changes from the database
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 :)
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})
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