Django Tastypie: Allow Random as an Order By Option - django

Per this question, I know how to randomly order a queryset in the Meta class of a tastypie Resource, but is there a way to make it an available order_by option instead of making it the default? It looks like anything defined in the ordering Meta setting must also be listed in the fields setting and ? obviously isn't a field. Without that I simply get,
{"error": "No matching '?' field for ordering on."}

You can override the apply_sorting method (documentation) on your Resource, maybe something like this (untested):
class YourResource(ModelResource):
def apply_sorting(self, obj_list, options=None):
if options and '?' in options.get('order_by', ''):
return obj_list.order_by('?')
return super(YourResource, self).apply_sorting(obj_list, options)
You might need to copy code from the ModelResource implementation for getting the correct order_by value if this doesn't work as-is.

Related

Is it possible to edit the 'field' class variable in Django CBV using URL args?

I am trying to use a CreateView to create a profile object. Depending on the type of profile, though, I want to show a different set of fields. Right now I am passing the type of profile through the url.
How would I go about accessing this argument to filter the types of fields? I know how to do so in something like a get() function in a CBV, but not in the body of the class itself. I also do not know if there is an appropriate function to do this in and have not been able to find a solution in the docs.
Thank you in advance for any help, and I am sorry if this question has an obvious answer that I have missed.
You would need to override some method. Potential methods that can work are get_form_class, get_form, etc. Try overriding get_form:
class MyView(CreateView):
model = SomeModel
fields = None
def get_form(self):
self.fields = ['field1', 'field2'] # set this according to your conditions
# the keyword arguments passed to the view can be accessed by using self.kwargs.get('<key_name>')
return super().get_form()

Django - Meta.base_manager_name - make related argument in the custom queryset and manager

I have a custom model manager and a custom queryset defined specifically for related obj which means I have defined Meta.base_manager_name in the model.
I would like to use a all() manager method which fetches related obj on a OneToOneFeild.
Now I know this does not make sense since OneToOneFeild will always return one obj there is no need for a all() method. I am working on django-oscar project and am extending its "Partner" model. It originally has a field "users" with ManyToManyField and now changed to a OneToOneFeild.
The users field is called in code several times using relation user.partners.all(). I don't want to extend/modify all these places (am I being lazy here?) since I want to keep the code as upgrade friendly as possible and so instead I wanted to have all() model manager defined which will work. Not sure if it is a good idea?
the all() method takes user arg to return queryset of the user instance
class PartnerQuerySet(models.QuerySet):
def all(self, user):
return self.filter(user=user)
class PartnerManager(models.Manager):
def get_queryset(self):
return PartnerQuerySet(self.model, using=self._db)
def all(self, user):
return self.get_queryset().all(users)
class Partner(models.Model):
objects = PartnerManager()
class Meta:
base_manager_name = 'objects'
The problem is when it is used with related obj it asks for user arg which makes sense but since I am using it with a related obj I wanted to use the related obj as arg so,
user.partner.all() - should use user as arg and fetch the results
user.partner.all(user) - and I should not have to do the below
2 related questions:
1) Does this make sense - should I be doing this?
2) how I can achieve user.partner.all() without adding user in arg
PS: I know i can work with middleware to get_current_user but this function is not reliable as per some of the responses on a different question on SO.
I don't think what you are trying to do will work. Your new situation with a OneToOneField gives you the partner instance.
>>>> user.partner
<Partner xxx>
While in the old situation with the ManyToManyField, the PartnerQuerySet would've been returned.
>>>> user.partner
<PartnerQuerySet []>
A solution would be to create a custom OneToOneField, but this would most probably violate the "simple is better than complex" rule and in the end may even be more work than changing all existing .all()'s.

What is the proper way of creating a setter for non-property model field

I want to define a setter function for a Django model field in order to validate the input and immediately raise a error if value is not valid.
I don't think that doing the validation in save() or pre_save() is a feasible solution for my problem because of things beyond my control.
Also changing the field into a property and use plain field.getter and field.setter are not feasible as this will break .filter(), .exclude() etc on the field, plus it will require a scheme change even if I changed field to _field and overrode the manager.
So, am I forced to override __setattr__ or is there a better way of doing this?
You could subclass the Field and override to_python.
class UnforgivingCharField(CharField):
__metaclass__ = models.SubfieldBase
def to_python(self, value):
if not passes_my_test(value):
raise Hell()
return super(UnforgivingCharField, self).to_python(value)
This is used when the value is set and also during get_prep_value, etc., so it will catch invalid values when filtering.
More on this here. Note the line at the bottom of the linked section that tells us to_python will be called.
Edit: Just in case you happen to be using South, you will need to add some introspection rules if you implement custom model fields.
See this django ticket:
https://code.djangoproject.com/ticket/3148
Also, see here for discussion:
Django model fields getter / setter
And this blog post:
http://www.b-list.org/weblog/2006/aug/18/django-tips-using-properties-models-and-managers/
Also note there is the option of using a custom manager that translates your filter kwargs for you, and using _name for fields, and making your own #name.setter #name.getter etc.
Can you just define a function that provides the proper functionality and raises the correct error?
class YourModel(models.Model):
def add_your_value(self, value):
# check if value is correct
# raise exception if it isn't
# set correct property

Django TastyPie Geo Distance Lookups

I'm using TastyPie for Geo-distance lookups. That is a bit difficult, because oficially its not supported by TastyPie. On Github (https://gist.github.com/1067176) I found the following code-sample:
def apply_sorting(self, objects, options=None):
if options and "longitude" in options and "latitude" in options:
return objects.distance(Point(float(options['latitude']), float(options['longitude']))).order_by('distance')
return super(UserLocationResource, self).apply_sorting(objects, options)
It works well, but now I would like to have the distance as a field result in TastyPie. Do you have any idea how to do that? Just including "distance" in the fields attribute doesn't work.
Thanks in advance for your help!
The fields defined in the meta attributes aren't enough to have the additional values returned.
They need to be defined as additional fields in the resource:
distance = fields.CharField(attribute="distance", default=0, readonly=True)
This value can be filled by defining dehydrate_distance method inside the resource
def dehydrate_distance(self, bundle):
# your code here
or by adding some additional elements to queryset in resources meta like so:
queryset = YourModel.objects.extra(select={'distance': 'SELECT foo FROM bar'})
Tastypie itself appends a field called resource_uri that isn't actually present in the queryset, looking at the source code of tastypie's resources might be helpful for you too.

Django - how to write custom queryset per-field instead instead of per-model

I want to create a custom field such that if the field is queried, then the filter is always __iexact.
Example:
class Domain(models.Model):
domain = models.IExactCharField()
name = models.CharField()
I want a query like Domain.objects.filter('domain=newdomain') to be rewritten as Domain.objects.filter('domain__iexact=newdomain').
I understand you can do this with a custom manager, but I want adding the field to add the custom manager. And if a custom manager is already defined, I want the managers functionality to be chained. Is this possible? I was looking at the contribute_to_class method and thought it might have some potential when defining the field.
The code below won't work - the lookup_type is being added elsewhere (in QuerySet) unfortunately. I'll take a look inside :)
class IExactCharField(models.CharField):
def get_prep_lookup(self, lookup_type, value):
return super(IExactCharField, self).get_prep_lookup('iexact', value)
It enforces iexact lookups - you can evantually add check of lookup_type before referencing to superclass.
PS. Bear in mind that some databases (SQLite) won't support case insensitive unicode string lookups.
EDIT: the only workaround I have is to make all domain fields lowercase on save() or some save signal.