Django Model Manager for Default Options - django

I have a Django model which has a foreign key that is optional. I set it up this way so that table would contain default options of different service_types but one could override this option by specifying a controller foreign key.
Now in my views I have a bunch of code that looks like this:
try:
modeService = RegressionServices.objects.get(controller=controller, service_type=SERVICE_TYPE_CONTROLLER_MODE)
except RegressionServices.DoesNotExist:
modeService = RegressionServices.objects.get(service_type=SERVICE_TYPE_CONTROLLER_MODE)
I would like to reduce this down to one call and I think that a Django model Manager should be the way to do so. Essentially it would check for the controller in **kwargs and if present it would basically do the code above. I am looking in the docs and only finding that the get_query_set method is usually being overridden. Is it okay to override the get() method? Will I even have access to the RegressionServices model in a model Manager get() method?
Can anyone think of a way to do this other than a model manager?

Just do a logical OR, using Q objects.

Related

How can i change django rest default behaviour for primary keys

According to Docs
http://www.django-rest-framework.org/api-guide/serializers/
The default ModelSerializer uses primary keys for relationships
It means for relation ships by default it will use
PrimaryKeyRelatedField
Now i want that instead of PrimaryKeyRelatedField the django rest should use
CustomPrimaryKeyRelatedField by default.
I don't want to manually write that in my 30 serializers and just want that if its not defined then use CustomPrimaryKeyRelatedField
Which thing i need to override for that
If you want to override this behaviour without modifying your code, you need to mangle with package source code. I think it's sufficient to change serializer_related_field in ModelSerializer https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/serializers.py.
A better approach would be to create a class in your project which inherits from ModelSerializer and overrides this single field, then replace in your project ModelSerializer with MyModelSerializer.

In Django, how to use a manager as default but not for related fields?

Let's say I've got FooManager() that I set as the default manager for a model Foo, i.e. by having it be the first manager that Django encounters in the model definition. Now, admin, dumpdata, and Django generally uses this manager by default, as desired.
However, I don't want related field managers to use FooManager(), i.e. if Foo has a foreign key to Bar, then the related manager bar_instance.foo_set should use the "plain" Foo manager (to use the term in Django docs), not FooManager.
This doesn't seem possible, because the way to have FooManager NOT applied to related fields, is by setting its use_for_related_fields attribute to False. But all that does is get Django to use the the default manager (as opposed to the "plain" manager) for related fields.
And what's the default manager in this case? FooManager! Conundrum.
Any way to make this work, i.e. use FooManager as default manager but not for related fields?
NOTE: I'm using Django 1.6. I don't see anything in the 1.7 docs to suggest default/related manager behavior has changed. Also note I do NOT want to have to explicitly set the related manager per the new 1.7 functionality here; I want the reverse related manager to use the plain manager by default, as I'm refactoring an existing project and would prefer not to change every reverse related manager reference.
In this section the docs say the behavior is exactly what you want it to be.
The implementation also seems to do exactly what you want. 1.6 too.
Update:
If you don't want to change every usage, then create subclass of ForeignKey, which uses subclass of ForeignRelatedObjectsDescriptor as a related_accessor_class with this method overwritten.
Pseudo code:
class PlainManagerForeignRelatedObjectDescriptor(ForeignRelatedObjectDescriptor):
#cached_property
def related_manager_cls(self):
return create_foreign_related_manager(
models.Manager,
self.rel,
)
class PlainManagerForeignKey(ForeignKEy):
related_accessor_class = PlainManagerForeignRelatedObjectDescriptor

Django, Custom Managers affect save method?

