Cannot assign "'10000'": "Jobs.client_id" must be a "Clients" instance - django

I have two tables, Jobs and Clients.
class Jobs(models.Model):
client_id = models.ForeignKey(Clients,db_column='client_id',on_delete=models.CASCADE)
class Clients(models.Model):
created = models.DateTimeField()
modified = models.DateTimeField(auto_now=True)
I have Jobs data in json format.
jobs_data = {
'client_id':'10000',
....
}
When I want to save this data into Jobs table I get the ValueError: Cannot assign "'10000'": "Jobs.client_id" must be a "Clients" instance.
To save the table I have tried
jobs_obj = Jobs.objects.create(**v['Job'])
I also tried -
client_obj = Clients.objects.get(id=v['Job']['client_id'])
jobs_obj = Jobs.objects.create(**v['Job'],Clients=client_obj)
How can I fix this problem ?

Related

How to create multiple instances of a model with factoryboy in django?

How do I create multiple instances of this Resource? When I try to do it, I get the same instance created. I do tend to end up with it creating multiple users, but only one Resource.
Here is the factory declaration
class ResourceFactory(DjangoModelFactory):
class Meta:
model = Resource
client = factory.SubFactory(
ClientFactory,
)
user = factory.SubFactory(
UserFactory,
)
start_date = Faker("date_time")
end_date = None
department = Faker("sentence", nb_words=2)
title = Faker("sentence", nb_words=4)
custom_data_field = {"fake": "data"}
This is roughly how I have been trying to do things. I want all resources associated with the same client. At this point, I got the client from the database, because I was getting random errors, and that seemed to fix those errors, at least.
client = ClientFactory()
db_client = Client.objects.get(id=client.id)
resources = [ResourceFactory(client=db_client) for i in range(5)]
if I run len(Resource.objects.all()) at this point, it comes back as 1. How do I create 5 separate resources in the database, all associated with the same client?

Compare set of model instances with their conterparts in DB | Django

I have a question reg. comparing big set of model instances with data in DB.
for example I have a model with 5 fields:
model Foo(models.Model)
fields1 = models.Integerfield()
fields2 = models.Integerfield()
fields3 = models.Integerfield()
fields4 = models.Integerfield()
fields5 = models.Integerfield()
class Meta:
unique_together = (‘field1', 'field2’,)
and I have 400.000 model Foo entries saved in DB.
Also I have 400.000 +/- few instances in memory(in python)of the same model generated from internet CSV file (without pk set).
Question is – what is the most efficient way to do following:
1)If instance in python equal to same instance in DB – keep instance in DB.
2)If instance in python not equal to instance in DB – update instance in DB.
If instance in python does not coincide to any instances in DB – write it to DB.
If no instances in python coincide to particular instance in DB – delete instance from DB.
Its should be bulk operations or RAW SQL as sample size is quite big.
Thank you.
PS. What i do now - delete all, reset counter, write all again to db
Hoping you use Django>=2.2. Try this script,
import csv, os
from your_app.models import Foo
def get_db_object_from_file_object(file_object):
return Foo(
field1=file_object[0],
field2=file_object[1],
field3=file_object[2],
field4=file_object[3],
field5=file_object[4],
)
def update_db_object_from_file_object(db_object, file_object):
db_object.field1 = file_object[0]
db_object.field2 = file_object[1]
db_object.field3 = file_object[2]
db_object.field4 = file_object[3]
db_object.field5 = file_object[4]
with open("<filename.csv>") as f:
reader = csv.reader(f)
eof = os.fstat(f.fileno()).st_size
file_objects = {(each[0], each[1]): each for each in reader}
db_objects = {
(each.field1, each.field2): each
for each in Foo.objects.filter(
field1__in=(each[0] for each in next_lines),
field2__in=(each[1] for each in next_lines)
)
}
to_create = []
to_update = []
for pair, obj in file_objects.items():
if pair not in db_objects:
to_create.append(obj)
else:
update_db_object_from_file_object(db_objects[pair], obj)
to_update.append(db_objects[pair])
del db_objects[pair]
Foo.objects.bulk_create(to_create)
Foo.objects.bulk_update(to_update, ["field1", "field2", "field3", "field4", "field5"])
Foo.objects.filter(id__in=[each.pk for each in db_objects.values()])

