Open mattlinares opened 11 years ago
Hi, I'm happy to help you. I never use widget in a test environment, but from your trace it's seems that the widget is not initialized correctly. The problem is that self.widgets is empty so i sugget if you don't use init you have to put the right inputWidget inside widgets tuple like in init :https://github.com/asaglimbeni/django-datetime-widget/blob/develop/datetimewidget/widgets.py#L80-82. Remember to use last version of widget 0.5.3.a use 'pip install django-datetime-widget' to update. Thank you for your contribution. Alfredo
Thanks for the quick response. I understand what is happening now. Since I'm testing with a POST and my view deals with POSTS like:
def new_event(request):
if request.method == 'POST':
form = EventForm(request.POST, request=request
as you the form and widget is not being initialised.
I'm not sure how I would put the input widget inside the widgets tuple in testing though. My test looks like this:
response = self.client.post('/events/new/', {'name': 'Wells',
'location': 'Wells', 'date': '2014-09-04 16:00:00.000000'})
self.assertEqual(response.status_code, 302)
Is there a way I can hook into the form widget initialisation sequence with a testing framework?
Don't worry if you can't help.
Thanks again! Matt
Hi Matt, Yes from the test is impossible to put widgetInput. Can you show me how is build EventForm? Are you sure that 'date': .... is the same fileds id of the Datetimewidget?
Thanks Alfredo,
Here's the form builder and below is the related view.
class EventForm(forms.Form):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(EventForm, self).__init__(*args, **kwargs)
name = forms.CharField(max_length=1024,
initial="Give short",
widget=forms.TextInput(attrs={'onfocus':'if(this.value=="Give short") this.value="";'}))
location = forms.CharField(max_length=1024,
initial="Be specific",
widget=forms.TextInput(attrs={'onfocus':'if(this.value=="Be specific") this.value="";'}))
dateTimeOptions = {
'format': 'dd/mm/yyyy HH:ii P',
'autoclose': 'true',
'showMeridian': 'true',
}
date = forms.DateTimeField(label="Date and time",widget=DateTimeWidget(options=dateTimeOptions,
attrs={'id':"date-time"}))
host_act = forms.CharField(max_length=1024,
initial="What act will you bring, if any?", required=False,
widget=forms.TextInput(attrs={'onfocus':'if(this.value=="What act will you bring, if any?") this.value="";'}))
description = forms.CharField(required=False, max_length=10240,
initial="Give some details. Any activities prepared?",
widget=forms.Textarea(attrs={'onfocus':'if(this.value=="Give some details. Any activities prepared?") this.value="";'}))
views.py
def new_event(request):
if request.method == 'POST':
form = EventForm(request.POST, request=request)
if form.is_valid():
event = Event(
date = form.cleaned_data['date'],
name = form.cleaned_data['name'],
description = form.cleaned_data['description'],
location = form.cleaned_data['location'],
host = request.user,
host_act = form.cleaned_data['host_act']
)
event.save()
member = request.user.get_profile()
member.event_commitments.add(event)
event_url = reverse('events',kwargs={'event_id':event.id})
user_list = User.objects.filter(userprofile__receive_email__exact=True)
mailing_list = []
for member in user_list:
mailing_list.append(member.email)
subject = 'event needs crew'
username = request.user.username
message = ('%s has proposed The event will only be publicised when there is enough crew.' % (username.capitalize, event.location, event.date, event_url))
send_mail(subject, message, 'info', mailing_list, fail_silently=False)
return HttpResponseRedirect(event.url)
else:
form = EventForm()
return render_to_response('new_event.html',{'form':form},
context_instance=RequestContext(request))
Try to run this Test:
response = self.client.post('/events/new/', {'name': 'Wells', 'location': 'Wells', 'date-time': '2014-09-04 16:00:00.000000'}) self.assertEqual(response.status_code, 302)
Let me know if it works
That seems to throw the same error.
======================================================================
ERROR: test_MyView (crewcal.tests.ResponseTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/methuselah/code/django/ssc/main/../crewcal/tests.py", line 56, in test_MyView 'location': 'Wells', 'date-time': '2014-09-04 16:00:00.000000'}) File "/Users/methuselah/.virtualenvs/ssc/lib/python2.7/site-packages/django/test/client.py", line 449, in post response = super(Client, self).post(path, data=data, content_type=content_type, extra) File "/Users/methuselah/.virtualenvs/ssc/lib/python2.7/site-packages/django/test/client.py", line 262, in post return self.request(r) File "/Users/methuselah/.virtualenvs/ssc/lib/python2.7/site-packages/django/core/handlers/base.py", line 111, in get_response response = callback(request, _callback_args, _callback_kwargs) File "/Users/methuselah/.virtualenvs/ssc/lib/python2.7/site-packages/django/contrib/auth/decorators.py", line 20, in _wrapped_view return view_func(request, _args, _kwargs) File "/Users/methuselah/.virtualenvs/ssc/lib/python2.7/site-packages/django/contrib/auth/decorators.py", line 20, in _wrapped_view return view_func(request, _args, *_kwargs) File "/Users/methuselah/code/django/ssc/main/../crewcal/views.py", line 117, in new_event if form.is_valid(): File "/Users/methuselah/.virtualenvs/ssc/lib/python2.7/site-packages/django/forms/forms.py", line 124, in is_valid return self.is_bound and not bool(self.errors) File "/Users/methuselah/.virtualenvs/ssc/lib/python2.7/site-packages/django/forms/forms.py", line 115, in _get_errors self.full_clean() File "/Users/methuselah/.virtualenvs/ssc/lib/python2.7/site-packages/django/forms/forms.py", line 270, in full_clean self._clean_fields() File "/Users/methuselah/.virtualenvs/ssc/lib/python2.7/site-packages/django/forms/forms.py", line 281, in _clean_fields value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name)) File "/Users/methuselah/.virtualenvs/ssc/lib/python2.7/site-packages/datetimewidget/widgets.py", line 91, in value_from_datadict D = to_current_timezone(datetime.strptime(date_time[0], self.format)) TypeError: must be string, not None
Ran 4 tests in 2.224s
FAILED (errors=2) Destroying test database for alias 'default'... (ssc)~/code/django/ssc:
Hi again,
The problem seems to be that the widget renames the date element as "date_0" but I was sending test data with a date field named "date". This value is not expected by other parts of the app so it chokes again later. Why does the widget rename the date value, and can you recommend a good way to alter this behaviour?
Thanks!
Hi Matt, Sorry but i did'nt have a lot of time to investigate your issue. Now for you question: The id is renamed by Django DateTimeInput, it's a normal behavior because in theory we can use more than one widget in one field. It's responsibility of value_from_datadict method to decompose the values into every input and return the correct value. I hope to find some of time next week to understand better what happen during your test. Alfredo
Hi, just wanted to say that we're hitting the same issue. The value_from_datadict
function being called is on django.forms.widgets.Widget
, and the implementation doesn't seem to deal with the renamed element. From pdb in that method (django/forms/widgets.py
):
ipdb> print data
<QueryDict: {u'from_date': [u'2008-01-01'], u'to_date': [u'2008-01-01']}>
ipdb> print name
from_date_0
so it's returning [None]
. In our case, we're using https://github.com/alex/django-filter to build the form, which may have something to do with it? Code is here:
https://github.com/openwater/h2o-really/blob/add-obs-basics/observations/filters.py
Thanks.
I had the same issue with unit tests, with the following date time format: %d/%m/%Y %H:%M:%S
I solved it using this format:
strart_date = start_date.strftime("%d/%m/%Y %H:%M") data = {"date": start_date} form = TestForm(data)
Hope it helps
I am still not able to get this going. Can anyone help any further?
@llazzaro I wasn't able to work your fix into my code. I tried a few things, a bit like this:
start_date = '2014-09-04 16:00'
start_date = time.strftime("%d/%m/%Y %H:%M", start_date)
response = self.client.post('/events/new/', {'name': 'Wells',
'location': 'Wells', 'date-time': start_date})
self.assertEqual(response.status_code, 302)
which raised:
TypeError: argument must be 9-item sequence, not str
Can you say exactly how you did it? Thanks. Btw, your use of strftime() seems to differ from the typical: http://docs.python.org/2/library/time.html#time.strftime
Thanks!
I've had to go ahead testing without the widget using this fix around my forms.py code where it is specified:
http://stackoverflow.com/questions/4088253/django-how-to-detect-test-environment
I'm not entirely happy with it. Perhaps I can include testing of the widget in Selenium or something later.
Any further thoughts or resolutions gladly accepted.
Hi mattlinares, sorry for late I was realy busy on last month. I want to ask you if you have update your version of django-datetime-widget with latest version 0.6? There are some fixes and maybe some of theme fix your test environment issue.
Thanks so much for this plugin. It's working well on the front end. However, I'm finding this bug in testing. Seems to choke in this widget. I can't work out why. I've tried to work through what's happening but can't find the issue. Can you help? Thanks again!
The test adds an object using a date and stumbles in its attempt.