Passing kwargs from template to view? - python

As you may be able to tell from my questions, I'm new to both python and django. I would like to allow dynamic filter specifications of query sets from my templates using **kwargs. I'm thinking like a select box of a bunch of kwargs. For example:
<select id="filter">
<option value="physician__isnull=True">Unassigned patients</option>
</select>
Does django provide an elegant solution to this problem that I haven't come across yet?
I'm trying to solve this in a generic manner since I need to pass this filter to other views. For example, I need to pass a filter to a paginated patient list view, so the pagination knows what items it's working with. Another example is this filter would have to be passed to a patient detail page so you can iterate through the filtered list of patients with prev/next links.
Thanks a bunch, Pete
Update:
What I came up with was building a FilterSpecification class:
class FilterSpec(object):
def __init__(self, name, *args):
super(FilterSpec, self).__init__()
self.name = name
self.filters = []
for filter in args:
self.add(filter)
def pickle(self):
return encrypt(pickle.dumps(self))
def add(self, f):
self.filters.append(f)
def kwargs(self):
kwargs = {}
for f in self.filters:
kwargs = f.kwarg(**kwargs)
return kwargs
def __unicode__(self):
return self.name
class Filter(object):
def __init__(self, key, value):
super(Filter, self).__init__()
self.filter_key = key
self.filter_value = value
def kwarg(self, **kwargs):
if self.filter_key != None:
kwargs[self.filter_key] = self.filter_value
return kwargs
I then can filter any type of model like this:
filterSpec = FilterSpec('Assigned', Filter('service__isnull', False)))
patients = Patient.objects.filter(**filterSpec.kwargs())
I pass these filterSpec objects from the client to server by serializing, compressing, applying some symmetric encryption, and url-safe base-64 encoding. The only downside is that you end up with URLs looking like this:
http://127.0.0.1:8000/hospitalists/assign_test/?filter=eJwBHQHi_iDiTrccFpHA4It7zvtNIW5nUdRAxdiT-cZStYhy0PHezZH2Q7zmJB-NGAdYY4Q60Tr_gT_Jjy_bXfB6iR8inrNOVkXKVvLz3SCVrCktGc4thePSNAKoBtJHkcuoaf9YJA5q9f_1i6uh45-6k7ZyXntRu5CVEsm0n1u5T1vdMwMnaNA8QzYk4ecsxJRSy6SMbUHIGhDiwHHj1UnQaOWtCSJEt2zVxaurMuCRFT2bOKlj5nHfXCBTUCh4u3aqZZjmSd2CGMXZ8Pn3QGBppWhZQZFztP_1qKJaqSVeTNnDWpehbMvqabpivtnFTxwszJQw9BMcCBNTpvJf3jUGarw_dJ89VX12LuxALsketkPbYhXzXNxTK1PiZBYqGfBbioaYkjo%3D
I would love to get some comments on this approach and hear other solutions.

Rather than face the horrible dangers of SQL injection, why not just assign a value to each select option and have your form-handling view run the selected query based on the value.
Passing the parameters for a DB query from page to view is just asking for disaster. Django is built to avoid this sort of thing.

Concerning your update: FilterSpecs are unfortunately one of those (rare) pieces of Django that lack public documentation. As such, there is no guarantee that they will keep working as they do.
Another approach would be to use Alex Gaynor's django-filter which look really well thought out. I'll be using them for my next project.

Related

Generic method for updating entity with transactions

I have a GAE model with several methods that update entities with transactions. Something like this:
class MyModel(ndb.Model):
#staticmethod
#ndb.transactional
def update_foo(ekey):
entity = ekey.get()
entity.foo = "x"
entity.put()
#staticmethod
#ndb.transactional
def update_bar(ekey):
entity = ekey.get()
entity.bar = "y"
entity.put()
To clean up my code, I was thinking, I could centralize the code that does updates with transactions. Something like this:
class MyModel(ndb.Model):
#staticmethod
#ndb.transactional
def update_tx(ekey, **kwargs):
entity = ekey.get()
for prop, value in kwargs.iteritems():
setattr(entity, prop, value)
enitty.put()
def update_foo(self):
self.update_tx(self.key, foo="x")
def update_bar(self):
self.update_tx(self.key, bar="y")
Is this a reasonable idea, or are there dangers in this approach that I haven't considered?
It's reasonable. It really depends on your use case.
I actually had something similar in place, but more and more I have to special case my update_tx() for each entity type to the point that only 1 or 2 of my ~10 models still use it, because there is almost always other logic that needs to be executed.
If I update a user's account state from 'deactivated' to 'activated' I need to perform a few queries to see if they completed all the mandatory onboarding steps.
If a user updates their email I have to send a new verification link to that new email before it can change
Certain fields are only editable if the entity is in a certain state
If a user submit's a new start date and end date, I need to save the old start date and end date in new object for historical purposes
etc
That logic could happen outside of this function, but I often want that to happen in the same transaction.
That aside, one thing it doesn't seem to handle is needing to update a batch of entities in a single transaction, so your pseudo code would need to look more like this if that's important to you:
class MyModel(ndb.Model):
def update_properties(self, **kwargs):
for prop, value in kwargs.iteritems():
setattr(self, prop, value)
#staticmethod
#ndb.transactional(xg=True)
def update_txs(keys, updates):
# keys is an array of ndb.Key()s,
# updates is an array of the same size, containing **kwargs for each key
entities = ndb.get_multi(keys)
for index, entity in enumerate(entities):
entity.update_properties(**updates[index])
ndb.put_multi(entities)
#classmethod
def update_tx(cls, ekey, **kwargs):
cls.update_txs([ekey], [kwargs])
def update_foo(self):
self.update_tx(self.key, foo="x")
def update_bar(self):
self.update_tx(self.key, bar="y")

