Django: Mixing managed transactions, raw SQL with cursors and COMMIT statements

This is definitely an issue that can slip under the radar without any explicit warnings. To get an idea of the issue at hand, imagine this scenario.

from django.db import transaction, models, connection

@transaction.commit_on_success
def safe_view(request):
# Object 1
x, is_new = SomeModel.objects.get_or_create(arg1 = '1', arg2 = '2')
x.some_custom_sql()

# Object 2
y = ImageModel(associated_object = x)
y.caption = "This should be created if the whole request is valid"
y.save()

# Abort
raise Exception("STOP! Hammertime.")


class SomeModel(models.Model):
title = models.TextField()

def some_custom_sql(self):
sql = "UPDATE %s SET fti = to_tsvector('%s') WHERE %s = %s" % (self._meta.db_table, self.title, self._meta.pk.column, self.pk)

cursor = connection.cursor()
cursor.execute(sql)
cursor.execute("COMMIT;")

Because the view safe_view() is wrapped in a transaction, you would presume that any code in there will be rolled back if an exception were to occur, so an instance of SomeModel and ImageModel would not exist.

However, due to an explicit call to "COMMIT" in some_custom_sql(), the transaction is finalised by the time it returns back to safe_view().

Once the code continues, it will create an instance of ImageModel and save it to the database.

Even though the view is wrapped in commit_on_success() and an exception is raised, the changes to the database are already permenant.

EBy the time you hit the exception, it would have:

  • Created an instance of SomeModel
  • Updated the row for the FTI entry
  • Created an instance of ImageModel

This is not ideal!

To prevent this, refrain from using "COMMIT" in raw SQL unless you know exactly what you're doing!

Instead, replace cursor.execute("COMMIT;") with transaction.commit_unless_managed(). It'll automatically detect if the database is locked in a transaction before committing the transaction.

This problem looks incredibly easy to spot when it's next to each other on the same page, but remember that the "COMMIT" lines could be anywhere in your project. Even in 3rd party modules you've downloaded.

They will silently break your transactions and leave little evidence of permanent database changes until somebody notices!

Be vigilant and you will spot out all the problems in no time!

7151214449524

Twitter Bootstrap: How to change the tooltip text label

Oh my God, twitter bootstrap is a pretty damn good styling and widget framework. Check it out!

My first issue with it however is that I couldn't find a way to change the tooltip label after it's been created.

It's easily solved, but with a rather convoluted and hidden method.

$('#target').attr('data-original-title', item.value + ' selected.').tooltip('fixTitle');

What this one line wonder does is change the title attribute, then tell it to update using the "fixTitle" call.

Flying-kick-headshot 
BOOM! HEADSHOT!

Source

Django: How to save InMemoryUploadedFile (a temporary uploaded file) to disk?

When a user uploads a file using forms.FileField, you usually want to save it in some way.

To stash the file away on disk, just use the following snippet.

from django.core.files.storage import default_storage
from django.core.files.base import ContentFile

file = request.FILES['your_file_fieldname']
path = default_storage.save('heart_of_the_swarm.txt', ContentFile(file.read()))

There you have it!

i4IaIek6mz5sW

Now back to more important things, like eating cheerleaders.

Source

Django: Programmatically saving image from URL to FileField or ImageField

This was a bit of a tricky one to figure out. The reason being we store our files not in the file system but using MogileFS, which required a custom Storage wrapper.

So our model looks a little something like this.

class Product(models.Model):
# other fields
image = models.FileField(storage = MogileFSStorage(), upload_to = 'product_images')

And that's completely fine if we're using the admin to manually upload image files.

However, if we wanted to programmatically save an image using code... Where do we begin?

I'm glad to say that it's actually easier than expected.

from django.core.files import File
from django.core.files.temp import NamedTemporaryFile

product = Product()
# set all your variables here
product.save()

# Save image
image_url = 'http://whatever.com/image.jpg'
img_temp = NamedTemporaryFile(delete = True)
img_temp.write(urlopen(image_url).read())
img_temp.flush()

product.image.save("image_%s" % product.pk, File(img_temp))
product.save()

And that's it! There's no need to worry about storage stuff because that's handled at the model declaration level.

This code should work fine for both FileField and ImageField.

Of course, how to access the file is completely up to you and out of the scope of this post.

5KbWT 
It'll all makes sense once someone puts it into perspective for you!

Sources

CSS: Horizontal scrollbar when using Facebook "fb-like" widget

This has been bugging me for a good while. Tracked it down to the Facebook "Like" widget taking up more horizontal real-estate than it should.

image

If I deleted the fb-like widget, everything would go back to normal. Unfortunately, that's not proper solution...

So why is it even showing up!?

  • Restricting the widths on the iframe didn't seem to do anything.
  • Restricting the width of the parent div didn't seem to do anything either.
  • Setting overflow hidden on the parent div didn't work.

So what now?

The answer lies a few elements above. The one just above the <script> tag. There's a hidden div #fb-root.FB_UI_Hidden, which has a div and iframe nested inside it.

That iframe is injected during load time and although out of sight, it has a width of 575px causing the horizontal scrollbar to show unnecessarily.

Solution? Well first, don't use overflow; hidden on the <body> tag as suggested here. That's just silly because it disables your scrollbars altogether.

The correct method is to target CSS styling to it and restrict the width.

.FB_UI_Hidden { width: 100px !important; }

That's it! Another one line wonder.

image

Source

 
Copyright © Twig's Tech Tips
Theme by BloggerThemes & TopWPThemes Sponsored by iBlogtoBlog