Should I sacrifice performance over readability - django

I'm developing a django rest service. Me and my colleague are currently in an argument about django models. We have a model named Report which contains field/fields about location (longitude, latitude, address, city, postal code).
Does it make sense that I want to make location a separate model? Other models may also use this location model. Here is what I mean:
class Location(models.Model):
address = models.CharField(max_length=200)
city = models.CharField(max_length=100)
postal_code = models.CharField(max_length=10)
latitude = models.FloatField()
longitude = models.FloatField()
class Report(models.Model):
user = models.ForeignKey(User)
description = models.CharField(max_length=500)
datetime = models.DateTimeField(auto_now_add=True)
location = models.OneToOneField(Location)
I know that for every query on report there has to be another query on location, but I think it's worth it, because it looks much more clean to me and other models can also use this Location model, without copying fields.

I think you answered your question yourself! If you want to reuse the Location model it is more then ok to put it in a separate model!

Related

Where and how put my business logic in django

A friend recommended that I read the book two scoops Django and I was amazed at the recommendations he makes for a robust and well-designed Django project. This reading created a doubt in me and it is where I put the business logic, I give an example. Suppose I have two models:
models.py
class Sparks(models.Model):
flavor = models.CharField(max_length=100)
quantity = models.IntegerField(default=0)
class Frozen(models.Model):
flavor = models.CharField(max_length=100)
has_cone = models.BooleanField()
quantity_sparks = models.IntegerField(default=0)
Let's suppose that every time I add a frozen, if it has sparks, I have to subtract it from the Sparks model and check that there is an available quantity. In the book they recommend putting this logic in models.py or forms.py. If create some model required modify data from another model where should I do it?
Your data model is lacking, that's the likely source of uneasiness.
class Flavor(models.Model):
name = models.CharField(max_length=100)
class Sparks(model.Model):
flavor = models.ForeignKeyField(Flavor, on_delete=models.CASCADE)
quantity = models.IntegerField(default=0)
class Frozen(model.Model):
# This maybe should be a OneToOne, can't tell from your description.
sparks = models.ForeignKeyField(Sparks)
has_cone = models.BooleanField()
Then you'd do
frozen_instance = Frozen.objects.get()
frozen.sparks.quantity # This has replaced frozen_instance.quantity_sparks

How to create classes in Django model

Since Django is mapping each model to a table. I am not able to create packages in my code. Where I can wrap sections of the class to make it more logical and increase the coupling.
For example
class Employee(models.Model):
#personal information
first_name = models.CharField(max_length=20)
middle_initial = models.CharField(max_length=1)
last_name = models.CharField(max_length=20)
dob = models.DateField()
#job contract information
full_time = models.BooleanField()
hours_per_day = models.PositiveSmallIntegerField()
#.. and more
What I am trying to do is this
employee.job.is_full_time
employee.job.get_hours_per_day
# and more
However this means that I have to create a new model and connect it with the employee model using OneToOneField. I don't want to do that .. joins in the database are expensive. Is there anyway to create something like this ?
class Employee(models.Model):
class PersonalInformation:
first_name = models.CharField(max_length=20)
middle_initial = models.CharField(max_length=1)
last_name = models.CharField(max_length=20)
dob = models.DateField()
class Job:
full_time = models.BooleanField()
hours_per_day = models.PositiveSmallIntegerField()
#.. and more
The main key to the answer is to create a model that contain multiple classes which are going to be mapped to one table in the database.
There is no way to do that with just Django. Django models represent flat, relational databases. Extending the model framework to provide functionality beyond what its backend is capable of is unnecessary, and therefore not implemented in the default framework.
There are third-party packages that provide what you want, but as far as I know these packages use database backends that are capable of using such data structures.
Personally I would go with your first example, a flat, single model that represents all my Employee data. Prevent any disambiguity in your field names, and there will be no cost for using a flat model over a nested model.
And remember: premature optimization is a lot more expensive than an join statement.

Django - Best way to merge two identical apps

I recently came onto a project in which we have two applications that are virtually identical. We are using Django 1.4 and Postgresql 8.4. Both models have the following:
class Author(models.Model):
person = models.ForeignKey(Person)
book = models.ForeignKey(Book)
order = models.PositiveIntegerField(blank=True,null=True)
institute = models.ForeignKey(Institution,blank=True, null=True)
rank = models.ForeignKey(Rank,blank=True, null=True)
class Institution(models.Model):
name = models.CharField(max_length=200)
parent_institution = models.ForeignKey('self', blank=True, null=True)
location = models.ForeignKey(Location, blank=False, null=False)
type = models.ForeignKey(InstitutionType, blank=False, null=False)
class Person(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
middle_name = models.CharField(max_length=50,blank=True,null=True)
gender = models.CharField(max_length=1,choices=GENDER_TYPE,blank=True,null=True)
class InstitutionType(models.Model):
type = models.CharField(max_length=255)
Is there a way to easily merge the two, either through SQL or through Django? I'm not quite sure what the best approach would be. My only issue is that there is a lot of foreign key references. Is there a good way in which you could change the primary keys of one application's table to be higher than the other application (essentially reassign primary keys in the second table starting where the first table ends) and have them trickle down and then eventually merge the two tables? Any sort of feedback would be much appreciated.
If what Alexander is suggesting to you is not to your linking, you can use django multi-db support to:
Keep both apps running on the same database and models
Use a migration/sync script while you slowly decouple both models so that only one is being used
Write tests :)
Probably the most difficult thing in merging are models.
If you use Django you should use South too. If you don't - try it.
Take first application as a base. Add fields from second application and create schemamigration.
Then move your data with datamigration from second application.
Merge your code from the second app.

