I have a model containing items, which has many different fields. There is another model which assigns a set of this field to each user using a m2m-relation.
I want to achieve, that in the end, every user has access to a defined set of fields of the item model, and he only sees these field in views, he can only edit these field etc.
Is there any generic way to set this up?
One way to do this would be to break the Item model up into the parts that are individually assignable to a user. If you have fixed user types (admin, customer, team etc.) who can always see the same set of fields, these parts would be whole groups of fields. If it's very dynamic and you want to be able to set up individual fields for each user, each field is a part of its own.
That way, you would have a meta-Item which consists solely of an Id that the parts can refer to. This holds together the parts. Then, you would map a user not to the Item but to the parts and reconstruct the item view from the common Id of the parts.
A second approach would be to not include the filtering in the model layer. I. e., you leave the mapping on the model layer as it is and retrieve the full set of item fields for each user. Then you pass the items through a filter that implements the rules.
Which approach is better for you depends on how you want to filter. If it's fixed types of users, I would probably implement a rules-based post-processor, if it's very dynamic, I would suggest the approach from my earlier answer. Another reason to put the filtering rules in the model would be if you want to reuse the model in applications that couldn't reuse your filter engine (for example if you have applications in different languages sharing the same database).
Related
As we all know the best code style practice to is to name Django models (classes) as singular (Cat, User, Permission, etc.), instead of plural (Cats, Users, Permissions), because it represents the structure of one record of the model. But in case of user settings it become UserSetting. Setting could be interpretted as one key-value pair but we have complete user settings record with multiple key-value pairs. So it's UserSettings.
It appearently become confusing. So what should we do in that case?
UserSetting
UserSettings
UserSettingsRecord
Other ideas?
I would simply use UserSettings, because you should name your model as a single instance of it, since a single instance contains multiple settings the plural is the correct choice (UserSetting seems to contain only a single user setting). To distinguish a single instance from multiple instances, you could append the noun instance/row/record, so with UserSettingsRecord you could make it more explicit even if I don't see it necessary (the thing is obvious and with long names you only lengthen the code).
We have a django application that is, at its core, a series of webpages with Forms which our users fill out in order. (We'll call the particular series of pages with forms on them a "flow".)
We will be white-labeling this application for a Partner -- the Partner will want to add some fields and even add some webpages with their own new Forms. This may result in a new order in which the Forms are filled out. (A new "flow", in addition to changes to existing Forms/Models or new Forms/Models.)
What is the best way to extend our existing, simple Forms-and-Models structure to use different Forms and Models depending on the running instance of the app (e.g. an environment variable)? Some things we thought about:
implement something like get_user_model for every Model and Form use in the app, which would look at the current environment
implement a more generic key-value store so that we're not bound by the current implementation's field types (i.e., have the data field name be part of the data as well)
a data model which tracks this particular environment's "flow" and which models it needs to use
subclass existing Models and Forms for each new white-label implementation
Model Field injection may be what you are looking for, take a look of this article
The approach boils down to three concepts:
Dynamically adding fields to model classes Ensuring Django’s model
system respects the new fields
Getting the load ordering correct for the above to work
Mezzanine has done a beautiful job implementing this model field injection with dynamic extra models via EXTRA_MODEL_FIELDS
i am new to both python and Django, trying to create a database that hold general information about people, so i have this:
a model for a Person (contain general info).
a model for a Category that a person belongs to (a person can be in multiple categories at the same time).
each category contain its own extra data (a person who is in "Writers" category might have some books that we want to store in DB)
i thought about model sub-classing, but it seems that this will not work if a person can be in multiple categories the same time (especially dynamically)
another thought is creating profiles that have OneToOne relationship with the Person model, but i am not sure if it is the best way
what is the best/other ways to tackle this?
It sounds like you want each category to have a ForeignKey to Person.
add ManyToManyField(Category) to Person class.
Django permissions in User model are solved the same way (via Group class)
edit:
you're right, I'm sorry about my useless answer.
My solution would looks like this:
Class Person(Model):
#property
def extras(self):
extra_data = {}
for category in self.categories.all():
category_model_class = CATEGORIES_DATA_MAP[category.name]
extra_data[category.name] = category_model_class.objects.filter(user=self.pk)
return extra_data
... where CATEGORIES_DATA_MAP is dictionary with category/model relation map
The multiple 1to1 rel is the way to go.
Define an ActorProfile model, a WriterProfile model etc, with each having a fk to User. Use some orm magic to load then when necessary.
It's basic that the FK is in the profile model, otherwise you'll need to add a new column on the user table each time you need a new kind of profile.
As the profiles will be probably somewhat overlapping, I'd suggest to use composition (instead of inheritance), do more profile types which store the common data, and keep the specific profiles for very specific data.
EDIT
Use a document-based database (mongodb?) and forget about migrations, fixed schemata, artificial joins... You have to think only about structuring the data the way you really need, but the advantages are worth considering.
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.
I'm torn how to structure my code to accommodate business rules specific to instances of a particular model.
For example. Lets say I have a Contact model with a type field and choices=(('I','Individual'),('C','Company)). Based on the type of model that I have, I might want to have custom methods.
So thinking out loud, something like this would be nice:
class IndividualContact(Contact):
""" A custom class used for Contact instances with type='I' """
criteria = Q(type='I')
# The goal here is that Contact is now aware of IndividualContact and constructs
# objects accordingly.
Contact.register(IndividualContact)
Or even:
class SpecialContact(Contact):
""" A custom class used for the contact with pk=1 """
criteria = Q(pk=1)
At which point I have a nice home for my special instance specific code.
One of the alternatives I explored is using model inheritance and avoiding things like type fields that impart new behaviors. That way, new classes plug into the existing framework elegantly and you're nicely set up to add custom fields to your different types in case you need them.
In my case I have a resource crediting system on the site that allows me to say things like "You may only have 2 Listings and 20 Photos". Individual resource types are rationed, but there is a generic credit table that gives you credits for various content types. The logic that goes into counting up your Listings and Photos varies based on the type of object you're working with.
I.E.:
listing_credit = Credit.objects.create(content_type=ContentType.objects.get_for_model(Listing), user=user, credit_amt=2)
# Should subtract **active** listings from current sum total of Listing credits.
listing_credit.credits_remaining()
photo_credit = Credit.objects.create(content_type=ContentType.objects.get_for_model(Photo), user=user, credit_amt=5)
# Photos have no concept of an active status, so we just subtract all photos from the current sum total of Listing credits.
# Also, the Photo might be associated to it's user through a 'created_by' field whereas
# Listing has a user field.
photo_credit.credits_remaining()
My current approach is separate classes but I'd like to reduce that boilerplate and he necessity of creating N separate tables with only a credit_ptr_id.
Take a look at django proxy models. They allow you to do exactly what you want.
http://docs.djangoproject.com/en/dev/topics/db/models/#proxy-models
But since in you case the behavior is dependent on the field value, then you should add custom managers to the proxy models that retrieve items only of only that type on queries.