Django: managing permissions, groups and users during data migrations - python

Problem
During a data migration, I'm trying to create a django.contrib.auth.models.Group and some Users and then attaching said group to one of the users.
Problem I'm finding (other than the permissions still not being created, but I've already found a solution to that), is that for some reason the many-to-many manager doesn't seem to be working as it should (?).
Basically what I'm trying to do is something like:
group = Group.objects.create(name="manager")
# user creation...
user.groups.add(group)
However, I get the following error:
TypeError: Group instance expected, got <Group: manager>
Whenever I try to replicate this in the Django shell, it works without any problem. It only fails while doing migration. Any ideas?
Things I've tried and other information
I've tried both populating the m2m relation through the User related manager and the Group related manager, that is, user.groups.add(group) and group.user_set.add(user). Both give me a similar error.
Just partially related, but just so I have the permissions needed, I have this first in my migration:
for app_config in apps.get_app_configs():
app_config.models_module = True
create_permissions(app_config, verbosity=0)
app_config.models_module = None
The group is supposedly created properly. Given that I create the groups and the users in different helper functions, I actually grab the group with Group.objects.get(name="manager"), and when printing, it shows the correct information.

Turns out that the problem comes up when you use the django.contrib.auth.models.Group model directly. If instead you use apps.get_model("auth.Group"), everything works fine.

Related

how to do migrations dynamically in django?