Transparently storing Django model field as JSON data

Say I have an object, "Order," a field of which, "items," holds a list of order items. The list of items will never be searched or individually selected in the database so I just want to store it in a DB field as a JSON string.
I'm trying to figure out the best way to embed this functionality so it's fairly transparent to anyone using the model. I think saving the model is pretty easy - just override the save method and serialize the "items" list into an internal "_items" field, and then write that to the db. I'm confused about how to deserialize, though. Having looked into possibly some kind of classmethod for creation, or creating a custom manger, or something to do with signals, I've thoroughly confused myself. I'm sure this has been solved a hundred times over and I'm curious what people consider to be best practice.
Example classes:
class OrderItem():
def __init__(self, desc="", qty=0):
self.desc = desc
self.qty = qty
class Order(Model):
user = ForeignKey(User)
_items = TextField()
def save(self, *args, **kwargs):
self._items = jsonpickle.encode(self.items)
super(Order, self).save(*args, **kwargs)
Example usage:
order = Order()
order.items = [OrderItem("widget", 5)]
order.save()
This would create a record in the DB in which
_items = [{"desc":"widget", "qty":5}]
Now I want to be able to later select the object
order = Order.objects.get(id=whatever)
and have order.items be the unpacked array of items, not the stored JSON string.
EDIT:
The solution turned out to be quite simple, and I'm posting here in case it helps any other newbies. Based on Daniel's suggestion, I went with this custom model field:
class JSONField(with_metaclass(SubfieldBase, TextField)):
def db_type(self, connection):
return 'JSONField'
def to_python(self, value):
if isinstance(value, basestring):
return jsonpickle.decode(value)
else:
return value
def get_prep_value(self, value):
return jsonpickle.encode(value)
A much better approach is to subclass TextField and override the relevant methods to do the serialization/deserialization transparently as required. In fact there are a number of implementations of this already: here's one, for example.

Pyramid resource: In plain English

