Django Admin: Managing database - django

I am using Django admin for managing my data. I have the following tables: Users, Groups, and Domains. Users has a many-to-many relationship with both Groups and Domains. Domains has a one-to-many relationship with Groups. When I remove a User from a Domain, I also want to remove any entries in Users_Groups for that particular User and Groups belonging to the Domain.
How do I do this? Where do I put the code?
Thanks.

The Django book (specifically, Appendix B) seems to suggest you override the delete method on the User model class and have it trigger the extra deletes.

I would suggest overriding save, but I'm guessing you're using the django.contrib.auth.User object. In that case, you can accomplish about the same thing with a pre_save signal:
def manage_domains(signal,**kwargs):
if kwargs.has_key('instance'):
instance = kwargs['instance']
else: return
old_instance = User.objects.get(pk=instance.pk)
instance_categories = instance.categories.all()
for group in old_instance.groups.all():
if group not in instance_categories:
instance.groups.clear()
pre_save.connect(manage_domains, sender=User)
This is not even close to an efficient solution. What will happen is that when a User object is saved, the above changes will be made to the object in memory, then the save will overwrite the object in the database. You've gone to the trouble not only of hitting the database to find out if the unmodified version of the object agrees with with what you're about to save, but you're also looping through two category sets, both requiring a database hit to load.
The best way to make an efficiency improvement here would be to subclass the ManyToMany field manager itself, because that's what's paying attention to changes as they occur in memory, rather than merely comparing state after the fact. But this would be a bit more involved and would also require you to abandon the built-in User object.

Related

Django auth_user - Best practice to exclude inactive users

Our app sets the is_active field in User Model to False to represent a deleted user.
What's the best practice for excluding the deleted users (where is_active=False) from each and every access to the user table?
Please consider the following:
1. The app is already written, so we'd appreciate as minimum code changes as possible.
2. The app uses: request.user, get_object_or_404() and of course User.objects, so the solution has to take all of them into account.
From the research I've done, I found:
1. Proxy model: will force me to make a lot of changes in the code; I don't know how it works with request and get_object_or_404().
2. contribute_to_class: Can it be used to override objects manager or to just to add a new one? Is it safe?
3. Middleware changes: I don't want to get into this. Too risky for me.
Is there an elegant way for doing this?
There's no way to do this, nor should you try. The only way to limit every action to a selection of model instances is to limit the default queryset, which then effectively orphans the excluded instances, providing no way to access them ever again. The Django docs explicitly warn against this behavior.
If you override the get_query_set() method and filter out any rows, Django will return incorrect results. Don't do that. A manager that filters results in get_query_set() is not appropriate for use as an automatic manager. (emphasis mine)
"Automatic" managers are basically the same as the default manager. It's what's used for related fields, in the Django admin, and in countless other areas of the Django machinery. If you limit the default manager, you limit everything across the board.
Now, there's other options for quickly accessing the limited queryset; they simply aren't "automatic", meaning you still must make a point of using them instead of just having everything happen by magic. However, "magic" violates one of the core Python tenants in this respect: explicit is better than implicit. Limiting the User queryset by default is an implicit action. Filtering the queryset manually, referencing a custom manager method, or using a subclass of User are all explicit actions, and preferable as a result.

How best to handle m2m relationships within an API

I'm busy creating an API using django with tastypie. I'm at a bit of a loss on how I should manage the foreign key relationship updates. I have User and Group objects related in a many-to-many fashion. Tastypie offers functionality for me to update the related set within each update, ie when I update a group I must supply the whole corresponding user set.
Ideally I'd like to have separate functionality to add and remove relationships. Consider the fact that 1 group has 1000 users, and I simply want to remove 2 users. I would love to access a url and give the 2 users that need to be deleted instead of loading the group object with its 1000 users, removing 2, then sending 998 users back along with the group details.
What is the correct design method to handle this case? Considering my use of tastypie, how can I best implement this practically?

django: context info for permissions/rules

Folks, I run into a scenario which I believe is quite common but am a little lost over it.
In a company different categories of employees can have different
access rights. In django, this can be implemented using Groups and Permissions.
All employees have common permissions to access their company 's
portal, and also while everyone can insert comments inside the
portal, the number and type of comments one can make can differ
according to the category he is in.
Admin can change these numbers and also the permissions
(common/unique) each group have. I've looked at django-rules but I need to store this extra info somewhere.
Admin can add more categories and assign the same kind of permissions.
Currently, I use this:
class GroupPermExtra(models.Model):
group = models.ForeignKey(Group)
permission = models.ForeignKey(Permission)
context_info = models.TextField()
class Meta:
unique_together = (("group", "permission"),)
to store the extra info (in this case, the number of comments), which I thought may be stored as json.
However, I believe the above is not a good solution as there is already a many
to many attribute between Group and Permission but since I can't add
a intermediate through, what would be a better way to do this?

Filtering of data according to user logged in Django app

I have a Django app that works well for me, but currently has no notion of user: I am the only one using it, and I would like to change this...
Except for the admin views, the logged-in user should not have access to the data created by other users. There is no shared data between users.
I suppose I have to add a user foreign key to all the models I created. Correct?
Is there a simple way to implement the filtering based on request.user? Can this be done more or less automatically, or do I have to go through all the code to check each and every query done on the database?
I have written the code using TDD, and I intend to follow up... What are the best strategies to ensure that user-filtering is implemented correctly, e.g. that I did not forget to filter an existing query? I suppose I can write tests that show that a particular query is not yet filtered, and implement the filter. But what about the queries that I will write later? Is there a way I can assert that all existing and future queries return objects that only belong to the current user?
Thanks.
Yes, you'll need to add a User FK. Don't forget you'll have to migrate your database tables - either manually, or via a tool like South.
One way of implementing the filter would be to define custom Managers for your models, with a for_user method that takes the User as an argument: something like:
class ForUserManager(models.Manager):
def for_user(self, user):
return self.filter(user=user)
Now you can use this manager - subclassed and/or with a mixin as necessary - on all your models, and remember to use objects.for_user(request.user) everywhere.
This will make testing easier too - your test could monkeypatch that for_user method so that it sets a flag or a counter in a global variable somewhere, and then test that it has incremented as expected.
Edit in response to comment No, as you suspect, that won't work. It's not even that everyone will necessarily get the last-logged-in user: it's that Managers are class-level attributes, and as such are reused throughout a process, so any request served by that server process will use the same one.

Django: Difference between User.objects.profile.all() and User.objects.get_profile()?

I have a UserProfile model with related_name='profile' for the User FK.
Let's say I have a User obj, user1. If I want to get the UserProfile object from the user1, what is the difference between using user1.profile.all() and user1.get_profile() in terms of db hits and efficiency?
Neither of these commands is actually valid in Django. However, if you fix the syntax issues, they do completely different things.
If you want to get both the User instance and its associated Profile in one go, with a single db hit, you would use this:
user = User.objects.select_related('profile').get(pk=my_pk_value)
Now you can access the profile from the user by doing user.profile, and you don't incur another db hit. You can do exactly the same if you miss out select_related, but it will incur another db hit.
If you already have a User object user, you would do user.get_profile(), and that gets you the actual Profile object - with another db hit.