I am currently struggling to find the best way to approach the following problem:
I have user registration implemented using django-registration and I want each user to be able to upload different set of documents. Each user will have an "agency", that require some extra documents, however those documents might be different.
So my User base class will have a one-to-one relation with all those base documents required for each user, however I am not sure how to let each agency define their own set of documents and how to tie it to the User.
Thanks.
Sounds to me like these are not one-to-one relations but one-to-many (specifically: one-User-to-many-Documents).
This would result in the Document containing a ForeignKey to the User.
In case one Document could be linked to many users, this may even be a many to many relationship.
In case, documents could be shared between User and Agency, either the Documents also have an optional ForeignKey to the Agency or - if no User needs to be linked to the document you might want to add a Generic Relationship "owner" to the Document that either links to a User or an Agency. See the Django documentation on Generic Relations for more detail.
However, Generic Relations are a little restricted, making it hard to use them in .filter() and .exclude() queries. Thus, I would recommend you to link to User and Agency in different attributes, if they do not have to share an attribute "owner" or "author", ...
Does each Agency only refer to one User or does an Agency "group" multiple Users? In these cases, refer to the Agency with a ForeignKey in the User model. This would mean, that you need to either inherit from the Django User Model or create a User Profile that contains your additionally defined variables. I personally prefer the second option here. See the amazing article on SimpleIsBetterThanComplex for these and other options on extending the User model, including great code examples.
If a User may also be part of multiple Agencies, you could instead use ManyToMany in the Agency and leave the User model alone. However, I would not recommend using this option if you do not intend to have multiple Agencies per user.
Update 1:
According to your comment, a User only belongs to one agency but an agency may link to multiple users. In this case, the user model should link to the Agency via ForeignKey. If an Admin User should assign Agencies, this is also easy to administrate, (at least in the Django admin), since the admin user then just has to edit the user itself (or the profile) in order to link the agency to it.
Using a post_save signal, you could check for a User that just has been saved, if the file type (type attribute (CharField with or without specific choices set) at the Document Model and Agency as well) required by the Agency is already linked to the User. If it is not, create and link it. The Document model should also contain the File-Field, so that it is easy to check, if the document has been uploaded already.
Update 2:
Just to help you with this, here is another great article from SimpleIsBetterThanComplex about Django signals.
Related
I have just started developing a bookstore site with Django and I have a question about user authentication.
I want users to have a wallet, shopping cart and additional information for their account such as profile picture, phone number, address, etc. to buy books.
And now I am faced with the dilemma of whether to change the User model itself, or create a Profiles model for each and link it to the User model, or create a separate model (in other words, the authentication system) and do everything from scratch.
Now I have started building a separate authentication system. Everything was going well until I had problems in sending and receiving user data in the template contexts.
Finally, in general, I want to know if Django authentication system is really suitable for all users of a site?
Django is one of the most battle-hardened and well tested 'batteries-included' frameworks out there, so the built-in Authentication is more than acceptable. The Docs have an overview, with a guide on how to extend.
You can make an assessment of 3rd party packages relating to authentication here, and make a judgement as to whether or not any of these packages are suited to your e-commerce use-case.
With regards to your User model, its widely considered best practice to begin your project with a custom user model (i.e. before your first migration). The official docs even state this, however some people still prefer the 'old' way of doing this, which is to create a separate 'one-to-one' profile model.
Here is a tutorial about beginning a project with a custom User model.
Here is one about changing mid-project.
If the default Django's User model does not contain everything you need, you can always extend it with your own model. Django docs have it covered with some examples here: https://docs.djangoproject.com/en/4.0/topics/auth/customizing/#extending-the-existing-user-model
By extending the User model you can add additional fields and/or functions to the User model (for example, you can add an image, description, age, relationship status, etc.).
Having said that, I really recommend using Django's authentication backend. It's well-tested and secure.
So I wanted to create 2 signup options on the website. For example a student and teacher login methods. I want the form or model to extend and save it to the sqlite3 db. For example, if a student signs up the database would store a field isteacher = False and vise versa.
Also once they login is there a way to display two different dashboards based on the user?
Is there any guide or link to show me how to build this step by step? I have spent close to 8 hours figuring this out and i'm very close to giving up. Thanks for your time.
You don't need two sign up forms for such a thing if the students and teachers use the same credentials (e.g. username/email and password). Just simply add a selector for users to identify themselves. If they are not going to use same credentials, create a base view for common fields, then create separate signup views inheriting from that base view.
You need to extend User to add extra fields such as is_teacher (though I recommend you use CharField with choices so that you can add extra types of users in the future), there is a couple of ways of doing this explained elaborately in Django documentation, in your case setting up a custom user model via AbstractUser seems the best as I predict you will be extending that model further.
You can use UserPassesTestMixin or user_passes_test decorator to conditionally alter views for different types of users.
Using Django 1.5 here. I have an application I've created that currently has one big set of data, for one "account" if you will. Meaning all the data in all the models in my application are available to all logged-in users. Now, I want to be able to allow more people to use my application but with their own set of data. So I need to separate users into different accounts with different sets of data for each account. There could potentially be one or multiple users that has access to each account. At this time I don't need different users within one account to have different levels of access though I do intend for one user to be the account "owner".
I know that to make this conversion, I of course need to add a field to every model with a foreign key to a new "account" model. But beyond that I'm a little foggy. This appears to be a square peg in the round hole of Django's auth system. So the question is, what is the best approach?
A few thoughts I had so far:
Simply filter each and every query by account
Wrap each and every view with a decorator, but with multiple models, do I have to create a different decorator for each model? Can I tell from within the decorator which model is being accessed?
Somehow make use of the Auth system's user_passes_test decorator, but again, different models.
Extend the auth system to include a request.account attribute
Create a new mixin for my views? What if I'm not using exclusively CBVs?
Different middleware?
I considered using a new group for each account and then filtering by group instead of a new account model but I predict that would be a poor fit in this situation, as it isn't using groups as they were intended.
This is less of a code question and more of a big-picture, best-practices question. How would you approach this?
What you request is not so exotic: This is called authority data - you seperate your users to authorities and each authority will have each own data. For instance, you may have a number of departments in an organization - the data of each department can be edited only by members of the same department. I have already written a blog post with a simple approach to that using django:
http://spapas.github.io/2013/11/05/django-authoritiy-data/
To recap the post, I propose just adding an Authority model for which your User will have a ForeignKey (each User will have a Profile).
Now, all your Models whose data will belong to specific Authorities will just contain a ForeignKey to Authority. To check for the permissions you could use CBVs - the django admin will only be available to the central Administrators that have access to all the data. I recommend against using the django permissions for authorization of Authority data. If you want read the post which is much more detailed and ask here any questions.
Note: I've since asked this question again given the updates to Django's user model since version 1.5.
I'm rebuilding and making improvements to an already existing Django site and moving it over from Webfaction to Heroku, and from Amazon's SimpleDB to Heroku Postgres (though testing locally on Sqllite3 when developing). A lot of what I'm doing is moving over to use built-in Django functionality, like the Django admin, user authentication, etc.
Conceptually, the site has two kinds of users: Students and Businesses. The two types of users have completely different permissions and information stored about them. This is so much the case that in the original structure of the site, we set up the data model as follows:
Users
ID (primary_key)
Business_or_Student ('B' if business, 'S' if student)
email (unique)
password (hashed, obviously)
...
Students
ID (Foreignkey on Users)
<more information>
...
Businesses
ID (Foreignkey on Users)
<more information>
...
This worked pretty well for us, and we had the bare-bones user information in the Users table, and then any more detailed information in the Students and Businesses tables. Getting a user's full profile required something along this pseudocode:
def get_user_profile(id):
if Users(id=id).Business_or_Student = 'B':
return Businesses(id=id)
else:
return Students(id=id)
In moving over, I've found that Django's built-in User object has pretty limited functionality, and I've had to extend it with a UserProfile class I've created, and then had additional Student and Business tables. Given all of the patching I'm doing with this in the Django admin, and being relatively unfamiliar with Django models since I always did it differently, I'm not sure if this is the best way to go about it, or if I should just stick all of the information for businesses and students in the UserProfile table and just differentiate the two with different groups, or if there's even some way to do this all in the built-in User object.
Since businesses and students also have different interfaces, I'm seriously considering setting up the two as different apps within my Django project, and so separating their views, models, etc. entirely. That would look something like:
MyProject/
MyProject/ (project folder, Django 1.4)
mainsite/
students/
businesses/
One of my biggest concerns is with the Django Admin. In extending User, I already had to add the following code:
class UserProfileInline(admin.StackedInline):
model = UserProfile
can_delete = False
verbose_name_plural = 'profile'
class UserAdmin(UserAdmin):
inlines = (UserProfileInline, )
However, I would like the information for the Business or Student aspects of the user to show up in the Django admin when that User is pulled up, but the ForeignKey part of the model is in the Student and Business model since every Student/Business has a User but every User has only one Student or one Business object connected with it. I'm not sure how to add a conditional Inline for the Admin.
Question: Given this structure and these concerns, what is the best way to set up this site, particularly the data model?
This is not a complete solution, but it will give you an idea of where to start.
Create a UserProfile model in mainsite. This will hold any common attributes for both types of users. Relate it to the User model with a OneToOne(...) field.
Create two more models in each app, (student/business), Business and Student, which have OneToOne relationships each with UserProfile (or inherit from UserProfile). This will hold attributes specific to that type of users. Docs: Multitable inheritance / OneToOne Relationships
You may add a field in UserProfile to distinguish whether it is a business or student's profile.
Then, for content management:
Define the save() functions to automatically check for conflicts (e.g. There is an entry for both Business and Student associated with a UserProfile, or no entries).
Define the __unicode__() representations where necessary.
I hope I understood your problem... maybe this can work? You create a abstract CommonInfo class that is inherited in into the different Sub-classes (student and businesses)
class CommonUser(models.Model):
user = models.OneToOne(User)
<any other common fields>
class Meta:
abstract = True
class Student(CommonUser):
<whatever>
class Business(CommonUser):
<whatever>
In this case the models will be created in the DB with the base class fields in each table. Thus when you are working with Students you run a
students = Students.objects.get.all()
to get all your students including the common information.
Then for each student you do:
for student in students:
print student.user.username
The same goes for Business objects.
To get the student using a user:
student = Student.objects.get(user=id)
The username will be unique thus when creating a new Student or Business it will raise an exception if an existing username is being saved.
Forgot to add the link
I will be creating an intranet site with multiple roles (client-employee, client-admin, staff team member). Each role will have a model that attaches (via One-to-One or ForeignKey field) to a user with custom fields. I want each role to have it's own set of permissions (like a group).
How can I store this permissions set inside my application. Groups seem to be defined as part of the contrib.admin app rather than in code. I couldn't find anything in documentation on how to define a group.
What is the best way to handle model level permissions. Maybe I could do a check in the model if see if the user has the right role-model.
Access control lists are tricky (some say dead), but Django comes with a good default implementation in contrib.auth equipped with:
Users
Permissions: Binary (yes/no) flags designating whether a user may perform a certain task.
Groups: A generic way of applying labels and permissions to more than one user.
A more detailed introduction can be found here:
http://parand.com/say/index.php/2010/02/19/django-using-the-permission-system/