Add new object to model with a foreign key

So this seems to be asked before but for the life of me, i cannot get any of the solutions to work.
I have two classes, Device and Log. There are many logs per device and i'd like to be able to add new items to the Log objects.
class Device(models.Models):
name = models.Charfield(max_length=100)
type = models.Charfield(max_length=100)
class Log(models.Modles):
device = models.ForeignKey(Device, related_name='msgs', on_delete=models.CASCADE)
log = models.Charfield(max_length=100)
date_time = models.DateTimeField(auto_now=True)
I've been trying things like this in my view:
device = Device.objects.filter(name=hostname)
device.msgs.add(log=new_log_msg)
but nothing i try is working. any ideas?
You need a Device instance, but filter always gives a queryset. You should use get.
device = Device.objects.get(name=hostname)
device.msgs.add(log=new_log_msg)
Get device object as
device = Device.objects.filter(name=hostname) # If hostname not found throw exception
For creating a new log
log = Log.objects.create(device=device, log='')
use get instead of filter in queryset and for creating and updating the alway intitiate the instance.
device = Device.objects.get(name=hostname)
device.msgs.add(log=new_log_msg)
For adding data in log
Log.objects.create(device=device, log='')
The device=device is foriegn key.

OperationalError: (OperationalError) no such column

I have a problem. I have to do this query:
#app.route('/api/subscriptions/<string:id>', methods=('DELETE',))
#decorators.login_required
def delete_subscription(id):
dbsession = DBSession()
session = Session()
favorit = (dbsession.query(StudentsFavorites)
.filter(Exams.number == str(id))
.filter(StudentsFavorites.exam_id)
.filter(Students.id == StudentsFavorites.student_id)
.filter(Students.id == str(session.get_user_id()))
.delete() )
dbsession.flush()
return jsonify(error=False)
But when I do this query I get this exception:
OperationalError: (OperationalError) no such column: exams.number u'DELETE FROM students_favorites WHERE exams.number = ? AND students_favorites.exam_id AND students.id = students_favorites.student_id AND students.id = ?' ('123123123', 'a24213')
The tables are very big and got lots of information, so i can't post all of it. But this query works:
#app.route('/api/subscriptions/<string:id>', methods=('PUT',))
#decorators.login_required
def add_subscription(id):
dbsession = DBSession()
session = Session()
examID = (dbsession.query(Exams.id)
.filter(Exams.number == id).first()
)
favorit=StudentsFavorites(student_id=session.get_user_id(), exam_id=examID.id)
dbsession.add(favorit)
dbsession.flush()
return jsonify(error=False)
Short view to the table:
table: Exams
rows: id, number (number is the id i put into the function)
table: StudentsFavorites
rows: student_id, exams_id
table: Students
rows: id
I really didn't understand, why he didn't find the number row in the exception.
EDIT:
Database StudentsFavorites:
class StudentsFavorites(Base):
"""N:M resolve model for the exams to the semester.
"""
__tablename__ = "students_favorites"
student_id = Column(Unicode(255), ForeignKey("students.id"), primary_key=True, autoincrement=False)
exam_id = Column(Integer, ForeignKey("exams.id"), primary_key=True, autoincrement=False)
created_at = Column(DateTime, nullable = False, default = datetime.now)
student = relationship("Students", uselist = False, lazy="joined")
exam = relationship("Exams", uselist=False, lazy="joined")
Something like this? I tried this:
(dbsession.query(StudentsFavorites)
.filter(StudentsFavorites.exam.id == str(id))
.filter(StudentsFavorites.student.id == str(session.get_user_id()))
.delete()
)
But got the error, that id didn't exist in exams / student
You have two cases of the same problem. Your query has information for StudentFavorites which means it knows about StudentFavorites.student_id and StudentFaovrites.exams_id. It doesn't know anything about Students.id, Exames.id and Exames.number. In order for you to query a StudentFavorites object and have it know about those other values you're going to have to perform a sql join.
Join's can be a bit of a pain in the ass to get working in sqlalchemy (well... in regular sql as well). Since I don't know what your table schema is I can't talk about that but the view should look something like this.
#app.route('/api/subscriptions/<string:id>', methods=('DELETE',))
#decorators.login_required
def delete_subscription(id):
dbsession = DBSession()
session = Session()
favorit = (dbsession.query(StudentsFavorites)
.join(Exames)
.join(students)
.filter(Exams.number == str(id))
.filter(StudentsFavorites.exam_id)
.filter(Students.id == StudentsFavorites.student_id)
.filter(Students.id == str(session.get_user_id()))
.delete() )
dbsession.flush()
return jsonify(error=False)
Alternatively, you can look into setting up Foreign key relationships in your table statements if you use the ORM to create your tables
The reason your second example works is because you're specifying a query over an exam table and only using values found in that table.
Response to Edit:
Right now your table relationships aren't set up correctly. Specifically the sections: Many To Many and Deleting Rows from the Many to Many Table
This example code is explained in much more (and better) detail in the posted link but the basic idea is that you have a associate_table (in your case StudentFavorites) contains foreign keys which have a relationship which is specified in one or more of your other tables. I personally advise that you go with the table example and not the object example.
association_table = Table('association', Base.metadata,
Column('left_id', Integer, ForeignKey('left.id')),
Column('right_id', Integer, ForeignKey('right.id'))
)
class Parent(Base):
__tablename__ = 'left'
id = Column(Integer, primary_key=True)
children = relationship("Child",
secondary=association_table,
backref="parents")
class Child(Base):
__tablename__ = 'right'
id = Column(Integer, primary_key=True)