I'm using Django 1.7. I've got a default custom manager that filters on an "active" boolean field. According to the docs, it needs to be the default manager to work with related fields (ie. accessing User.story_set only shows active Story objects). I'm keeping the standard manager for admin and shell access, but I am unable to save changes to objects, I'm speculating because save() methods pass through the default manager at some point.
class Story(models.Model):
active = models.BooleanField(default=True)
....
objects = ActiveStoryManager()
full_set = models.Manager()
class ActiveStoryManager(models.Manager):
def get_query_set(self):
return super(ActiveStoryManager, self).get_query_set().filter(active=True)
use_for_related_fields = True
This works well for all public-facing use. However, in admin and shell I am unable to affect inactive objects, including turning them back active.
story = Story.full_set.get(id=#) will fetch a story with active=False, but after setting active=True I am unable to save, getting a
django.db.utils.IntegrityError: duplicate key value violates unique constraint "stories_story_pkey"
DETAIL: Key (id)=(#) already exists.
Calling save.(force_update=True) returns django.db.utils.DatabaseError: Forced update did not affect any rows.
So while save() is a model method, it seems to depend on the default manager at some point in the saving process.
A workaround is using the Queryset API, e.g. Story.full_set.filter(id=#).update(active=True), but that's only usable in the shell, and requires manually typing each change, still can't save inactive instances in the admin.
Any help on this?
It cannot be done! As inancsevinc pointed out, save() calls on the default manager. The Django docs mention that get_query_set should not be modified on default managers, and I have sadly found out why. Hopefully in the future relatedManagers can be specified/controlled, but for now this method will not work for me. Confirmed in Django IRC chat.
Instead, I'm throwing together a ordinary Manager method, as well as model methods for some models, to get equivalent functionality. Also requires changing all the related_set calls in the template to include the new methods, so it's a pain, but no other way.
To make admin page work with a different manager, you can implement get_queryset method on your ModelAdmin class.
class StoryAdmin(ModelAdmin):
def get_queryset(self, request):
return self.model.full_set.get_queryset()

How do I change field or model attributes of a third-party Django app?

Let's say, I use django.contrib.flatpages, or any other third-party app in my project. I want to change some of this app's model attributes - for example, verbose_name.
How can I do that?
The simple answer is "don't"; use a proxy model instead.
It depends. If you want to add some new fields, you can create another model with OneToOneField. If you want to add some methods, ordering etc., use proxy model. If you want to change some DB restrictions (e.g. max_length) you can patch the source code of the app, but think twice before doing that, you should have a really good reason for that.
If you want to change verbose_name, you can override label in corresponding form field, no change in model needed.

Django - logical delete

I want to make the following modification to the Django framework.
I want it to create a "deleted" field for each model I create.
I want it to be checked as deleted when I delete it from the admin page instead of being physically deleted.
I do not want these records checked as deleted to be listed.
I'm new to Django, I'm seeing if I can do what I want to do with it easily. I need this change because it's the way we currently work.
So far these are the changes I have made, I would like to understand how the whole Django framewok works inside but I'm so far from that, is there any documentation online which explains clearly how the inside framework parts/files/modules/classes work together, the specific role of each one, etc
In the base.py file, in the modelbase class, below this code,
for obj_name, obj in attrs.items():
new_class.add_to_class(obj_name, obj)
I added,
from django.db import models
new_class.add_to_class('deleted', models.BooleanField())
When it creates a model it adds the "deleted" field to it.
In the base.py file, in the save method, I changed what it was there for
self.deleted = True
self.save()
So, now it check as deleted a record instead of physically delete it.
Now what I want is those records not to be listed.
I don't understand why you're modifying the framework code instead of putting your deleted field in a model base class that all of your models extend from.
Nevertheless, a nice way to filter those records out would be to add a custom manager to the model (or your base model class, if you choose to create one). To this manager, override the get_query_set method as described here. In your overridden method, add a exclude(deleted=True) filter.
Take a look at the Django-logicaldelete app, You just inherit your models from their provided Model class and you get Logical delete for all of them.
It comes with an adminModel as well so you can manage logically deleted models there too.
Override the delete() method in your model class, set the deleted attribute there
Create a custom manager which will filter by deleted attribute and set it as the default one (objects = MyDeletedManager)