Django user customization database tables - python

I am trying to build a Django website where the user is able to create custom objects known as items. Each item needs to be able to have certain properties that are stored in the database. For example an item would need properties such as
Serial Number,
Description,
Manufacture Date
However I want the user to be able to specify these fields similar to what Microsoft dynamics allows . For example a user should be able to specify they want a text field with the name Model Number, associated with a specific item type and from then on they can store those properties in the database.
I am not sure the best approach to do this because a standard database model, you already have all the fields defined for a specific table, however this essentially means i have to find a way to have user defined tables.
Does anyone know a good approach to handle this problem, at the end of the day I want to store items with custom properties as defined by the user in a database.
thanks

There are multiple ways you can go.
In non-relational databases you don't need to define all the fields for a collections ( analogous to a table of RDBMS).
But if you want to use SQL with Django, then you can define a Property Model.
class Property(models.Model):
name = CharField()
value = CharField()
item = models.ForeignKey(Item, on_delete=models.CASCADE)
class Item(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
You can render a FormSet of Property form. To add extra empty forms on the fly, render dynamic formsets.

Related

How to add a conditional field in a Django model?

Basically, what I want is a field to be available if a condition is met, so something like this:
class ConditionalModel(models.Model):
product = models.ForeignKey(product, on_delete=models.CASCADE)
if category == "laptop":
cpu_model = models.CharField(max_length=200)
so if I were to go to the Django admin page and create an instance of the model and then choose "laptop" as the product from the drop-down list of existing "products", a new field would be available. I couldn't find anything about this in the documentation, so I'm wondering whether it's even possible.
What you are asking for is not "technically" possible. A model relates a database object, and under traditional SQL rules, this isn't possible. You could instead make that field optional, and then customize the admin page's functionality.
Another potential option, though I do not have much experience with it, would be to use a NoSQL database in the case where you don't want to store NULL values in your db.
I do not think it is possible because models defines databases tables so the column has to be present.
You can use the keyword blank=True to allow an object without this field.
Maybe you can customize the admin interface to hide the field in some cases.
You can't do that in models.
You can hide it in admin panel or you can make separate model for laptop.
Or you can make field blank=True
Making a field optional is not possible but you can use a generalized model called Product and two or more specialized ones called for example : ElectronicProduct that contains the field cpu_model and NonElectronicProduct, the two specialized models have to contain a OneToOneField to the Product model to ensure inheritance.

how to store a dictionary in django model as a field?

I'm trying to build up a social network and want my users to have 3 privacy options [privtae, public, friends_except],
private and public are boolean fields and friends_except is a list of users
if it's not possible to store a dict in a model as a field then what do I do to implement want I want to.
Firstly, if you're using a relational database, you can either create a new model containing all those attributes, and link them as foreign key with main model, or denormalize it to store all the fiels separately in the base model iteself. If you're using a nosql system like MongoDB, then you can certainly store it as a dictionary or JSON field.
Secondly, since at a time user can have only one privacy option selected, why to have a separate model or even a dictionary type construct. Just store it as a CharField with choices specified.
PRIVACY_CHOICES = [('public', 'public'), ('private', 'private', ('custom', 'custom')]
privacy_choice = models.CharField(max_length=256, choices=PRIVACY_CHOICES)
friends_allowed = models.ManyToManyField('User', blank=True)
look, instead of your approach what I would recommend you is to create a model let's say Friends_except with 1 field as a Foreign key to your user model. you'll be able to send all of the users you wanna block to your blocked user table
(that's kinda what happens on facebook)
then in the view, you can easily make a simple query
if:
user.is_authentictaed and is not in users.friends_except.objects.all()
" display your post" else Nah.

Django set privacy options per model field

I have gone through the question, best way to implement privacy on each field in model django and Its answers doesn't seem solve my problem so I am asking some what related question here,
well, I have a User model. I want the user to make possible to control the privacy of each and every field of their profile (may be gender, education, interests etc . ..).
The privacy options must not to be limited to just private or public, but as descriptive as
public
friends
only me
friend List 1 (User.friendlist.one)
friend List 2 (User.friendlist.two)
friend List 3 (User.friendlist.three)
another infinte lists that user may create.
I also don't want these privacy options to be saved on another model, but the same so that with one query I could get the user object along with the privacy options.
so If I have the UserModel,
class User(models.Model):
name = models.CharField()
email = models.EmailField()
phone = models.CharField()
How do I setup a privacy setting here? I am using postgres, can I map a JSON field or Hstore even an ArrayField?
what is the best solution that people used to do with Django with same problem?
update:
I have n model fields. What I really want is to store the privacy settings of each instance on itself or some other convenient way.
I have worked on my issue, tried solutions with permissions and other relations. I have a Relationship Model and all other relationship lists are derived from the Relationship model, so I don't want to maintain a separate list of Relationships.
So my pick was to go with a Postgres JSONField or HStoreField. Since Django has good support for postgres freatures, I found these points pro for the choice I made.
JSON/HashStore can be queried with Django ORM.
The configurations are plain JSON/HashStore which are easy to edit and maintain than permissions and relations.
I found database query time taken are larger with permissions than with JSON/HStore. (hits are higher with permissions)
Adding and validating permissions per field are complex than adding/validating JSON.
At some point in future if comes a more simple or hassle free solution, I can migrate to it having whole configuration at a single field.
So My choice was to go with a configuration model.
class UserConfiguration(models.Model):
user = # link to the user model
configuration = #either an HStore of JSONFeild
Then wrote a validator to make sure configuration data model is not messed up while saving and updating. I grouped up the fields to minimize the validation fields. Then wrote a simple parser that takes the users and finds the relationship between them, then maps with the configuration to return the allowed field data (logged at 2-4ms in an unoptimized implementation, which is enough for now). (With permission's I would need a separate list of friends to be maintained and should update all the group permissions on updation of privacy configuration, then I still have to validate the permissions and process it, which may take lesser time than this, but for the cost of complex system).
I think this method is scalable as well, as most of the processing is done in Python and database calls are cut down to the least as possible.
Update
I have skinned down database queries further. In the previous implementation the relations between users where iterated, which timed around 1-2ms, changing this implementation to .value_list('relations', flat=True) cut down the query time to 400-520µs.
I also don't want these privacy options to be saved on another model, but the same so that with one query I could get the user object along with the privacy options.
I would advice you to decouple the privacy objects from the UserModel, to not mess your users data together with those options. To minimize the amount of database queries, use djangos select_related and prefetch_related.
The requirements you have defined IMO lead to a set of privacy related objects, which are bound to the UserModel. django.contrib.auth is a good point to start with in this case. It is build to be extendable. Read the docs on that topic.
If you expect a large amount of users and therefore also an even larger amount of groups you might want to consider writing the permissions resolved for one user in a redis based session to be able to fetch them quickly on each page load.
UPDATE:
I thought a little more about your requirements and came to the conclusion that you need per object permission as implemented in django-guardian. You should start reading their samples and code first. They build that on top of django.contrib.auth but without depending on it, which makes it also usable with custom implementations that follow the interfaces in django.contrib.auth.
What about something like this?
class EditorList(models.Model):
name = models.CharField(...)
user = models.ForeignKey(User)
editor = models.ManyToManyField(User)
class UserPermission(models.Model):
user = models.ForeignKey(User)
name = models.BooleanField(default=False)
email = models.BooleanField(default=False)
phone = models.BooleanField(default=False)
...
editor = models.ManyToManyField(User)
editor_list = models.ManyToManyField(EditorList)
If a user wants to give 'email' permissions to public, then she creates a UserPermission with editor=None and editor_list=None and email=True.
If she wants to allow user 'rivadiz' to edit her email, then she creates a UserPermission with editor='rivadiz' and email=True.
If she wants to create a list of friends that can edit her phone, then she creates and populates an EditorList called 'my_friends', then creates a UserPermission with editor_list='my_friends' and phone=True
You should then be able to query all the users that have permission to edit any field on any user.
You could define some properties in the User model for easily checking which fields are editable, given a User and an editor.
You would first need to get all the EditorLists an editor belonged to, then do something like
perms = UserPermissions.objects.filter(user=self).filter(Q(editor=editor) | Q(editor_list=editor_list))
First of all, in my opinion you should go for multiple models and for making the queries faster, as already mentioned in other answers, you can use caching or select_related or prefetch_related as per your usecase.
So here is my proposed solution:
User model
class User(models.Model):
name = models.CharField()
email = models.EmailField()
phone = models.CharField()
...
public_allowed_read_fields = ArrayField(models.IntegerField())
friends_allowed_read_fields = ArrayField(models.IntegerField())
me_allowed_read_fields = ArrayField(models.IntegerField())
friends = models.ManyToManyField(User)
part_of = models.ManyToManyField(Group, through=GroupPrivacy)
Group(friends list) model
class Group(models.Model):
name = models.CharField()
Through model
class GroupPrivacy(models.Model):
user = models.ForeignKey(User)
group = models.ForeignKey(Group)
allowed_read_fields = ArrayField(models.IntegerField())
User Model fields mapping to integers
USER_FIELDS_MAPPING = (
(1, User._meta.get_field('name')),
(2, User._meta.get_field('email')),
(3, User._meta.get_field('phone')),
...
)
HOW DOES THIS HELPS??
for each of public, friends and me, you can have a field in the User model itself as already mentioned above i.e. public_allowed_read_fields, friends_allowed_read_fields and me_allowed_read_fields respectively. Each of this field will contain a list of integers mapped to the ones inside USER_FIELDS_MAPPING(explained in detail below)
for friend_list_1, you will have group named friend_list_1. Now the point is the user wants to show or hide a specific set of fields to this friends list. That's where the through model, GroupPrivacy comes into the play. Using this through model you define a M2M relation between a user and a group with some additional properties which are unique to this relation. In this GroupPrivacy model you can see allowed_read_fields field, it is used to store an array of integers corresponding to the ones in the USER_FIELDS_MAPPING. So lets say, for group friend_list_1 and user A, the allowed_read_fields = [1,2]. Now, if you map this to USER_FIELDS_MAPPING, you will know that user A wants to show only name and email to the friends in this list. Similarly different users in friend_list_1 group will have different values in allowed_read_fields for their corresponding GroupPrivacy model instance.
This will be similar for multiple groups.
This will be much more cumbersome without a separate permissions model. The fact that you can associate a given field of an individual user's profile with more than one friend list implies a Many to Many table, and you're better off just letting Django handle that for you.
I'm thinking something more like:
class Visibility(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
field = models.CharField(max_length=32)
public = models.BooleanField(default=False)
friends = models.BooleanField(default=False)
lists = models.ManyToManyField(FriendList)
#staticmethod
def visible_profile(request_user, profile_user):
"""Get a dictionary of profile_user's profile, as
should be visible to request_user..."""
(I'll leave the details of such a method as an exercise, but it's not
too complex.)
I'll caution that the UI involved for a user to set those permissions is likely to be a challenge because of the many-to-many connection to friend lists. Not impossible, definitely, but a little tedious.
A key advantage of the M2M table here is that it'll be self-maintaining if the user or any friend list is removed -- with one exception. The idea in this scheme is that without any Visibility records, all data is private (to allow everyone to see your name, you'd add a Visibility record with user=(yourself), field="name", and public=True. Since a Visibility record where public=False, friends=False, and lists=[] is pointless, I'd check for that situation after the user edits it and remove that record entirely.
Another valid strategy is to have two special FriendList records: one for "public", and one for "all friends". This simplifies the Visibility model quite a bit at the expense of a little more code elsewhere.

If I need a database view or not?

I have these models:
class Company(models.Model):
name=models.CharField(max_length=100)
description=models.TextField()
#some more fields
class Product(models.Model):
name=models.CharField(max_length=100)
company=models.ForeignKey(Company)
#some more fields
class Category(models.Model):
parent=models.ForeignKey('self',null=True,blank=True)
name=models.CharField(max_length=100)
products=models.ManyToManyField(Product,null=True,blank=True)
#some more fields
as U can see each company has a list of product and each product belongs to some categories,I'm going to get the list of categories of each company using company pk,what's the best practice?should I define a database view?how can I do this?
Note:I've not ever used database view in django,I searched about it and that doesn't sound easy to me!
I always try to avoid using database views, stored procedures and in general stuff that 'lives' in the database itself rather than in the application code-base for the simple reason that it is very hard to maintain (and also you say good bye to database agnostic applications).
My advice here is to stick with django orm (which can do a lot) and only if you unable to get decent performances or if you need some advanced feature available through stored procedures/views only then to go for that solution.
Using views in django is quite easy.
Say you have 1 view to query, you create the view on the db then you write the model with fields matching the view' columns (name and type).
UPDATE:
You then need to set the table name as the view name in meta class definition.
After that you need to tell django not to write on that and to not try to create a table for the view model, luckily there is a conf for that:
class ViewModel(models.Model):
... view columns ...
class Meta():
db_table = 'view_name'
managed = False
I've no idea why you think you need a db view here. Generally, you don't use them with Django, since you do all the logic in Python via the ORM.
To get the list of categories for a company, you can just do:
categories = Category.objects.filter(products__company=my_company)
where my_company is the Company instance you're interested in.

Django OneToOne Field

Now I'm working one url mapping. Let's say I have three classes, company, user, and store, and my goal is that their urls will be in the same hierarchy. Since they are the same hierarchy in urls, I have to create a class url_mapping to ensure there is no duplicate name. Let's me give a more concrete problem I have.
Class Company(models.Model):
company_name = models.CharField(max_length=30)
url_mapping = models.OneToOneField(URL_mapping)
Class User(models.Model):
user_name = models.CharField(max_length=30)
url_mapping = models.OneToOneField(URL_mapping)
Class store(models.Model):
store_name = models.CharField(max_length=30)
url_mapping = models.OneToOneField(URL_mapping)
Class URL_mapping(models.Model):
url = models.CharField(max_length=30)
Now, when a visitor access to my site with certain url, I'll match the url in URL_mapping class, and then do the reverse lookup and see which type of url between company, user, and store it is.
Since User, Store, and Company have different view function, is it possible that we can quickly re-directly to the corresponding view function quickly using reverse lookup? Or should I add another field in URL_mapping saying that which url type it is?
The example is
http://www.example.com/levis -> will handle by brand_views
http://www.example.com/david -> will handle by user_views
http://www.example.com/mancy -> will handle by store_views
In database, we will have
url_mapping
id:1, name:levis
id:2, name:david
id:3, name:mancy
user
id:1, name:david, url_mapping:2
brand
id:1, name:levis, url_mapping:1
store
id:1, name: mancy, url_mapping:3
Where url_mapping is oneToOneField.
Don't know how to quickly look up from url_mapping class now.
Thank you.
I understand your question as "I have a URL, and I want to go to the corresponding Store, company or the User".
You can do that using
URL_mapping.objects.get(url).user
URL_mapping.objects.get(url).store
URL_mapping.objects.get(url).company
Clearly 2 of these will give you an error and you wouldn't know which it maps to.
Seems to me like, for what you are really looking for here, you should really use Generic Foreign Keys
So, then you will be able to do:
URL_mapping.objects.get(url)
which will have the corresponding User, Company or the Store model.
I would use a SlugField in each model (Company, User, Store) as their identifier.
theoretically, you do not need any URL mapping tables at all, in the view that handles the requests, extract the last part of the url, which is a slug identifying a Company, or a User, or a Store, and search Company, then User, and then Store models for the given slug. Stop when you find the object.
to improve speed, you can create an auxiliary model like you did and use GenericForeignKey relation as Lakshman Prasad suggested. In this auxiliary model, again, I would use a SlugField for an identifier. And if you use that, you do not need slugs in your main models.
I personally think this is a bad design. First, I doubt that these URLs are REST-ful. Second, for this to work, the slugs in your main models have to be unique across these three models, which can be ensured by only an external mechanism, you cannot use a UNIQUE constraint here. Your URL_mapping model is simply one such mechanism. It basically stores your slugs for the three models outside the models and, if you add the UNIQUE constraint to the SlugField in URL_mapping, makes sure the slugs are unique across your main models.

Categories