How can I use a different object manager for related models? - django

I have a couple of classes:
class Person(models.Model):
address = models.ForeignKey(Address, on_delete=models.CASCADE)
class Address(LiveModel):
address = models.CharField(max_length=512)
some_manager = SomeManager()
some_other_object_manager = OtherManager()
class Meta:
base_manager_name = 'some_other_object_manager'
Because I set some_manager, the default manager used is SomeManager which is good. BUT if I am querying a Person, I want it to use Address's OtherManager manager for querying and I thought that by setting base_manager_name, I would be able to achieve this (https://docs.djangoproject.com/en/2.2/topics/db/managers/#using-managers-for-related-object-access). Unfortunately this does not work. Any ideas? Particularly I am trying to achieve this in the admin, if that makes a difference.

To clarify, this does work as intended. The issue here was in the detail. I was using the Django admin which does not query the related fields the way I expected. It actually uses the related fields default manager for the queryset. If you want to do what I am trying to do, this is a nice simple example: https://books.agiliq.com/projects/django-admin-cookbook/en/latest/filter_fk_dropdown.html

Related

Prefetch queryset when related_name="+"

Is it possible without related name (related_name="+") to prefetch objects on the target instance? Sure I know it's not a problem with the related name, but I'm not really sure if it's possible without it.
Here is the example code:
from django.db import models
class Parent(models.Model):
name = models.CharField(max_length=50)
class Child(models.Model):
parent = models.ForeignKey(to=Parent, related_name="+", on_delete=models.CASCADE)
name = models.CharField(max_length=50)
Parent.objects.all().prefetch_related('child_set')
Maybe it's possible using the Prefetch(lookup, queryset=None, to_attr=None) object, because it takes the queryset in the argument list?
Looked through the code a bit and found this line:
rel_obj_descriptor = getattr(instance.__class__, through_attr, None)
Here instance is the model instance, and through_attr is the field name of related instance to be fetched. This line basically tries to get a related descriptor to perform the prefetch query. In your case rel_obj_descriptor would contain None.
To answer your question no it is not possible at least for a Foreign Key, there may be some hack for Many to Many relationships as Django appears to use some internal descriptors for them.
I would advice you to simply not set related_name="+" since you want to use the backwards relation here. You say "It's because of separation of concerns between multiple apps" but that does not make much sense. Don't we set a foreign key to the user model for various other models anyway and still use the related name? Does the point of separation of concerns arise there(the user model is in a separate app)?
try
parent = Parent.objects.get(id=pk)
parent.child_set.all()
I don't know if having related_name = '+' prevents this situation, but if you never define related_name, you can definitely use this method.

How to display manytomany field in django admin with a related model in a user-friendly way?

