Django - How to link to a legacy database via intermediary? - mysql

I have to integrate a legacy design with my Django project and I am looking for some advice on using an intermediary. The existing design works but now I need to filter the Project by a third table.
In english - I have a Organization (Django) and which points to many Projects (Legacy). But all of the Project don't refer to that Organization. I have a third table ProjectMap which was build via a Trigger to address that. It corresponds the Organization.name to a project.
How do I glue this together in order allow me to do this.
projects = Organization.objects.get(pk=1).projects.all()
And it won't get ALL of the projects just the ones which match in the third table. Here is what I have so far..
By the way if anyone has a better strategy I'm all ears
class Organization(models.Model):
name = models.CharField(max_length=32)
projects = models.ManyToManyField(Project)
class Project(models.Model):
"""This is the project info page..
Note: 'id' does exist and is the pk.
"""
result_number = models.IntegerField(null=True, db_column='LBLDGRUNNO', blank=True)
building_number = models.IntegerField(db_column='LBLDGNO')
name = models.CharField(max_length=150, db_column='SPIBLGNAME', blank=True)
class Meta:
db_table = u'PROJINFO'
managed = False
class ProjectMap(models.Model):
projinfo_table_id = models.IntegerField(null=True) # 'id' of Project
name = models.CharField(max_length=128, null=True) # 'name' in Organization
Thanks so much!

Not sure if this is what your asking, but you can use the through call on the ManyToManyField to define an intermediate table:
class Organization(models.Model):
name = models.CharField(max_length=32)
projects = models.ManyToManyField(Project, through="ProjectOrganisation")
class Project(models.Model):
#Stuff Here
class ProjectOrganisation(models.Model):
project = models.ForeignKey(Project)
organization = models.ForeignKey(Organization)
#Other Fields Here
Django does this automatically with manytomany fields anyway, just if you want to add extra fields, this is the way to do it.

Related

Unable to change the value of foreign key to foreign key of an object Django

I am having a model structure like:
class user(models.Model):
name = models.CharField(max_length=100)
tasks = models.IntegerField(default=0)
class project(models.Model):
worker = models.ForeignKey(user, on_delete=models.CASCADE)
project_name = models.CharField(max_length=100)
class task(models.Model):
project = models.ForeignKey(project, on_delete=models.CASCADE)
task_name = models.CharField(max_length=150)
expected_date = models.DateField(auto_now=False,auto_now_add=False,)
actual_date = models.DateField(auto_now=False,auto_now_add=False,blank=True,null=True,)
I want to traverse through the task list and if actual date field is not null i.e. task completed then to update the tasks field in user class by 1. I have written the following code:
a = task.objects.filter(actual_date__isnull=False)
for x in a:
x.project.worker.tasks+=1
However this is not giving the desired result. What should I do?
You are not saving your object after modifying it - simply modifying the value doesn't write it to the database. Try this instead:
a = task.objects.filter(actual_date__isnull=False)
for x in a:
worker = x.project.worker
worker.tasks += 1
worker.save()
On a separate note you should consider following PEP8 conventions and using CamelCase for your class names. As it is currently you can very easily mix up classes with objects.

Django Query values_list getting last value

