I have a simple API that downloads a file in the system. It works perfectly in the local server, but when I deploy the same code to production, it gives me a 500 server error. If I try with another id that doesn't exist, it will say the object is not found.
My code is as follows.
def get_permissions(self):
"""
Instantiates and returns the list of permissions that this view requires.
"""
if self.request.query_params.get("download") == "file":
return []
return [permission() for permission in self.permission_classes]
def get(self, request, *args, **kwargs):
if request.query_params.get("download") == "file":
return self.download_file(request)
/....other codes........./
def download_file(self, request, *args, **kwargs):
instance = self.get_object()
file_handle = instance.file.path
document = open(file_handle, "rb")
response = HttpResponse(FileWrapper(document), content_type="")
response["Content-Disposition"] = (
'attachment; filename="%s"' % instance.file_name
)
return response
My endpoint URL is this:
{{prod}}api/v1/example/notes/12/?download=file
When I call this api, putting local in place of prod, it works and I get a file downloaded, but not in production. Is it something to do with file being closed before getting a response??
I've been playing with Django Two Factor authentication for the last two days or so, and I have it partially working. I am trying to figure out a way to remove the QR Token Generator. I have tried subclassing the setup view, but the form wizard is causing me some grief. The wizard is confusing me. I know in a regular form, how to remove radio buttons, but in this case, I can't seem to locate the source of the Token Generator.
The SetupView...
#class_view_decorator(never_cache)
#class_view_decorator(login_required)
class SetupView(IdempotentSessionWizardView):
"""
View for handling OTP setup using a wizard.
The first step of the wizard shows an introduction text, explaining how OTP
works and why it should be enabled. The user has to select the verification
method (generator / call / sms) in the second step. Depending on the method
selected, the third step configures the device. For the generator method, a
QR code is shown which can be scanned using a mobile phone app and the user
is asked to provide a generated token. For call and sms methods, the user
provides the phone number which is then validated in the final step.
"""
success_url = 'two_factor:setup_complete'
qrcode_url = 'two_factor:qr'
template_name = 'two_factor/core/setup.html'
session_key_name = 'django_two_factor-qr_secret_key'
initial_dict = {}
form_list = (
('welcome', Form),
('method', MethodForm),
('generator', TOTPDeviceForm),
('sms', PhoneNumberForm),
('call', PhoneNumberForm),
('validation', DeviceValidationForm),
('yubikey', YubiKeyDeviceForm),
)
condition_dict = {
'generator': lambda self: self.get_method() == 'generator',
'call': lambda self: self.get_method() == 'call',
'sms': lambda self: self.get_method() == 'sms',
'validation': lambda self: self.get_method() in ('sms', 'call'),
'yubikey': lambda self: self.get_method() == 'yubikey',
}
idempotent_dict = {
'yubikey': False,
}
def get_method(self):
method_data = self.storage.validated_step_data.get('method', {})
return method_data.get('method', None)
def get(self, request, *args, **kwargs):
"""
Start the setup wizard. Redirect if already enabled.
"""
if default_device(self.request.user):
return redirect(self.success_url)
return super(SetupView, self).get(request, *args, **kwargs)
def get_form_list(self):
"""
Check if there is only one method, then skip the MethodForm from form_list
"""
form_list = super(SetupView, self).get_form_list()
available_methods = get_available_methods()
if len(available_methods) == 1:
form_list.pop('method', None)
method_key, _ = available_methods[0]
self.storage.validated_step_data['method'] = {'method': method_key}
return form_list
def render_next_step(self, form, **kwargs):
"""
In the validation step, ask the device to generate a challenge.
"""
next_step = self.steps.next
if next_step == 'validation':
try:
self.get_device().generate_challenge()
kwargs["challenge_succeeded"] = True
except Exception:
logger.exception("Could not generate challenge")
kwargs["challenge_succeeded"] = False
return super(SetupView, self).render_next_step(form, **kwargs)
def done(self, form_list, **kwargs):
"""
Finish the wizard. Save all forms and redirect.
"""
# Remove secret key used for QR code generation
try:
del self.request.session[self.session_key_name]
except KeyError:
pass
# TOTPDeviceForm
if self.get_method() == 'generator':
form = [form for form in form_list if isinstance(form, TOTPDeviceForm)][0]
device = form.save()
# PhoneNumberForm / YubiKeyDeviceForm
elif self.get_method() in ('call', 'sms', 'yubikey'):
device = self.get_device()
device.save()
else:
raise NotImplementedError("Unknown method '%s'" % self.get_method())
django_otp.login(self.request, device)
return redirect(self.success_url)
def get_form_kwargs(self, step=None):
kwargs = {}
if step == 'generator':
kwargs.update({
'key': self.get_key(step),
'user': self.request.user,
})
if step in ('validation', 'yubikey'):
kwargs.update({
'device': self.get_device()
})
metadata = self.get_form_metadata(step)
if metadata:
kwargs.update({
'metadata': metadata,
})
return kwargs
def get_device(self, **kwargs):
"""
Uses the data from the setup step and generated key to recreate device.
Only used for call / sms -- generator uses other procedure.
"""
method = self.get_method()
kwargs = kwargs or {}
kwargs['name'] = 'default'
kwargs['user'] = self.request.user
if method in ('call', 'sms'):
kwargs['method'] = method
kwargs['number'] = self.storage.validated_step_data\
.get(method, {}).get('number')
return PhoneDevice(key=self.get_key(method), **kwargs)
if method == 'yubikey':
kwargs['public_id'] = self.storage.validated_step_data\
.get('yubikey', {}).get('token', '')[:-32]
try:
kwargs['service'] = ValidationService.objects.get(name='default')
except ValidationService.DoesNotExist:
raise KeyError("No ValidationService found with name 'default'")
except ValidationService.MultipleObjectsReturned:
raise KeyError("Multiple ValidationService found with name 'default'")
return RemoteYubikeyDevice(**kwargs)
def get_key(self, step):
self.storage.extra_data.setdefault('keys', {})
if step in self.storage.extra_data['keys']:
return self.storage.extra_data['keys'].get(step)
key = random_hex(20).decode('ascii')
self.storage.extra_data['keys'][step] = key
return key
def get_context_data(self, form, **kwargs):
context = super(SetupView, self).get_context_data(form, **kwargs)
if self.steps.current == 'generator':
key = self.get_key('generator')
rawkey = unhexlify(key.encode('ascii'))
b32key = b32encode(rawkey).decode('utf-8')
self.request.session[self.session_key_name] = b32key
context.update({
'QR_URL': reverse(self.qrcode_url)
})
elif self.steps.current == 'validation':
context['device'] = self.get_device()
context['cancel_url'] = resolve_url(settings.LOGIN_REDIRECT_URL)
return context
def process_step(self, form):
if hasattr(form, 'metadata'):
self.storage.extra_data.setdefault('forms', {})
self.storage.extra_data['forms'][self.steps.current] = form.metadata
return super(SetupView, self).process_step(form)
def get_form_metadata(self, step):
self.storage.extra_data.setdefault('forms', {})
return self.storage.extra_data['forms'].get(step, None)
Seems to reference a MethodForm...
class MethodForm(forms.Form):
method = forms.ChoiceField(label=_("Method"),
initial='generator',
widget=forms.RadioSelect)
def __init__(self, **kwargs):
super(MethodForm, self).__init__(**kwargs)
self.fields['method'].choices = get_available_methods()
I can't seem to track back to where the list of choices is defined, clearly in this case it is saying generator is the initial choice in setup, but I can't figure out how to remove the generator option as a list of valid choices. I also tried to remove generator from the form_list but this didn't seem to make a difference either.
If there's an easier way to remove the Token Generator option and a different approach that's altogether different, I'm open to that too.
Thanks in advance for any thoughts.
Found it. It was in the models.py....
def get_available_methods():
methods = [('generator', _('Token generator'))]
methods.extend(get_available_phone_methods())
methods.extend(get_available_yubikey_methods())
return methods
I removed the ('generator', _('Token generator')) reference from inside the brackets ( list ) and it removed the Token Generator option.
I'm looking for a simple tutorial explaining how to write items to Rethinkdb from scrapy. The equivalent can be found for MongoDB here.
Here is a translation of "Write items to MongoDB" line for line with RethinkDB.
A couple notes:
I'm not sure where crawler.settings are set.
The scrapy docs say process_item's second param item can be an
object or dict, so the .insert(dict(item)) cast/conversion is probably necessary.
import rethinkdb as r
class RethinkDBPipeline(object):
table_name = 'scrapy_items'
def __init__(self, rethinkdb_uri, rethinkdb_port, rethinkdb_db):
self.rethinkdb_uri = rethinkdb_uri
self.rethinkdb_port = rethinkdb_port
self.rethinkdb_db = rethinkdb_db
#classmethod
def from_crawler(cls, crawler):
return cls(
rethinkdb_uri=crawler.settings.get('RETHINKDB_URI'),
rethinkdb_db=crawler.settings.get('RETHINKDB_DATABASE', 'items')
)
def open_spider(self, spider):
self.conn = r.connect(
host = self.rethinkdb_uri,
port = self.rethinkdb_port,
db = self.rethinkdb_db)
def close_spider(self, spider):
self.conn.close()
def process_item(self, item, spider):
r.table(self.table_name).insert(dict(item)).run(self.conn)
return item
I am writing a web application using django and part of it requires me to download images given by google image search and store it in a directory onto the server. Here is the code I have written:
def post(self, request, *args, **kwargs):
image = request.FILES['image_file']
query = json.loads(request.POST['metadata'])
owner = User.objects.filter(username="jane")[0]
imageSearch = utils.GoogleImageSearch(query=query['query'], user=owner)
instance = ModelInstance(user=owner, raw_image=image, metadata=str(query))
instance.save()
someThread = utils.SomeThread(InstanceModel=instance, googleImageSearch=imageSearch)
someThread.start() #This line does not start a new thread on apache
someThread.join()
return Response(status=status.HTTP_200_OK)
Here is my utils.py
class GoogleImageSearch(object):
query = ""
directoryToSave = ""
numberOfImages = ""
user = ""
def initializeDirectoryStructure(self):
pathToStoreImages = self.directoryToSave
if os.path.exists(pathToStoreImages):
shutil.rmtree(pathToStoreImages)
os.makedirs(pathToStoreImages)
def __init__(self, query, user):
self.query = query
self.numberOfImages = constants.NUMBER_OF_SEARCH_RESULTS
self.user = user
self.directoryToSave = os.path.join(constants.IMAGE_CONTAINER_ROOT, user.username)
self.initializeDirectoryStructure()
def ImageSearch(self):
exitCode, numberOfImages = imagesearch.searchAndSave(self.query, os.path.join(constants.IMAGE_CONTAINER_ROOT, self.user.username) , constant$
class SomeThread(Thread):
def init(self, mosaicModel, googleImageSearch):
Thread.init(self)
self.mosaicModel = mosaicModel
self.googleImageSearch = googleImageSearch
def run(self):
self.googleImageSearch.ImageSearch()
When I run this code with the django development server, it runs fine.
But when I run this on Apache, the thread never starts.
I am guessing that apache does not allow new threads to be created from the django application.
I wanted to know if there any way(may be some apache configuration file changes) to start the thread.
Thanks in advance.
Working with ReviewBoard 1.6.11, which uses Django 1.3.3.
There is a RepositoryManager class that has a method called 'accessible', defined as this:
class RepositoryManager(Manager):
def accessible(self, user, visible_only=True, local_site=None):
"""Returns repositories that are accessible by the given user."""
if user.is_superuser:
qs = self.all()
else:
q = Q(public=True)
if visible_only:
q = q & Q(visible=True)
if user.is_authenticated():
q = q | (Q(users__pk=user.pk) |
Q(review_groups__users=user.pk))
qs = self.filter(q).distinct()
return qs.filter(local_site=local_site)
The problem is that I want to filter the results of this query by something else that does not interact with the database (filesystem permissions of the user). accessible() needs to return a QuerySet, though. Otherwise, I would just create a list and populate it with the appropriate items from the result.
I'm fairly new to Django. Is this a reasonable thing to do, or am I going about this all wrong?
I was able to solve this by creating a QuerySet subclass like so:
class RepositoryQuerySet(QuerySet):
def __init__(self, *args, **kwargs):
super(RepositoryQuerySet, self).__init__(*args, **kwargs)
self._user_filter = None
def _clone(self, *args, **kwargs):
retval = super(RepositoryQuerySet, self)._clone(*args, **kwargs)
retval._user_filter = self._user_filter
return retval
def filter_by_user_access(self, user):
self._user_filter = user.username
def iterator(self):
for repo in super(RepositoryQuerySet, self).iterator():
if self._user_filter is None:
yield repo
continue
# ...logic for restricting access by user...
# If user has access, just yield repo. If not, just 'continue'
Then in RepositoryManager.accessible, right after the call to distinct(), call:
qs.filter_by_user_access(user)
Finally, for the manager to use the new query set class, create:
def get_query_set(self):
return RepositoryQuerySet(self.model, using=self.db)
in the RepositoryManager class.