Extending the Auth User and Group models in Django - django

I initially extended only the Group model, and although I got the extra fields working correctly, I end up with inconsistent results when I switch back to the auth-user model:
group1 = MyGroup(..)
user = group1.user_set.all()[0]
group2 = user.groups.all()[0]
group1 == group2 #(False!)
type(group1) #MyGroup..
type(group2) #Group..
My next thought was to extend both the auth.User and auth.Group models.
Example structure:
from django.contrib.auth.models import User As DjangoUser
from django.contrib.auth.models import Group As DjangoGroup
class MyGroup(DjangoGroup):
extra1 = models.CharField(..)
class MyUser(DjangoUser):
extra1 = models.CharField(..)
Is this possible? I saw a bug-report stating it was fixed here. However I didn't see an example of the correct way to achieve this, nor was it clear if this portion was necessary post bug-fix:
manager = UserManager()
class MyUser(DjangoUser):
signature = forms.CharField()
post_count = forms.IntegerField()
objects = manager
_default_manager = manager
Any ideas/examples of this sort of behavior? I attempted to re-define the 'groups' link in the user model but that led to a validation error. Ideally I would like to be able to run the example above and have group1 == group2 and type(group2) == type(MyGroup())

You can dynamically add a new field to django User/Group models, so that no new class type will be created. For reference, see: http://code.google.com/p/comaie-django-groups/source/browse/trunk/src/comaie/django/groups/models.py?r=5
models.ForeignKey(
Group,
null = True,
blank = True,
related_name = 'children',
verbose_name = _('parent'),
help_text = _('The group\'s parent group. None, if it is a root node.')
).contribute_to_class(Group, 'parent')
def get_all_groups(self):
"""
Returns all groups the user is member of AND all parent groups of those
groups.
"""
direct_groups = self.groups.all()
groups = set()
for group in direct_groups:
ancestors = group.get_ancestors().all()
for anc in ancestors:
groups.add(anc)
groups.add(group)
return groups
setattr(User, 'get_all_groups', get_all_groups)

Related

get foreign key related data in django using filter

This is the model :
class Requirement(models.Model):
name = models.CharField(max_length=100)
user = models.ForeignKey(
User,on_delete=models.CASCADE, related_name = 'user'
)
assigned_user = models.ForeignKey(
User,related_name = "assigned",on_delete=models.CASCADE,
)
I am running this query:
requirementsOb = Requirement.objects.filter(user = currentUser)
Where currentUser is logged in user. The result returns multiple requriements. I also want to get all user related data. How can i get user related data only for assigned_user
You can try like this:
current_user = request.user
requirements = current_user.user.all() | current_user.assigned.all()
Or you can try this approach:
requirementsOb = Requirement.objects.filter(Q(user = currentUser) | Q(assigned_user=currentUser))
If you want to get user data from requirements, you can try:
for r in requirementsOb:
r.user
r.assigned_user
If you want to get only the first requirement from the requirementsOb, then try like this:
requirement = requirementsOb.first() # or .last() for last object
requirement.user
requirement.assigned_user
More information can be found in documentation.

How to test is user is one of the groups in a list of groups

I have a list of groups, and I want to test if the user belongs to any one of the groups.
I can get a list of user's groups:
user_groups = user_object.groups.all()
And I can use sets:
if not set(user_object.groups.all()).isdisjoint(group_list):
Is this the best way?
Added:
group_list comes from a many-to-many field from another model (MyClass.groups_allowed.all())
class MyClass(models.Model):
...
groups_allowed = ManyToManyField(Group, default=None, blank=True)
...
def user_can_view(self, user_object):
...
if not set(user_object.groups.all()).isdisjoint(self.groups_allowed.all()):
return True
...
You can check user's group like
if user_object.groups.filter(name = groupname).exists():
pass
or
if user_object.groups.filter(name__in= groupname_list):
pass
if group_list is queryset:
user_object.groups.filter(id__in=group_list.values_list('id', flat=True))
else you have get id from that list and do next:
user_object.groups.filter(id__in=groups_id_list)
it does just one request to your db

Not getting fields and their values which are ManyToManyField type