Is there any way that we can create an create an input field dynamically in the form without doing manually work, like first create the particular field in model and then run makemigartions command and then run migrate command.
I have tried using formset but that is not what i am looking for.
refer to vtiger demo
username - admin
password - admin
when you open this link there is a option ADD CUSTOM FIELD. i want to do same with my django. Hope i am able to explain you what i wants to do. I am searching for this since 3 days and cannot able to implement that.
You DO NOT (I repeat: "you DO NOT") want to "dynamically add fields" to a model (that is, to your database schema). You want your database schema to be stable, known, and totally under version control. If you don't get why, just ask yourself how your code could use a field that it's not even aware of (and that's only one of the oh so many reasons not to do such a thing).
"Features" like the one you mention are built using a fixed schema that is used to describe a "meta schema", where each "custom field" is actually a record in a "custom_fields" table, and then you usually have yet another table to store the matching values. This doesn't come without a lot of code complexity and a huge impact on performances both at the code AND database level.
If this is a project requirement, you now at least have a first idea of how this is to be done. But if your point is just to avoid having to write code and run migrations, then well, you really want to think twice about it...

Django saying that table does not exist

I am new to Django and I am working in a project which is using a mysql DB.
They imported the DB to Django models and it seemed that it wasn't missing anything. When I did a query with Django, though, it was saying a table was missing. I checked the table name in the DB and it was matching. Pretty weird. I solved the problem anyway by using the syntax ".using('db_config').values('column1', 'column2')"
The model was the following:
class UserRoles(models.Model):
role_id = models.AutoField(primary_key=True)
class Meta:
managed = False
db_table = 'user_roles'
The command giving the error:
UserRoles.objects.filter(role_id=number)
The command without throwing the error:
r = UserRoles.objects.using('db_config').values('role_id')
q = r.filter(role_id=number)
The error was the following:
django.db.utils.OperationalError: no such table: user_roles
My question here is why did Django could not find the table before? Why did I need to use the method "values" to find the rows?? I checked and all the fields were matching.I also ran makemigrations, syncdb before
PS: Another odd thing that it was that the metatag "unique_together" didn't work as well. I had to use the method "values" to make the query work as well. I don't know if it s related somehow.
This has nothing to do with values, You're using the using method in the second query which is used to tell django which database you want to query.
Henceforth you're looking in a separate database which does have the relevant migrations applied
For anyone else who finds this when they Google it, the problem that I had that caused this same error (which was not the OP's problem, as it turns out) was that I had a router that assigned the model to different hosts for reading and writing, and the writing host was behind a firewall, so that would be another thing to check if you see that Django is saying the table does not exist when it definitely does.

How to add many to one relationship with model from external application in django

My django project uses django-helpdesk app.
This app has Ticket model.
My app got a Client model, which should have one to many relationship with ticket- so I could for example list all tickets concerning specific client.
Normally I would add models.ForeignKey(Client) to Ticket
But it's an external app and I don't want to modify it (future update problems etc.).
I wold have no problem with ManyToMany or OneToOne but don't know how to do it with ManyToOne (many tickets from external app to one Client from my app)
Even more hacky solution: You can do the following in the module level code after you Client class:
class Client(models.Model):
...
client = models.ForeignKey(Client, related_name='tickets')
client.contribute_to_class(Ticket, name='client')
I haven't fully tested it (I didn't do any actual database migrations), but the correct descriptors (ReverseSingleRelatedObjectDescriptor for Ticket and ForeignRelatedObjectsDescriptor for Client) get added to the class, and South recognizes the new fields. So far it seems to work just like a regular ForeignKey.
EDIT: Actually not even that hacky. This is exactly how Django sets up foreign keys across classes. It just reverses the process by adding the field when the reverse related class is built. It won't raise an error if any of the original fields on either model is shadowed. Just make sure you don't do that, as it could potentially break your code. Other than that, I don't think there should be any issues.
There are (at least) two ways to accomplish it:
More elegant solution: Use a TicketProfile class which has a one-to-one relation to Ticket, and put the Client foreign key into it.
Hacky solution: Use a many-to-many relation, and manually edit the automatically created table and make ticket_id unique.

Django Data Migration, using South with Inheritance

We are migrating the data in several instances of our Django project to a new schema.
The old schema had:
class Group(models.Model)
class User(models.Model)
And the new schema has:
class AccessEntity(models.Model)
class Group(AccessEntity)
class User(AccessEntity)
We are trying to use South to do a data migration for these groups and users. http://south.aeracode.org/docs/tutorial/part3.html
I've gathered that I'll need to use forward rules to specify how to migrate the Users but there are a few issues I've run up against.
The main issue is how to keep the ID of the User/Group the same if I were to create a new User object that extends the AccessEntity class.
Users & Groups are referenced to by objects they own or are assigned to them. If I change their ID that information would be lost. Is there a way of keeping the same ID for an object even though I need it to now extend from AccessEntity?
not sure if I understand your question correctly, but the way multi-table model inheritance works ist that there will be an implicit one-to-one field in the parent and child models. So both User and Group would use an ID field of AccessEntity if AccessEntity has such a field.
If you create AccessEntity such that it has a field ID you can assign to it when you write a forward (data)-migration. That way you can make sure that the AccessEntity gets the right ID.
If have written a longer multi-table inheritance tutorial and it looks like you are trying to do something similar.
And furthermore the answer to this question could also be helpful (note that some things in the original answer does will not work in new versions of django / south, see my tutorial / the answer at the bottom for changes).
What might be a problem in your case is that if you already have data in both User and Groups and the id field is auto-generated, IDs likely not be distinct, e.g. you are likely going to have both a User and a Group with ID==1. This could be a problem if you want to query based on those IDs and of course ID could not be a primary key for AccessEntity then.

Design ideas for a webapp in Django

I'm working on a user based, social networking type of web application in Django. It's my first one so I would like to make sure I'm using some good practices.
Currently the web app supports two kinds of users. This is represented by two different Groups. When I register a user I assign them to one of these two groups. I also have two apps, one for each type of user. The apps handle whatever things are distinct to a particular type of user. I have another app that handles the actual authentication. This app uses Django's built in User type and assigns them a UserProfile. The two different types of users have their own profiles which extend/inherit from UserProfile.
This works reasonably well, and is fairly reusable since the authentication app can pull the user type from the url and figure out which type of user to create. Since the groups are named conveniently, they can be added to the correct group too.
Is this the best way or are there more preferred, tried and true ways to handle this? It seems like a pretty common enough scenario. I don't want to continue incorrectly reinventing the wheel if I don't have to.
I was thinking of adding another app called, common, or something which would handle things that are common to all users. For example, viewing a users profile page might be something anyone who is logged in might want to do, regardless of what type of user they are.
Thanks!
Easy part first, with 2) you're spot on. That would be the simplest and most effective way of doing that. It makes sense instead of replicating functionality across both applications to have one app that handles things that are common to both user types.
Back to 1)
With both profiles extending from UserProfile, you'd run into the issue of (if you were using get_profile() on a User object - see http://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users) that you'd get back just a UserProfile object, not knowing which group the user actually belongs to based on the object received. This is because they both extend UserProfile but UserProfile would not be able to be (I believe) abstract, because you want every User to have a pointer to a UserProfile object which may actually be a UserGroup1 or a UserGroup2 object.
What I would suggest you do is make two seperate Models, that do not extend from the same Model (out of necessity): Group1 and Group2. You would store the information that is common to both profiles in the UserProfile of the User object. Then in the UserProfile you would have a ForeignKey to both a Group1 and a Group2 object:
group1 = models.ForeignKey(Group1, blank=True, null=True)
You would have to do the logic checking yourself, to ensure that only one is ever valid (you could just do this in an overridden save() method or something), but then to grab all of a user's data at once, and also know which group they are on you could do the following:
User.objects.filter(username='blahblah').select_related('profile', 'profile__group1', 'profile__group2')
Only one query to the database would give you all the information you'd need about a user, and you'd also know which group they are in (the one that isn't 'None').
I hope that helps.
P.S. I am assuming in this that groups don't just have unique data to each other, but also unique functionality.

Categories