Pre-Populating Model-Formsets With Multiple Model Instances

I am building a football predictions app whilst learning django and have the following models:
class Team(models.Model):
Name = models.CharField(max_length=30)
class Fixture(models.Model):
HomeTeam = models.ForeignKey(Team, related_name='HomeTeamRef')
AwayTeam = models.ForeignKey(Team, related_name='AwayTeamRef')
HomeTeamScore = models.IntegerField(null=True, blank=True)
AwayTeamScore = models.IntegerField(null=True, blank=True)
Date = models.DateField()
class Player(models.Model):
User = models.ForeignKey(User)
DefaultHomeScore = models.IntegerField()
DefaultAwayScore = models.IntegerField()
class Prediction(models.Model):
Fixture = models.ForeignKey(Fixture)
HomeTeamScore = models.IntegerField()
AwayTeamScore = models.IntegerField()
Date = models.DateTimeField()
Player = models.ForeignKey(Player)
I have many fixture objects populated and have been using model formsets based on the Prediction model to render a view which allows the user to enter scores.
The problem is that they must choose which fixture the prediction relates to. I would like to pre-populate this so they get a list of fixtures and just enter the hometeamscore and awayteamscore. This involves pre-poulating the Prediction.Fixture field and Prediction.Player field but I am unsure on how to go about this?
Any help is much appreciated.
Edit: The problems seems to be how to pass multiple instances of Fixture into a Prediction model formset, I have seen examples of passing one but would like to do this all in one go.
I also would like the user to be able to make one Prediction per Fixture.
I think this is what you are looking for:
https://docs.djangoproject.com/en/1.7/topics/forms/formsets/#using-initial-data-with-a-formset
Your code would look something like this:
initial_data = []
for fixture in fixtures:
initial_data.append({'Player':player,'Fixture':fixture})
formset = MyPredictionFormset(initial=initial_data)
P.S. Not to be pedantic, but your field names are not PEP 8 compliant. They should be lowercase with underscores, but it's your call. (http://www.python.org/dev/peps/pep-0008/)

Django: pull list of records by state using zip code

I have a Django app that has a series of zip code tagged posts. I'd like to create a page that shows all posts by state but am not sure how to go about it. I do have a ZipCode table, but my Post.zipcode field is not related to it (mostly because it is user entered, and allows zips that are not in the DB or from outside the US).
My relevant models:
class Post(models.Model):
body = models.TextField()
zipcode = models.CharField(max_length=5)
class ZipCode(models.Model):
zipcode = models.CharField(max_length=5)
city = models.CharField(max_length=64)
statecode = models.CharField(max_length=2)
statename = models.CharField(max_length=32)
latitude = models.FloatField()
longitude = models.FloatField()
In my Django view I'd love to take the "state" parameter that is passed in from my url pattern and do something like this:
def posts_by_state(request, state):
posts = Post.objects.filter(zipcode__statecode=state)
...
Unfortunately, my Post.zipcode field is not a foreign key to ZipCode so I get this error if I try:
FieldError at /post/state/VT/
Join on field 'zipcode' not permitted.
Anyone have a hint as to how I should construct a queryset that pulls all posts together for a requested state? Thank you in advance.
I'd suggest updating Post.zipcode to be a ForeignKey to ZipCode. If you can't you could do the lookup like this:
zipcodes = [zip_code.zipcode for zip_code in ZipCode.objects.filter(statecode=state)]
posts = Post.objects.filter(zipcode__in=zipcodes)
On a side note, ZipCode doesn't seem like the right name for that model. Perhaps Location would be better.
Fairly easy solution in the end. What I did was add a new foreign key field to Post called location so Post now looks like this:
class Post(models.Model):
body = models.TextField()
zipcode = models.CharField(max_length=5)
location = models.ForeignKey(ZipCode, null=True, blank=True, default=None)
When I create new Posts, I check to see if the inputted zip string matches a record in the ZipCode database, and if it does I create the location FK. This then allows me to do this in my view:
def posts_by_state(request, state):
posts = Post.objects.filter(location__statecode=state)
...
Thank you Seth and sdolan for your help!