I'm struggling to display a manytomany field in the admin with the related model in a user-friendly manner. The project is already up and running so adding a through table is not preferred.
The set-up is something along these lines;
class User(AbstractUser):
is_member_of_organization = models.ManyToManyField(Organization, blank=True, verbose_name=_("is member of organization(s)"), related_name='orgmembers')
class Organization(models.Model):
name = models.CharField(max_length=60, verbose_name=_("organization name"))
the only reasonable way I manage to display the related users with organization admin is via a TabularInline
admin.py
class UserOrgAdminInLine(admin.TabularInline):
model = User.is_admin_for_organization.through
extra = 0
#admin.register(Organization)
class OrganizationAdmin(admin.ModelAdmin):
inlines = (UserOrgAdminInLine,)
However, looking up users is not convenient as soon as their number increases. I would like something similar to filer_horizontal but I am not sure how to include it directly in the OrganizationAdmin admin class. Furthermore, I am using fieldsets (which I believe should have no special rules or syntax to it compared to ordinary fields = .
One little subquestion - in the tabular inline, when I use only model = User django throws an error that there is no foreign key to it, but when I use the additional .is_admin_for_organization.through it works, but there is no through table and I though that this work just in that case. Why is that?
Any help would be much appreciated.
Try adding
class UserOrgAdminInLine
raw_id_fields = ("is_member_of_organization",)

Create a Django's model which can have one of two types

I have a model Client which can be one of two types: PJ or PF. That means that a Client can have the fields of a PJ model or the fields of a PFmodel.
But I'm not sure how I can do it using the Django's models and admin app. I would like to give the user the option to select which type the Client is and then the appropriate fields will be shown to him/her.
Can someone help me with this problem? Should I use some kind of Design Pattern or how should I create my models?
Thanks in advance.
Model PF:
class PF(models.Model):
name = models.CharField(max_length=512)
card = models.IntegerField(unique=True)
Model PJ:
class PJ(models.Model):
ie = models.IntegerField(unique=True, null=True, blank=True)
Model Client:
class Client(models.Model):
type = models.SmallIntegerField(default=0) # 0=PF, 1=PJ
First I'd recommend to look at the commonality between these two models and use inheritance if you can. If a type field is inevitable, I'd recommend using CharField with choices instead.
If the two models are drastically different, I'd recommend separating these two models completely, and call them InternalClient, ExternalClient, however the name would make sense to the data model.

Django model inheritance: Create a subclass using existing super class

I'm using multi-table-inheritance, and want to know how to create an inherited type from an instance of the superclass.
Using the example given in the documentation:
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
class Restaurant(Place):
serves_hot_dogs = models.BooleanField()
serves_pizza = models.BooleanField()
Now when you create a Restaurant, you automatically make a Place, which is fine, and the behaviour I expect and want.
But what if I make a Place, and later decide I want to convert to a specific type (like Restaurant). How do you create a Restaurant, using an existing Place?
Multi-table inheritance is just OneToOneField relation between Place and Restaurant.
place = Place.objects.get(id=1)
# Create a restaurant using existing Place
restaurant = Resturant(place_ptr=place)
restaurant.save()
place = Place.objects.get(id=1)
# Create a restaurant using existing Place
place.__class__ = Restaurant
place.save()
restaurant = place
While undocumented, this seems to do the trick:
restaurant(place_ptr=place).save_base(raw=True)
This solves the problem without using any hacks and is the shortest solution, also in terms of processing, using Django APIs.
While searching for this solution, I also found a slightly longer one, but using documented APIs. It is basically the same as Mariusz answer, also see this answer for more details:
from django.forms.models import model_to_dict
restaurant(place_ptr=place, **model_to_dict(place)).save()
However, this second one is more risky due to limited field set returned by the model_to_dict (see again the answer explaining the differences among various methods presented). Naturally, it also generates more DB calls because it writes to both tables.

Handling uniqueness in a multi-tenant Django setup

I ahve a multi tenant Django database. All my multi tenant enabled models import from a class AccountSpecificModel, which as a FK to a class Account. Now I have some unique=True and unqiue_together in Meta, which do not specify account.
In my scenario, for AccountSpecificModel uniqueness has no menaing unless it takes care of account, which means I want to convert each unique to a unique_together with account, and simlar for unique_together.
How can I do this?
If I'm understanding you correctly, this is what you want:
class Client(models.Model):
account = models.ForeignKey(Account)
email = models.EmailField()
class Meta:
unique_together = (('account', 'email'),)
Notice the "two-tuple" I assigned unique_together to. You can do a standard tuple, but if there is more than one field that you want to be unique together, you'll just have to change it anyway.
Now 500 different accounts can have a client with the email example#example.com, but no account can have 2 clients with the same email.
I did not understand your question fully, but I found that when implementing complicated django model class customizations one good solution is a class factory. I found that it is less complicated and less surprising than multiple inheritance and other magic.
def factory(superclass, arguments):
class SomeClass(superclass):
[...]
class Meta:
[...]
return SomeClass
RealClass = factory(SuperClass, args)
I tried other approaches on a similar sounding problem for a while, but a factory for the class solved the problem in the end. Think about it, it may help you to solve your problem.