Django Model become huge - django

In my project few models has many fields like more than 25. Like i have a model name PeriodOfStay. and it fields are like
date_of_entry
i94_number
port_of_entry
city ....etc (please check the image for all field)
also it has many boolean fields . in one form user can multiple options.
most of the fields are optional.
so i am confused should i put all the fields in one model. Is it best practice. I don't want split one model to more and use OneToOne Relation cause in that case i need to break up many models cause most of the models in my project are like this also i need to send all data at once in a single request.
I just need to save data and show data to user. in some case i need to search by some field . Like in this form i need to search by i94_number.
Is using JsonField is ok for this problem cause i need to search & filter in some case.
I appreciate any help. Advance Thanks For Help.

Regarding your question about when to use one-to-one relations:
https://dba.stackexchange.com/a/15405
I think a JsonField is not what you want if you want to search & filter based on some fields. Keeping it in normal fields will make it faster
Some related resource that might be interesting: https://en.wikipedia.org/wiki/Database_normalization

Related

Using a Textfield with JSON instead of a ForeignKey relationship?

I am working on a project where users can roll dice pools. A dice pool is, for example, a throw with 3 red dice, 2 blue and 1 green. A pool is composed of several dice rolls and modifiers.
I have 3 models connected this way:
class DicePool(models.Model):
# some relevant fields
class DiceRoll(models.Model):
pool = models.ForeignKey(DicePool, on_delete=models.CASCADE)
# plus a few more information fields with the type of die used, result, etc
class Modifier(models.Model):
pool = models.ForeignKey(DicePool, on_delete=models.CASCADE)
# plus about 4 more information fields
Now, when I load the DicePool history, I need to prefetch both the DiceRoll and Modifier.
I am now considering replacing the model Modifier with a textfield containing some JSON in DicePool. Just to reduce the number of database queries.
Is it common to use a json textfield instead of a database relationship?
Or am I thinking this wrong and it's completely normal to do additional queries to prefetch_related everytime I load my pools?
I personally find using a ForeignKey cleaner and it would let me do db-wise changes to data if needed. But my code is making too many db queries and I am trying to see where I can improve it.
FYI: I am using MySQL
Is it common to use a JSON text field instead of a database relationship?
I don't think so. Also, I don't believe it's advisable because (especially using MySQL that doesn't support things like JSONField) you'll end up with a text that you'd then need to parse somehow to a dict and then look up the things you want.
Personally (and I would assume that most people) would stick to FK relationships. Also, by doing prefetch_related or select_related you're already avoiding unnecessary queries.

Determine how many times a Django model instance has been updated

