I work with the python Django Framework and try to build a website. I want to achieve a good performance for the case described below and search for a good database/model design. Since this is a database-relating question in my eyes, I wrote about columns and tables. In Django I would replace them with the respective models and fields.
I have a model with a user and a profile table. user contains the primary user data like username and email. profile contains all other profile details like name, birthdate, favorite color and so on. profile has also some dependent tables like e.g. custom_fields, where users can add custom fields to their profile.
One user has exactly one profile that he owns. Every contact can see the users profile. I need to store the profile owner with the profile.
If a user (A) views the profile of another user (B) and misses some information, A can add this information into the profile of B. That changes are not visible for anyone but the creator A. That means I need to store the editor (A) and the target (B) together with the profile.
I thought about how to design this and found three approaches:
Copy the table profile (containing only the users own profile) into edited_profile (containing all edits), add a column editor for the user who does the edit and manage both tables. That means that I also have to copy all tables that depend on profile or need a layer of junction tables between profile and the dependent tables. Also, if I ever want to improve or extend the model, I will always have to watch to keep both tables consistent. This seems to be not the best solution in my eyes.
Add columns user and editor into profile. The users own profile is identified by editor is NULL. If I need a profile for something else (e.g. a group), I need to add respective columns to the profile table to refer to it. That may include a lot of changes in the SQL queries because I may need to filter for the new columns, too.
Add a column profile_id into profile and create some junction tables:
user_profile (fk_user_id -> user_id, fk_profile_id -> profile_id) and
edited_profile (fk_user_id -> user_id, fk_editor_id -> user_id, fk_profile_id -> profile_id).
If I need a profile for something else (e.g. a group), I need to add respective junction tables.
I want to have a good database design with performant look ups. Usually I need the users own profile alone or together with the edits that another user has applied. Which one of the approaches is the best regarding lookup/update performance and maintenance? Is there another better design that I have missed?
Thank you for your help!
Related
I am using Django as back-end with graphene-django serving the front-end. I am new to both django and graphene so I am not sure what is the best approach to achieve field-level permissions with no code repetition in this set-up. For example, if my model is:
class MyModel(models.Model):
field1 = models.CharField()
field2 = models.CharField()
I want to be able to specify that user1 can read field1 but not field2; when the user1 queries GraphQL for all MyModels it would be only allow to retrieve field1 from rows (nodes) and not field2.
I did a bit of research and found 2 possible alternative solutions but I fear they may not be in the spirit of Django framework and/or conflicting with each other and there may be a better way to achieve this in Django. Ultimately I don't want to be repeating the permissions code in multiple parts of the Django and Graphene back-end so want this to be centralised at the lowest possible level, ideally at the Django model. I need to be able to control full CRUD per field depending on user_id and maybe even have some additional logic. The options I found were:
overriding get_node resolver in graphene-django DjangoObjectType to check for permissions there. Personally I see this as a very bad and last-resort solution as the checks are done only on graphql query/mutation layer and not elsewhere in Django. I could easily write a Django form or view that would not benefit from the permission check unless this is coded again in that form/view.
I could extend the Django model to perform arbitrary per-field checks and this seems the right level where to enforce permission checks but ideally I would prefer to use built-in features or a 'popular' library for this type of stuff. I tried searching for a library but I couldn't find anything that is even remotely production ready or gaining any traction - which leads me to the consider that there may be a better approach to address this problem. Django-field-permissions package seemed on the right path though.
I was wondering if anyone has a view on the best approach to solving this problem that fits Django and Graphene frameworks and without repeating the permissions code everywhere?
You're not going to find a stable/popular package for this, as it's not a design that a database can support well.
You cannot link (Foreign Key) a field and a table, you can only link two tables using a field. Therefore, any work to determine whether a row in a table has access to a field in another table, will be costly and error prone.
The best you could do, is to write a service layer that sits in between a resolver and a model that nullifies fields a user has no access to. You pass it the user (info.context.user) and a model, and it does a separate query to a field permissions model, fetches the record and nullifies each field according to permissions.
This inherently means each field needs to be nullable in order to support the permissions, complicating the frontend - it's a lot of work...
A better approach if your business logic allows it, is to group those fields into models, that can then be tied to "roles" or groups. So if this were medical data in a hospital:
- name ----- \
- address | -> Person model => all personnel, except custodial
- birth date -/
- medication -------\
- patient history | => PatientStatus model => all medically trained personnel
- current physician /
- ...
That way you use standard built-in permissions to deny access to entire tables (as illustrated above) and object level permissions (Guardian, Authority) to deny access to all but the current physician for the really classified things.
Hope this helps and good luck!
A little background. I've been developing the core code of an application in python, and now I want to implement it as a website for the user, so I've been learning Django and have come across a problem and not sure where to go with it. I also have little experience dealing with databases
Each user would be able to populate their own list, each with the same attributes. What seems to be the solution is to create a single model defining the attributes etc..., and then the user save records to this, and at the same time very frequently changing the values of the attributes of the records they have added (maybe every 5~10 seconds or so), using filters to filter down to their user ID. Each user would add on average 4000 records to this model, so say just for 1000 users, this table would have 4 million rows, 10,000 users we get 40million rows. To me this seems it would impact the speed of content delivery a lot?
To me a faster solution would be to define the model, and then for each user to have their own instance of this table of 4000ish records. From what I'm learning this would use more memory and disk-space, but I'd rather get a faster user experience as my primary end point.
Is it just my thinking because I don't have experience with databases? Or are my concerns warranted and I should find a solution as to how to be able to do the latter?
This post asked the same question I believe, but no solution on how to achieve it. How to create one Model (table) for each user on django?
I want the user's of my site to be able to upload information into a database. I know that Django doesn't really allow me to let the user's have their own dynamically created tables. So I'm wondering what is the most efficient way of handling this.
For instance if all user's want to save mailing lists containing names, emails, numbers etc Would I just put all of these into one giant table with a column for the user ID or is there a smarter way to do this?
The basic functionality would allow users to upload data from a CSV in a restricted format. i.e. email, name which would be placed into a table like this:
user | email | name
However, I'd like to further improve on this so that a user can specify their own fields. i.e. Add phone numbers, address or whatever other info they want. Perhaps also having the ability to add their own field headings under a model similar to the following.
user | field1 | field2 | field3 | field4
You don't need to create a new table for each user. You would do exactly what you said, have a single mailing list table and store each record with an associated user ID. Then, when a user wants to view their lists, you filter that table by user ID. Similarly, if a user wanted to modify a mailing list, you'd make sure that user has the same ID as the record they're trying to modify.
Django already has a very powerful user authentication and permissions system. You should use it to ensure that only logged in users can access their records.
I suggest you take some time and carefully ready the Django documentation and follow the First Steps tutorials. They'll give you a better understanding about how to set up your models and implement authentication.
I have a project that looks like a simple shopping site that sells different kinds of products. For example, I have 4 models: Brand, Product, Consignment. Consignment is linked to Product, and Product is linked to Brand. To reduce count of queries to databases, I want to save current state of these models(or at least some of them). I want to do it, because I show a sidebar with brands and products. So every time when user opens some page, it will execute the query to database to get those brands and products.
But when admin add some new product or brand, I want to handle database changing and resave it. How to implement it?
Your answer is by using Cache. Cache is a method to store your objects in memory/other app like redis temporarily so that you do not need send queries to database. You can read the full description here.
Or, you can use this third party library that helps you to cache Django ORM Model. Here are the example.
Brand.objects.filter(name='stackoverlow').cache()
After doing an update to the model, you need to clear or invalidate the cache.
invalidate_model(Brand)
This looks like it should be easy but I just can't find it.
I'm creating an application where I want to give admin site access to people from different departments. Those people will read and write the same tables, BUT they must only access rows belonging to their department! I.e. they must not see any records produced by the other departments and should be able to modify only the records from their own department. If they create a record, it should automatically "belong" to the department of the user which created it (they will create records only from the admin site).
I've found django-guardian, but it looks like an overkill - I don't really want to have arbitrary per-record permissions.
Also, the number of records will potentially be large, so any kind of front-end permission checking on a per-record basis is not suitable - it must be done by DB-side filtering. Other than that, I'm not really particular how it will be done. E.g. I'm perfectly fine with mapping departments to auth groups.