I have a django model named Persona:
class Persona(models.model):
name=models.CharField(max_length=100,primary_key=True)
pages_visited = models.ManyToManyField(Page)
items_searched = models.ManyToManyField(ItemsSearched)
visits = models.IntegerField(null=True,blank=True)
connect = models.CharField(max_length=True,null=True,blank=True)
image = models.ForeignKey('Image',on_delete=models.CASCADE)
def __str__(self):
return self.name
I have an object for this model:
<QuerySet [<Persona: aman>]>
Now when i am trying to get the values of all fields for this object i can see all fields and their corresponding values except fields which are ManyToManyField type.
I get the following result when i execute this : Persona.objects.filter(name='aman').values()
<QuerySet [{'visits': None, 'image_id': 3, 'name': 'aman', 'connect': 'call'}]>
I cannot see 'items_searched' and 'pages_visited' fields and their corresponding values though when i log into admin i can see them.
These are the images which show you my execution:
Command Prompt
Admin Panel
To access m2m filed in django there is .all() keyword refer this
p1 = Persona.objects.filter(name='aman')
p1_m2m = p1.pages_visited.all()
which will give the result you wanted
I believe what you're looking for is Inlines.
In your admin file, add
from .models import Page # Edit this import according to your project structure
class PagesVisitedInline(admin.TabularInline):
model = Page
class PersonaAdmin(admin.ModelAdmin):
[...] # admin code goes here
inlines = [PagesVisitedInline, ]
You could use StackedInline aswell if you prefer, read more here.

django efficient queryset on related fields

Suppose you have the following models
class User:
pass
class Tag:
pass
class UserTag: # user is interested in tag
user = models.ForeignKey(User)
tag = models.ForeignKey(Tag)
class Blog:
tags = models.ManyToManyField(Tag)
For a given user, I want to get all blogs that user expressed his interests by UserTag
something like
Blog.objects.filter(tags__usertag_set__user=user_id)
I can do this in multiple steps but is it the best way to do it?
user_tags = UserTag.objects.filter(user=user)
result = Blog.objects.none()
for user_tag in user_tags:
tag = user_tag.tag
q = tag.blog_set.all()
result = result | q
This inevitably iterates all user_tags and bad...
you can do
user_tags = list(UserTag.objects.filter(creator=user).values_list('id', flat=True))
Blog.objects.filter(tags__in=user_tag)

I do not understand this error involving two objects with a many-to-many relation with one another

I am implementing a web interface for email lists. When a list administrator logs in, the site will visually display which lists they are an owner of and corresponding information about the lists. For this I have decided to have two tables:
1) An owner table which contains entries for information about list administrators. Each of these entries contains a 'ManyToManyField' which holds the information about which lists the owner in any given entry is an administrator for.
2) A list table which contains entries with information about each email list. Each entry contains the name of the list a 'ManyToManyField' holding information about which owners are administrators the list.
Here is the code in models.py:
from django.db import models
class ListEntry(models.Model):
name = models.CharField(max_length=64)
owners = models.ManyToManyField('OwnerEntry')
date = models.DateTimeField('date created')
class Meta:
ordering = ('name',)
class OwnerEntry(models.Model):
name = models.CharField(max_length=32)
lists = models.ManyToManyField('ListEntry')
class Meta:
ordering = ('name',)
I have already set up a simple local database to create a basic working website with. I have populated it with test entries using this code:
from list_app.models import *
from datetime import *
le1 = ListEntry(
name = "Physics 211 email list",
date = datetime.now(),
)
le1.save()
le2 = ListEntry(
name = "Physics 265 email list",
date = datetime(2014,1,1),
)
le2.save()
oe1 = OwnerEntry(
name = 'wasingej',
)
oe1.save()
oe1.lists.add(le1,le2)
le1.owners.add(oe1)
le2.owners.add(oe1)
oe2 = OwnerEntry(
name = 'doej',
)
oe2.save()
oe2.lists.add(le1)
le1.owners.add(oe2)
Here is where my error occurs: When the user has logged in via CAS, I have them redirected to this page in views.py:
def login_success(request):
u = OwnerEntry(name=request.user)
print(u.name)
print(u.lists)
return HttpResponse("login success!")
At the line 'print(u.lists)', I get the error "" needs to have a value for field "ownerentry" before this many-to-many relationship can be used.
What am I doing wrong here?
Your model structure is broken, for a start. You don't need ManyToManyFields on both sides of the relationship, only one - Django will provide the accessor for the reverse relationship.
Your issue is happening because you are not querying an existing instance from the database, you are instantiating an unsaved one. To query, you use model.objects.get():
u = OwnerEntry.objects.get(name=request.user.username)
You need to provide the actual class to the ManyToManyField constructor, not a string.
https://docs.djangoproject.com/en/dev/topics/db/examples/many_to_many/