I'm trying to find a generic way to get a count of how many times an instance of a model has had any of its fields updated. In other words, in Django, how do I get a count of how many times a specific row in a table has been updated? I'm aiming to show a count of how many updates have been made.
Let's say I have:
class MyModel(models.Model):
field = models.CharField()
another_field = models.IntegerField()
...
and I have an instance of the model:
my_model = MyModel.objects.get(id=1)
Is there a way to find out how many times my_model has had any of its fields updated? Or would I need to create a field like update_count and increment it each time a field is updated? Hopefully there is some kind of mechanism available in Django so I don't have to go that route.
Hopefully this isn't too basic of a question, I'm still learning Django and have been struggling with how to figure this out on my own.
There is no generic way to get this. As mentioned by wim you can use some "versioning package" to track whole history of changes. I've personally used the same suggestion: django-reversion, but there are other alternatives.
If you need to track only some fields then you may program some simpler mechanism yourself:
create a model/field to track your information
use something like FieldTracker to track changes to specific fields
Create handler post-save signal (or just modify model's save method) to save the data
You may also use something like "table audit". I haven't tried anything like that myself but there are some packages for that too:
https://github.com/StefanKjartansson/django-postgres-audit
https://github.com/torstenrudolf/django-audit-trigger
https://github.com/kvesteri/postgresql-audit

Django .order_by() with .distinct() using postgres

I have a Read model that is related to an Article model. What I would like to do is make a queryset where articles are unique and ordered by date_added. Since I'm using postgres, I'd prefer to use the .distinct() method and specify the article field. Like so:
articles = Read.objects.order_by('article', 'date_added').distinct('article')
However this doesn't give the desired effect and orders the queryset by the order they were created. I am aware of the note about .distinct() and .order_by() in Django's documentation, but I don't see that it applies here since the side effect it mentions is there will be duplicates and I'm not seeing that.
# To actually sort by date added I end up doing this
articles = sorted(articles, key=lambda x: x.date_added, reverse=True)
This executes the entire query before I actually need it and could potentially get very slow if there are lots of records. I've already optimized using select_related().
Is there a better, more efficient, way to create a query with uniqueness of a related model and order_by date?
UPDATE
The output would ideally be a queryset of Read instances where their related article is unique in the queryset and only using the Django orm (i.e. sorting in python).
Is there a better, more efficient, way to create a query with uniqueness of a related model and order_by date?
Possibily. It's hard to say without the full picture, but my assumption is that you are using Read to track which articles have and have not been read, and probably tying this to User instance to determine if a particular user has read an article or not. If that's the case, your approach is flawed. Instead, you should do something like:
class Article(models.Model):
...
read_by = models.ManyToManyField(User, related_name='read_articles')
Then, to get a particular user's read articles, you can just do:
user_instance.read_articles.order_by('date_added')
That takes the need to use distinct out of the equation, since there will not be any duplicates now.
UPDATE
To get all articles that are read by at least one user:
Article.objects.filter(read_by__isnull=False)
Or, if you want to set a threshold for popularity, you can use annotations:
from django.db.models import Count
Article.objects.annotate(read_count=Count('read_by')).filter(read_count__gte=10)
Which would give you only articles that have been read by at least 10 users.

Filter on a list of tags

I'm trying to select all the songs in my Django database whose tag is any of those in a given list. There is a Song model, a Tag model, and a SongTag model (for the many to many relationship).
This is my attempt:
taglist = ["cool", "great"]
tags = Tag.objects.filter(name__in=taglist).values_list('id', flat=True)
song_tags = SongTag.objects.filter(tag__in=list(tags))
At this point I'm getting an error:
DatabaseError: MultiQuery does not support keys_only.
What am I getting wrong? If you can suggest a completely different approach to the problem, it would be more than welcome too!
EDIT: I should have mentioned I'm using Django on Google AppEngine with django-nonrel
You shouldn't use m2m relationship with AppEngine. NoSQL databases (and BigTable is one of them) generally don't support JOINs, and programmer is supposed to denormalize the data structure. This is a deliberate design desicion: while your database will contain redundant data, your read queries will be much simpler (no need to combine data from 3 tables), which in turn makes the design of DB server much simpler as well (of course this is made for the sake of optimization and scaling)
In your case you should probably get rid of Tag and SongTag models, and just store the tag in the Song model as a string. I of course assume that Tag model only contains id and name, if Tag in fact contains more data, you should still have Tag model. Song model in that case should contain both tag_id and tag_name. The idea, as I explained above, is to introduce redundancy for the sake of simpler queries
Please, please let the ORM build the query for you:
song_tags = SongTag.objects.filter(tag__name__in = taglist)
You should try to use only one query, so that Django also generates only one query using a join.
Something like this should work:
Song.objects.filter(tags__name__in=taglist)
You may need to change some names from this example (most likely the tags in tags__name__in), see https://docs.djangoproject.com/en/1.3/ref/models/relations/.

How to get a single widget to set 2 fields in Django?

I got a model with 2 fields: latitude and longitude. Right now they're 2 CharFields, but I want to make a custom widget to set it in admin - was thinking about displaying Google Maps, then getting the coordinates of the marker.
But can I have 1 widget (a single map) to set 2 different fields?
Define lat and long fields on your form; set them to use the HiddenInputWidget.
After the init of your form, add another field which contains your custom widget that takes two values.
In the clean method for that added field, set the values of self.cleaned_data['lat'] and self.cleaned_data['lng']
There are probably cleaner ways, but it should work
I've used overriden full_clean method for data splitting. Using clean_FIELD method is too late.
I ended up setting a custom form on my admin with an extra not required field which had a widget that controls the map and setting a maps widget of that like stevejalim. However I didn't hide the input fields since they were still left in the view and I don't mind seeing them. It would probably be cleaner to override the template for editing that model instead and putting in a map, but that seemed like to much work for something that should be simple.
One solution would be if Django allowed for complex model fields where one model field corresponds to multiple db columns but that's not yet supported (see https://code.djangoproject.com/ticket/5929)
The other would be if Django would let us use a form field that corresponds to two model fields, but there doesn't seem to be a way of accomplishing that and I can't find a ticket for it.