How to render Django UTC time in local time - django

I have USE_TZ = True enabled in my settings.py file, so dateTime values are stored as UTC. When I want to display these dates/times on a template, they will be displayed in whatever timezone I have set in setings.py with TIME_ZONE = 'America/Toronto'.
But what if my users are in different timezones and I want it to automatically change the time based on the users timezone?
I found that using javascript I can do :
new Date(djangoDate)).toLocaleString()
will format the date and time to my timezone, regardless of what I have in TIME_ZONE = 'America/Toronto'
But is there a way to do this in python/Django?
Everything I have tried, like {% load tz %} relies on TIME_ZONE = 'America/Toronto'. in settings.py.
I have also tried:
timezone.activate(pytz.timezone('America/Winnipeg')) in my view, which seems to display the dates as intended, but found that this will actually change the UTC value in the database when using forms to update dateTime data, which is behavior I do not want.
I want to store in UTC, and render/display in local time, automatically without the user having to tell the application what timezone they are in. Is this possible?
Edit
Elaborating on timezone.activate - it will remove 1 hour from buildStart when form is submitted, without user changing this field
views.py:
class BuildUpdateView_Building(LoginRequiredMixin,UpdateView):
model = Build
form_class = EditBuild_building
template_name = 'build_edit_building.html'
login_url = 'login'
def get(self, request, *args, **kwargs):
proceed = True
try:
instance = Build.objects.get(id = (self.kwargs['pk']))
except:
return HttpResponse("<h2 style = 'margin:2em;'>This build is no longer available it has been deleted, please please return to dashboard</h2>")
if instance.buildActive == False:
proceed = False
if instance.deleted == True:
proceed = False
#all appears to be well, process request
if proceed == True:
form = self.form_class(instance=instance)
timezone.activate(pytz.timezone(self.request.user.t_zone))
customer = self.request.user.PSScustomer
choices = [(item.id, (str(item.first_name) + ' ' + str(item.last_name))) for item in CustomUser.objects.filter(isDevice=False, PSScustomer = customer)]
choices.insert(0, ('', 'Unconfirmed'))
form.fields['buildStrategyBy'].choices = choices
form.fields['buildProgrammedBy'].choices = choices
form.fields['operator'].choices = choices
form.fields['powder'].queryset = Powder.objects.filter(PSScustomer = customer)
context = {}
context['buildID'] = self.kwargs['pk']
context['build'] = Build.objects.get(id = (self.kwargs['pk']))
return render(request, self.template_name, {'form': form, 'context': context})
else:
return HttpResponse("<h2 style = 'margin:2em;'>This build is no longer editable here, or has been deleted, please return to dashboard</h2>")
def form_valid(self, form):
proceed = True
try:
instance = Build.objects.get(id = (self.kwargs['pk']))
except:
return HttpResponse("<h2 style = 'margin:2em;'>This build is no longer available it has been deleted, please please return to dashboard</h2>")
if instance.buildActive == False:
proceed = False
if instance.deleted == True:
proceed = False
#all appears to be well, process request
if proceed == True:
form.instance.editedBy = (self.request.user.first_name)+ " " +(self.request.user.last_name)
form.instance.editedDate = timezone.now()
print('edited date ' + str(form.instance.editedDate))
form.instance.reviewed = True
next = self.request.POST['next'] #grabs prev url from form template
form.save()
build = Build.objects.get(id = self.kwargs['pk'])
if build.buildLength >0:
anticipated_end = build.buildStart + (timedelta(hours = float(build.buildLength)))
print(anticipated_end)
else:
anticipated_end = None
build.anticipatedEnd = anticipated_end
build.save()
build_thres_updater(self.kwargs['pk'])#this is function above, it updates threshold alarm counts on the build
return HttpResponseRedirect(next) #returns to this page after valid form submission
else:
return HttpResponse("<h2 style = 'margin:2em;'>This build is no longer available it has been deleted, please please return to dashboard</h2>")
form.py
class EditBuild_building(forms.ModelForm):
buildStart = forms.DateTimeField(input_formats = ['%Y-%m-%dT%H:%M'],widget = forms.DateTimeInput(attrs={'type': 'datetime-local','class': 'form-control'},format='%Y-%m-%dT%H:%M'), label = "Build Start Time")
def __init__(self, *args, **kwargs):# for ensuring fields are not left empty
super(EditBuild_building, self).__init__(*args, **kwargs)
self.fields['buildDescrip'].required = True
class Meta:
model = Build
fields = ['buildDescrip', 'buildStart','buildLength','project', 'customer','powder','buildNotes','buildLayerHeight',
'parameters','recoaterType','buildProgrammedBy','buildStrategyBy','operator',
'tempHighThres','tempLowThres',
'humidHighThres','humidLowThres','hardRecoatThres',]
labels = {
'buildDescrip': ('Build Description'),
'buildStart': ('Build Start Time'),
'buildLength': ('Build Length (hours)'),
'buildNotes': ('Build Notes'),
'powder': ('Powder Used for Build'),
'tempHighThres': ('High Temperature Alarm (℃)'),
'tempLowThres': ('Low Temperature Alarm (℃)'),
'humidHighThres': ('High Humidity Alarm (%)'),
'humidLowThres': ('Low Humidity Alarm (%)'),
'hardRecoatThres': ('Hard Recoat Threshold'),
'buildLayerHeight': ('Layer Height (microns)'),
'recoaterType': ('Recoater Type'),
'customer': ('Customer'),
'operator': ('Machine Setup by'),
'project': ('Project'),
'parameters': ('Build Parameters'),
'buildProgrammedBy': ('Build Programmed by'),
'buildStrategyBy': ('Build Strategy by'),
}
widgets = {'buildDescrip': forms.TextInput(attrs={'class': 'required'}),
When I submit this form, it will subtract one hour from buildStart in the database. It also sets the seconds to 00 for some reason?
When I remove timezone.activate this behavior disappears...
It appears to subtract the hour on the form.save() operation

Related

How do I validate a field based on it's initial value in forms.py?

I have a custom self.clean method in forms.py which contains a check on whether the POSTed date values overlap with existing records. In the case where the user edits their record, but does not change the dates, this validation stops the record update. How can I change the validation with If statement or otherwise dependant on if the user has modified the start_date or end_date fields?
I've tried looking at things like self.get_initial() and self.has_changed() which seem to only be applicable in the view function? I'd rather validate in forms.py.
If I could filter out the record currently being edited from my "overlap" validations, that may be the neatest solution.
forms.py:
class EditBookingForm(ModelForm):
class Meta:
model = Bookings
#user not included as that is handled in views
fields = ['start_date', 'end_date', 'type', 'approved', 'members', 'guests']
...
def clean(self):
form_data = self.cleaned_data
#check if dates overlap by more than one day (ie. can start/end on the same day)
overlap_in = Bookings.objects.filter(start_date__lt=form_data['start_date'], end_date__gt=form_data['end_date']).count()
overlap_st = Bookings.objects.filter(start_date__lt=form_data['start_date'], end_date__gt=form_data['start_date']).count()
overlap_end = Bookings.objects.filter(start_date__lt=form_data['end_date'], end_date__gt=form_data['end_date']).count()
overlap_same = Bookings.objects.filter(start_date=form_data['start_date'], end_date=form_data['end_date']).count()
overlap_over = Bookings.objects.filter(end_date__gt=form_data['start_date'], start_date__lt=form_data['end_date']).count()
overlap = overlap_end + overlap_in + overlap_same + overlap_st + overlap_over
if overlap > 0:
self._errors["start_date"] = ["Your dates overlap with an existing booking"]
del form_data["start_date"]
return form_data
views.py:
booking = get_object_or_404(Bookings, pk=booking_id)
if request.method == "POST":
form = EditBookingForm(request.POST)
if form.is_valid():
#some code
#if not POST request
else:
form = EditBookingForm(instance=booking)
context = {
'form': form,
}
return render(request, 'bookings/edit_booking_page.html', context)
A ModelForm that is editing an existing instance will be passed the instance that is being edited when initialized. You should be able to use this pre-edit instance and exclude it's pk from your querysets
bookings = Bookings.objects.all()
if self.instance.pk:
bookings = bookings.exclude(pk=self.instance.pk)
overlap_in = bookings.filter(start_date__lt=form_data['start_date'], end_date__gt=form_data['end_date']).count()
# etc
Your 5 querysets can by simplified to at most 3 so long as you validate that end_date is greater than start_date. It's probably possible to reduce them to 1...
# So long as end_date is greater than start_date then this should be covered by overlap_st
# overlap_in = Bookings.objects.filter(start_date__lt=form_data['start_date'], end_date__gt=form_data['end_date']).count()
overlap_st = Bookings.objects.filter(start_date__lt=form_data['start_date'], end_date__gt=form_data['start_date']).count()
# So long as end_date is greater than start_date then this should be covered by overlap_over
# overlap_end = Bookings.objects.filter(start_date__lt=form_data['end_date'], end_date__gt=form_data['end_date']).count()
overlap_same = Bookings.objects.filter(start_date=form_data['start_date'], end_date=form_data['end_date']).count()
overlap_over = Bookings.objects.filter(end_date__gt=form_data['start_date'], start_date__lt=form_data['end_date']).count()

Defaulting an updateview action in django form under a def post

Working with another coder on a project. His change stopped the UpdateView on some forms from saving edits. I realized why.... he defined a
def post
which works for the case he was working on, but needs an else action that just does a default update. I am not sure how to do this when he UpdateView isn't doing it all automagically.
The code to the UpdateView:
class ProviderUpdateView(UpdateView):
model = Provider
form_class = ProviderForm
provider_form_class = ProviderForm
provider_term_form_class = ProviderTermForm
template_name = 'ipaswdb/provider/provider_form.html'
success_url = '/ipaswdb/provider/'
def get_context_data(self, **kwargs):
context = super(ProviderUpdateView, self).get_context_data(**kwargs)
provider = context['object']
context['provider_id'] = provider.id
prov = Provider.objects.get(pk=provider.id)
#print "provider: ",
#print prov
#print "provider terminated: ",
#print prov.is_terminated
if prov.is_terminated:
provider_form = ProviderFormView(instance=prov)
context['readonly'] = True
else:
print("NOT TERMINATED SO LETS DO THIS")
provider_form = ProviderForm(instance=prov)
context['readonly'] = False
context['provider_form'] = provider_form
provider_term_form = ProviderTermForm()
context['provider_term_form'] = provider_term_form
### Get the list of GroupLocations, but remove the current one this provider is associated with
### I just need the grouplocation id and the name
#grplocs = GroupLocationProvider.objects.filter(
return context
def post(self, request, *args, **kwargs):
#print self.request.POST.keys()
#print self.request.POST.values()
print("Posting...")
if self.request.POST.has_key('terminate'):
provider = Provider.objects.get(pk=kwargs['pk'])
form = ProviderTermForm(request.POST)
if form.is_valid():
print "Terminating Provider: ",
print provider
provider_term = ProviderTerm()
provider.is_terminated = True
provider.save()
### Update the term fields
provider_term.provider = provider
provider_term.old_id = provider.id
provider_term.term_date = form.cleaned_data['term_date']
provider_term.term_comment = form.cleaned_data['term_comment']
provider_term.save()
return HttpResponseRedirect(self.success_url)
I know I need an else to this statement in the post:
if self.request.POST.has_key('terminate'):
I am just not sure what the just do your regular thing' is in the UpdateView. I tested my hypothesis that his code broke the ability to edit and save a provider cause I removed the def post completely, and all worked well with the UpdateView automagic. Since we are overriding? the def post it seems to me we have to handle the regular update ourselves, just not sure how that looks.

request.user is not letting me make changes to the current user?

In my view function, I'm trying to make 2 modifications to the current user; consider him a premium subscriber by marking model field is_premium_subscriber as True and adding him to a group named Premium Agents.
However the changes don't seem to be registering in my views.py! Here is my code:
def payment_response(request):
new_charge = PremiumSubscriptionCharge()
if request.method == "POST":
... Some code here
try:
... lots of code here
new_charge.agent = request.user # This line is working fine, meaning request.user is properly assigned to the current user
request.user.is_premium_subscriber = True # This is not working, is_premium_subscriber is still false after the request
premium_agent_group = Group.objects.get(name='Premium Agents')
premium_agent_group.user_set.add(request.user) # This is not working either, the current user does not get added to the group.
request.user.save() # I don't know if this is necessary, but I put it here just in case.
except stripe.error.CardError as ce:
... some code
else:
... some code
My user model for reference. I created a custom User model by inheriting AbstractUser... could this have caused the issue?
class Agent(AbstractUser):
is_premium_subscriber = models.BooleanField(default=False)
Full views function:
def payment_response(request):
new_charge = PremiumSubscriptionCharge()
if request.method == "POST":
token = request.POST.get("stripeToken")
try:
customer = stripe.Customer.create(
email = request.user.email,
source = token,
)
charge = stripe.Charge.create(
amount = 1500,
currency = 'cad',
customer = customer.id,
description = "Agent Premium Subscription"
)
subscription = stripe.Subscription.create(
customer=customer.id,
items=[
{
"plan": "premiumagent",
},
],
)
new_charge.stripe_charge_id = charge.id
new_charge.agent = request.user
new_charge.customer = charge.customer
new_charge.stripe_subscription_id = subscription.id
request.user.is_premium_subscriber = True
premium_agent_group = Group.objects.get(name='Premium Agents')
premium_agent_group.user_set.add(request.user)
request.user.save()
except stripe.error.CardError as ce:
return False, ce
else:
new_charge.save()
return redirect("payment_success")
Okay I was working on something else, came back to it, and now it is working. What the. Thank you to those who commented.

Django form efficiency issue

I have inherited some code that was handled by multiple developers, and as such, there is no standard for the product. I am having significant performance issues, and am remedying a lot of them, but don't know how to break this one down. When the user submits on a page that pre-populates with data, and allows the user to select a date for the activity, they can submit, and anything with a date goes away for them. The problem is within the views.py. When the user submits, the following code runs, and hangs up at formset = formset(request.POST). I'm assuming that there are multiple db calls happening, but am not seeing them when I print to terminal. Below is the entirety of the submission process.
STATES = ['Routed','Reconciled']
formset = None
form = StudyOnlyForm()
study_pk = request.GET.get('study', '0')
if study_pk == '' or study_pk == '0':
study_pk = 0
# child transactions that are 'Recoginzed',
# reportable with a 'Routed' parent
qs = Transaction.objects.filter(contract__reportable=True,
cleared = False,
contract__study__pk=study_pk,
transaction_status='Recognized',
parent_transaction__isnull=False,
parent_transaction__transaction_status__in=STATES)
#Designed to capture standalone contracts
qs1 = Transaction.objects.filter(contract__reportable=True,
cleared = False,
contract__study__pk=study_pk,
contract__contract_type__name='Standalone',
transaction_status__in=STATES)
#Captures Arms contracts for Milestone payments
parent_list = []
arms_list = []
parent = Transaction.objects.filter(parent_transaction__isnull=True,
contract__reportable=True,
cleared = False,
contract__study__pk=study_pk,
contract__contract_type__name='ARMs',
transaction_status__in=STATES)
children = Transaction.objects.filter(contract__reportable=True,
cleared = False,
contract__study__pk=study_pk,
transaction_status='Recognized',
contract__contract_type__name='ARMs',
parent_transaction__isnull=False,
parent_transaction__transaction_status__in=STATES)
for child_item in children:
parent_list.append(child_item.parent_transaction.pk)
arms_list.append(child_item.pk)
for parent_item in parent:
if parent_item.pk not in parent_list:
arms_list.append(parent_item.pk)
qs3 = Transaction.objects.filter(pk__in=arms_list)
qs4 = qs | qs1 | qs3
qs = qs4.order_by('-pk')
formset = modelformset_factory(Transaction, form=PaidDateForm, extra=0, can_delete=False)
if request.method == "POST":
print 'if request.POST'
print datetime.datetime.now()
formset = formset(request.POST)
print 'created formset'
print datetime.datetime.now()
if formset.is_valid():
print 'formset valid'
print datetime.datetime.now()
updated_transactions = formset.save(commit=False)
print 'updated transactions'
print datetime.datetime.now()
for trans in updated_transactions:
if trans.paid_amount is not None and trans.date_cleared is not None:
trans_to_change = Transaction.objects.get(pk=trans.pk)
trans_to_change.paid_amount = trans.paid_amount
trans_to_change.date_cleared = trans.date_cleared
trans_to_change.paid_currency = trans_to_change.entered_currency
trans_to_change.paid_amount_usd =
Decimal(str(trans_to_change.paid_amount * Decimal(str(trans_to_change.exchange_rate)).quantize(Decimal('0.01')))).quantize(Decimal('0.01'))
trans_to_change.edited_by = request.user
trans_to_change.cleared = True
trans_to_change.save()
if updated_transactions:
messages.add_message(request, messages.INFO, 'The transactions have been updated successfully.')
return HttpResponseRedirect(reverse('track:update_pdate'))
else:
messages.add_message(request, messages.INFO, 'No transactions have been updated.')
return render_to_response(
'track/paid_date_update.html',
{'formset':formset,
'form': form,
'study_pk':study_pk,
},
context_instance=template.RequestContext(request))
else:
formset = formset(queryset=qs)
return render_to_response(
'track/paid_date_update.html',
{'formset':formset,
'form': form,
'study_pk':study_pk,
},
context_instance=template.RequestContext(request))
Forms:
class StudyOnlyForm(forms.Form):
action = forms.CharField(widget=forms.HiddenInput())
#
# JBL - Q4.0 changed this form to pull all studies (previously
# only 'active' studies), which really means all studies
# that are not 'ccc' studies
#
study = forms.ModelChoiceField(required=False,
label='Protocol',
queryset=Study.objects.all().exclude(study_status='ccc'))
def __init__(self, *args, **kwargs):
self.req = True
if 'req' in kwargs:
self.req = kwargs.pop('req')
super(StudyOnlyForm, self).__init__(*args, **kwargs)
print 'StudyOnlyForm() init'
self.fields['study'].required = self.req
class PaidDateForm(forms.ModelForm):
formfield_callback = jquery_datefield
paid_amount = forms.DecimalField(label="Cleared
Amount",max_digits=14,decimal_places=2,required=False)
date_cleared = forms.DateField(label="Cleared Date",widget=JQueryDateWidget(),
input_formats=settings.DATE_INPUT_FORMATS, required=False)
class Meta:
model = Transaction
include = ('date_time_created')
def __init__(self, *args, **kwargs):
super(PaidDateForm, self).__init__(*args, **kwargs)
print 'PaidDateForm init'
for field in self.fields:
if field != 'date_cleared':
self.fields[field].widget = forms.HiddenInput()
self.fields['paid_amount'].widget.attrs['size'] = 12
self.initial['paid_amount'] = '%.2f' % (self.instance.usd_amount)
You restrict the queryset in the GET branch, but not the POST branch. That means that the POST branch creates a formset containing every transaction.
replace your for loop:
for trans in updated_transactions.exclude(paid_amount=None, date_cleared=None).all():
trans_to_change = Transaction.objects.get(pk=trans.pk)
trans_to_change.paid_amount = trans.paid_amount
trans_to_change.date_cleared = trans.date_cleared
trans_to_change.paid_currency = trans_to_change.entered_currency
trans_to_change.paid_amount_usd = Decimal(str(trans_to_change.paid_amount * Decimal(str(trans_to_change.exchange_rate)).quantize(Decimal('0.01')))).quantize(Decimal('0.01'))
trans_to_change.edited_by = request.user
trans_to_change.cleared = True
trans_to_change.save()

how to overide in forms queryset none() attribute and somehow allow to save the field?

I have models.py
class Visit(Model):
reference_visit = models.ForeignKey('self',
help_text="Visit needs a refrence to Prior Visits",
null=True, blank=True)
show_prior_responses = models.BooleanField(default=False,
help_text="Show PriorResponses")
# has many field but i am making it short.
def __unicode__(self):
result = """Visit id:%s pt:%s""" % (self.id, self.patient.id)
return result
forms.py
class VisitSetupForm(Form):
list_visit_ids = ModelChoiceField(
queryset=Visit.objects.none(),
empty_label='Select Revisit ID',required=False)
show_prior_visit = ModelChoiceField(
queryset=User.objects.all(),
empty_label="Select User for Revisit",required = False)
has many but question is on list_visit_ids.
views.py
def setup(request):
"""
Allow an Admin user the ability to setup a patient & visit all at once.
"""
if request.user.is_superuser:
form_class = AdminVisitSetupForm
all_topics = True
else:
form_class = VisitSetupForm
all_topics = False
f = form_class()
# Get a list of topics for each report.
report_topics = {}
for r in Interview.objects.all():
report_topics[r.id] = [t['ad'] for t in r.topics.values('ad')]
data = {
'superuser':request.user.is_superuser,
'report_topics':simplejson.dumps(report_topics)
}
try:
request.user.reviewer
data['reviewer'] = True
except:
pass
if request.method == "POST":
f = form_class(request.POST)
if f.is_valid():
# Create the patient, generate a password, and send them on their way.
cd = f.cleaned_data
patient = None
if cd['revisit']:
# Check for an existing user first.
try:
patient = Patient.objects.get(username=cd['username'])
except Patient.DoesNotExist, e:
data['form'] = f
data['msg'] = 'There is no user with this username.'
return render_to_response('visit/setup.html', data, context_instance=RequestContext(request))
admin_user = get_user(request)
organization = None
if admin_user:
organization = admin_user.organization
if patient and not request.user.is_superuser:
# Make sure the patient they've selected is one of their own.
if patient.organization != organization:
return HttpResponseForbidden('You are not allowed to see this page.')
if not patient:
password = generate_password()
user = User.objects.create_user(cd['username'], cd['contact_email'], password)
user.first_name = cd['first_name']
user.last_name = cd['last_name']
user.save()
patient = Patient(
user=user,
username=user.username,
contact_phone=cd['contact_phone'],
date_of_birth=cd['date_of_birth'],
email=user.email,
first_name=user.first_name,
gender=cd['gender'],
last_name=user.last_name,
maiden_name=cd['maiden_name'],
organization=organization,
patient_type=cd['patient_type'],
security_answer=cd['security_answer'],
security_question=cd['security_question'],
)
patient.save()
# Send them an email.
t = loader.get_template('www/new_account.txt')
c = Context({
'password':'%s-%s-%s' % (password[:3], password[3:5], password[5:]),
'patient':patient
})
msg = t.render(c)
try:
send_mail(
'A request by your physician to do an online medical history before your appointment.',
msg,
'support#careprep.com',
[user.email]
)
except Exception, e:
log.error('Could not send email for new account %s because: [%s]' % (user.username, e))
request.session['password'] = password
# Create the Visit, too.
interview = cd['interview']
list_visit_ids = cd['list_visit_ids']
print list_visit_ids
visit = Visit(
reference_visit = cd['list_visit_ids'],
show_prior_responses = cd['show_prior_responses'],
patient=patient
)
if request.user.is_superuser:
topics = cd['topics']
else:
topics = set(list(interview.topics.all()) + list(cd['topics']))
reviewer_mode = cd.get('reviewer_mode') or patient.patient_type == 'Reviewer'
url, visit = initialize_visit(
request,
patient=patient,
starting_section=interview.starting_section,
visit_title='%s %s' % (patient, interview.title),
topics=topics,
reviewer_mode=reviewer_mode,
chief_complaint=cd['chief_complaint'],
location=cd['interview_site'],
reference_visit = cd['list_visit_ids'],
show_prior_responses = cd['show_prior_responses'],
)
next_url = "/visit/confirmation/%s/%s/?next=%s" % (patient.user.id, interview.id, url)
else:
v = Visit.objects.get(pk=request.POST['list_visit_ids'])
print v
return HttpResponseRedirect(next_url)
# all the fields that are not given pls ignore.
The template is fine.
Now watch forms.py when i do list_visit_ids = ModelChoiceField(queryset=Visit.objects.all(), empty_label='Select Revisit ID',required=False) It works perfectly fine on my local machine.But on my server it has around 6000 visit objects so this page hangs or i should say keep on loading.
So initially i changed it to list_visit_ids = ModelChoiceField(queryset=Visit.objects.none(), empty_label='Select Revisit ID',required=False)
Now i know that by this the form becomes invalid and should go to the else part Now my question how do i make reference_visit=cd['list_visit_ids'] in else (form is invalid)
case save().How do i override the none() attribute.
Thanks in advance i will really appreciate.
If your goal is to save your html page load by removing the 6000 choices (which I've done too: 10000+ <option> fields wrapped by misc html will absolutely choke a page), you shouldn't be using a ChoiceField at all. By setting queryset=Visit.objects.none() you're allowing zero choices and nothing passed in will validate.
You either show 6000 select item drop downs, radio boxes, etc., or find a way to /not/ have a giant select drop down (such as a hidden input or charfield), not fake around a ModelChoiceField who's main purpose is to populate that select drop down and validate.
In short: don't use a ModelChoiceField if you're not going to be using the html choices generated by it. Use something else and do the validation / model pulling yourself via the clean_FOO methods.
class MyForm(forms.Form):
my_input = forms.CharField()
def clean_my_input(self):
input = self.cleaned_data.get('my_input')
try:
return MyModel.objects.get(pk=input) # add a filter here if you want
# (whatever filters you were using in the queryset argument)
except MyModel.DoesNotExist:
raise forms.ValidationError("Doesn't exist / is invalid")
return input