I've been reading on the ways to implement authorization (and authentication) to my newly created Pyramid application. I keep bumping into the concept called "Resource". I am using python-couchdb in my application and not using RDBMS at all, hence no SQLAlchemy. If I create a Product object like so:
class Product(mapping.Document):
item = mapping.TextField()
name = mapping.TextField()
sizes = mapping.ListField()
Can someone please tell me if this is also called the resource? I've been reading the entire documentation of Pyramids, but no where does it explain the term resource in plain simple english (maybe I'm just stupid). If this is the resource, does this mean I just stick my ACL stuff in here like so:
class Product(mapping.Document):
__acl__ = [(Allow, AUTHENTICATED, 'view')]
item = mapping.TextField()
name = mapping.TextField()
sizes = mapping.ListField()
def __getitem__(self, key):
return <something>
If I were to also use Traversal, does this mean I add the getitem function in my python-couchdb Product class/resource?
Sorry, it's just really confusing with all the new terms (I came from Pylons 0.9.7).
Thanks in advance.
I think the piece you are missing is the traversal part. Is Product
the resource? Well it depends on what your traversal produces, it
could produce products.....
Perhaps it might be best to walk this through from the view back to
how it gets configured when the application is created...
Here's a typical view.
#view_config(context=Product, permission="view")
def view_product(context, request):
pass # would do stuff
So this view gets called when context is an instance of Product. AND
if the acl attribute of that instance has the "view"
permission. So how would an instance of Product become context?
This is where the magic of traversal comes in. The very logic of
traversal is simply a dictionary of dictionaries. So one way that this
could work for you is if you had a url like
/product/1
Somehow, some resource needs to be traversed by the segments of the
url to determine a context so that a view can be determined. What if
we had something like...
class ProductContainer(object):
"""
container = ProductContainer()
container[1]
>>> <Product(1)>
"""
def __init__(self, request, name="product", parent=None):
self.__name__ = name
self.__parent__ = parent
self._request = request
def __getitem__(self, key):
p = db.get_product(id=key)
if not p:
raise KeyError(key)
else:
p.__acl__ = [(Allow, Everyone,"view")]
p.__name__ = key
p.__parent__ = self
return p
Now this is covered in the documentation and I'm attempting to boil it
down to the basics you need to know. The ProductContainer is an object
that behaves like a dictionary. The "name" and "parent"
attributes are required by pyramid in order for the url generation
methods to work right.
So now we have a resource that can be traversed. How do we tell
pyramid to traverse ProductContainer? We do that through the
Configurator object.
config = Configurator()
config.add_route(name="product",
path="/product/*traverse",
factory=ProductContainer)
config.scan()
application = config.make_wsgi_app()
The factory parameter expects a callable and it hands it the current
request. It just so happens that ProductContainer.init will do
that just fine.
This might seem a little much for such a simple example, but hopefully
you can imagine the possibilities. This pattern allows for very
granular permission models.
If you don't want/need a very granular permission model such as row
level acl's you probably don't need traversal, instead you can use
routes with a single root factory.
class RootFactory(object):
def __init__(self, request):
self._request = request
self.__acl__ = [(Allow, Everyone, "view")] # todo: add more acls
#view_config(permission="view", route_name="orders")
def view_product(context, request):
order_id, product_id = request.matchdict["order_id"], request.matchdict["product_id"]
pass # do what you need to with the input, the security check already happened
config = Configurator(root_factory=RootFactory)
config.add_route(name="orders",
path="/order/{order_id}/products/{product_id}")
config.scan()
application = config.make_wsgi_app()
note: I did the code example from memory, obviously you need all the necessary imports etc. in other words this isn't going to work as a copy/paste
Have you worked through http://michael.merickel.org/projects/pyramid_auth_demo/ ? If not, I suspect it may help. The last section http://michael.merickel.org/projects/pyramid_auth_demo/object_security.html implements the pattern you're after (note the example "model" classes inherit from nothing more complex than object).

Check if a non-nullable field is null

I wanted to write some code like this:
class SomeModel(models.Model):
field = models.ForeignKey(SomeOtherModel)
def __init__(self, *args, **kwargs):
super(SomeModel, self).__init__(*args, **kwargs)
if self.field is None:
self.field = SomeOtherModel()
...
However this raises self.field.rel.to.DoesNotExist. The Django code is very clear on that:
class ReverseSingleRelatedObjectDescriptor(object):
def __get__(self, instance, instance_type=None):
...
if val is None:
# If NULL is an allowed value, return it.
if self.field.null:
return None
raise self.field.rel.to.DoesNotExist
An obvious workaround would be of course to make the field nullable however as far as I understand that would actually have an effect on the database schema, also I like the integrity checks Django offers. Another one would be to catch the exception and handle it appropriately. However this adds a lot of boilerplate code. Especially when there are multiple fields like that (a separate try...except block for each one of them - now that's ugly). What could I do?
I could use initial however this is quite limited when it comes to foreign keys. I do not always know the kind of default that I would like to have at the moment of creation. I will however know it at the initialization phase. Moreover it could then be dependent on the values of the other fields.
Check if it has the attribute set -
if hasattr(self, 'field')
proper way to refer a field in form is like this:
self.fields['myfield']
so, in your case, the null check should go like this
self.fields['myfield'].value is None
on the other note, don't use reserved/near to reserved words like 'field' for naming your fields.

How do I enforce domain integrity in a Django app transparently?

Here's the situation. I've got an app with multiple users and each user has a group/company they belong to. There is a company field on all models meaning there's a corresponding company_id column in every table in the DB. I want to transparently enforce that, when a user tries to access any object, they are always restricted to objects within their "domain," e.g. their group/company. I could go through every query and add a filter that says .filter(company=user.company), but I'm hoping there's a better way to do at a lower level so it's transparent to whoever is coding the higher level logic.
Does anyone have experience with this and/or can point we to a good resource on how to approach this? I'm assuming this is a fairly common requirement.
You could do something like this:
from django.db import models
from django.db.models.query import QuerySet
class DomainQuerySet(QuerySet):
def applicable(self, user=None):
if user is None:
return self
else:
return self.filter(company=user.company)
class DomainManager(models.Manager):
def get_query_set(self):
return DomainQuerySet(self.model)
def __getattr__(self, name):
return getattr(self.get_query_set(), name)
class MyUser(models.Model):
company = models.ForeignKey('Company')
objects = DomainManager()
MyUser.objects.applicable(user)
Since we are using querysets, the query is chainable so you could also do:
MyUser.objects.applicable().filter(**kwargs)

Categories

Resources