Lets say I have a blog and a class user in a model. Furthermore I have a class comment connected with a foreign key.
class User(models.Model):
UserName = models.CharField(max_length=50, blank=True)
UserCountry = models.CharField(max_length=2, blank=True)
class Comment(models.Model):
commentText = models.TextField(max_length=1000)
commentSub = models.ForeignKey(User, related_name='comLink')
created_at = models.DateTimeField(auto_now_add=True)
Now I want to make an csv export in model admin and a I have a queryset with values_list.
I am wondering whether there exists a possibility to get each User once and e.g. only the last comment?
myList = queryset.values_list('UserName', 'UserCountry', 'comLink__commentText')
comLink is the related name. Now I just want the last comment. A timestamp is existing and I have not figured out how to filter or reverse etc.
You can do it with Subquery, I don`t know your model design, so it would be approximately like that:
from django.db.models import OuterRef, Subquery
com = Comment.objects.filter(commentSub=OuterRef('pk')).order_by('-created_at')
myList = queryset.annotate(LastComment=Subquery(com.values('commentText')[:1]))
myList = myList.values_list('UserName', 'UserCountry', 'LastComment')
https://docs.djangoproject.com/en/2.0/ref/models/expressions/#subquery-expressions

Django showing error while saving data into a model: django.db.utils.IntegrityError: (1048, "Column 'id' cannot be null")

I am writing a script which can pull data from different API's and store into a MySQL database. This application will run from command line. So I am only using Django's ORM.
But when I am creating a model which doesn't have primary key but have a column named id. When I am trying to save data in this model I am getting a error django.db.utils.IntegrityError: (1048, "Column 'id' cannot be null")
I am really confused why this happens. Because from API I get values from id column and there is no chance to get null or empty value for this column.
Please suggest me what I am doing wrong here.
Here is my model:
class Graphite(models.Model):
class Meta:
db_table = 'graphite'
id = models.BigIntegerField()
full_name = models.CharField(max_length=250, null=True)
email = models.CharField(max_length=250, null=True)
status = models.CharField(max_length=150, null=True)
And this is the code when I am trying to save data in this model:
Graphite.objects.using('database_name').create(
id=row['id'],
full_name=row['full_name'],
email=row['email'],
status=row['status'])
When saving data into model I am using Graphite.objects.using('database_name'). because I have multiple database connected in this application.
Well I'm not sure did you use django migrations, but it won't let you create this kind of model in django, where your id property (in model) hasn't primary key as its parameter (mySQL). So why don't you just define:
class Graphite(models.Model):
class Meta:
db_table = 'graphite'
id = models.BigIntegerField(primary_key=True)
full_name = models.CharField(max_length=250, null=True)
email = models.CharField(max_length=250, null=True)
status = models.CharField(max_length=150, null=True)
so set primary_key on id? Then you wouldn't have to pass id when creating Graphite.
BUT
If you have to provide id which is something you need to have in every Graphite model and it's something different than primary key, then just define it different, let's say row_id. But you should still have at last one id property in your model with primary_key set to True when you want to have id as BigIntegerField.
EDIT (on the example)
In mySQL execute this command:
ALTER TABLE graphite ADD COLUMN row_id BIGINT;
Then your model should looks like this:
class Graphite(models.Model):
class Meta:
db_table = 'graphite'
row_id = models.BigIntegerField()
full_name = models.CharField(max_length=250, null=True)
email = models.CharField(max_length=250, null=True)
status = models.CharField(max_length=150, null=True)
And usage:
Graphite.objects.using('database_name').create(
row_id=row['id'],
full_name=row['full_name'],
email=row['email'],
status=row['status'])
and that's it.
The problem is that you do not have a primary key.
From the docs:
Each model requires exactly one field to have primary_key=True (either explicitly declared or automatically added).
So, you have to make your id field a primary key by adding primary_key=True. Then, it won't complain.
You are overriding id from default django table id.
so there is no id for primary key. Just make it primary=True. or use another id like graphaite_id
You are missing your primary key, make sure you have your primary=True and to store your id make another column for it

Django Model: What is a efficient way to list Foreign Key?

I have three models below. I omit some irrelative fields.
class Team(models.Model):
name = models.CharField(max_length=100)
class Player(models.Model):
name = models.CharField(max_length=100)
class Match(models.Model):
home = models.ForeignKey(Team)
away = models.ForeignKey(Team)
home_players = models.CharField(max_length=100, null=True)
away_players = models.CharField(max_length=100, null=True)
home_players and away_players have the type of player id list, such as [1,2,3,...,15].
I want to know better ways like using Foreign Key List.
Because, I have some troubles in manually inserting players IDs at Django Admin Page. It takes much time finding player name in Player() and matching player's ID. I guess the task would be easier if I can assign a certain relationship between Player() and Team().
That would be a many-to-many relationship.
https://docs.djangoproject.com/en/1.9/topics/db/examples/many_to_many/
class Match(models.Model):
home = models.ForeignKey(Team)
away = models.ForeignKey(Team)
home_players = models.ManyToManyField(Player)
away_players = models.ManyToManyField(Player)

Frequent update one filed of django model

Imagine, I have News models with many text fields
class News(models.Model):
title = models.CharField(max_length=255)
subtitle = models.CharField(max_length=255, blank=True)
lead = models.TextField(max_length=4096)
content = models.TextField()
...
last_visited = models.DateTimeField()
Every time my News object outputs, I update last_visited field:
news.last_visited = datetime.datetime.now()
news.save()
This code makes Django override all model fields:
UPDATE news SET title='...', subtitle='...', last_visited = '...' WHERE id = '...';
Instead of just one:
UPDATE news SET last_visited = '...' WHERE id = '...';
I worried how bad it is and is it worth of thinking about.
Django documentation offers queryset update but it looks not very elegant:
def upd(obj, **kwargs):
obj.__class__._default_manager.filter(pk=obj.pk).update(**kwargs)
upd(news, last_visited=datetime.datetime.now())
I use mysql backend.
Using update but with a cleaner approach:
class News(models.Model):
def update_visited(self):
News.objects.filter(pk=self.pk).update(
last_visited=datetime.datetime.now())
I think using queryset update is good. It removes the possibility that you overwrite changes to other fields by accident.
I know you're worried that it looks inelegant, but you only have to use it once in your upd function, then use upd in your views.
Supposing you want to use this on more than one model (guessing this because you pass obj to your upd function) it would probably make sense to have some base class that implements the last_visited field and your News class inherits from this class... Then you could do the update just on your base class.... Another possibilty would be putting the last_visited information into a seperate model and referencing the News model either through a ForeignKey or a GenericForeignKey (in the case you want to keep a 'history' for different models).