Join Multiple Querysets From Different Base Models Django

I currently have two different models.
class Journal(models.Model):
date = models.DateField()
from_account = models.ForeignKey(Account,related_name='transferred_from')
to_account = models.ForeignKey(Account,related_name='transferred_to')
amount = models.DecimalField(max_digits=8, decimal_places=2)
memo = models.CharField(max_length=100,null=True,blank=True)
class Ledger(models.Model):
date = models.DateField()
bank_account = models.ForeignKey(EquityAccount,related_name='paid_from')
account = models.ForeignKey(Account)
amount = models.DecimalField(max_digits=8, decimal_places=2)
name = models.ForeignKey(Party)
memo = models.CharField(max_length=100,null=True,blank=True)
I am creating a report in a view and get the following error:
Merging 'ValuesQuerySet' classes must involve the same values in each case.
What I'm trying to do is only pull out the fields that are common so I can concatenate both of them e.g.
def report(request):
ledger = GeneralLedger.objects.values('account').annotate(total=Sum('amount'))
journal = Journal.objects.values('from_account').annotate(total=Sum('amount'))
report = ledger & journal
...
If I try to make them exactly the same to test e.g.
def report(request):
ledger = GeneralLedger.objects.values('memo').annotate(total=Sum('amount'))
journal = Journal.objects.values('memo').annotate(total=Sum('amount'))
report = ledger & journal
...
I get this error:
Cannot combine queries on two different base models.
Anyone know how this can be accomplished?
from itertools import chain
report = chain(ledger, journal)
Itertools for the win!
If you want to do an Union, you should convert these querysets into python set objects.
If it is possible to filter the queryset itself rightly, you should really do that!
Use itertools.chain:
from itertools import chain
report = list(chain(ledger, journal))
Note: you need to turn the resulting object into a list for Django to be able to process it.
I had the same issue. I solved it using the union method combined_queryset = qs1.union(qs2)
Using your example: report = ledger.union(journal)