Django Unit testing, unknown column error - python

I'm a Django beginner and am getting acquainted to using it, and I'm also a big believer in unit testing.
Given a sample database table contracts with the fields
parent_id int
contract_num varchar
start_date date
end_date date
org_name varchar
I defined a model class by using django_admin.py inspectdb > models.py
class Contracts(models.Model):
parent_id = models.IntegerField()
contract_num = models.CharField(max_length=10L, db_column='contract_num')
start_date = models.DateField()
end_date = models.DateField(null=True, blank=True)
org_name = models.CharField(max_length=100L, db_column='org_name')
class Meta:
db_table = 'contracts'
Within the test class, I defined
def setUp(self):
self.contracts = Contracts(parent_id = 300, contract_num = "1234", start_date = timezone.now(), end_date = None, org_name = "TestContractName")
def test_contracts_access(self):
self.contracts.save()
getContracts = Contracts.objects.get(parent_id = 300)
self.assertEqual(getContracts.org_name, "TestContractName")
self.assertEqual(getContracts.contract_num, "1234")
self.assertEquals(getContracts.contract_num, "12")
getContracts.org_name = "TestContractNameUpdate"
getContracts.save()
updateContract = Contracts.objects.get(contract_num = "1234")
self.assertEqual(updateContract.org_name, "TestContractNameUpdate")
When I run this test, I get a database error 1054: "Unknown column contracts.id in field list". What exactly does that mean? The first error in the stack trace is the get call right after the first save.
Thing is, I have an exact same test set up for another model object and that one passes.

Make sure to check the primary key that is set in the database. If you have a primary key that is on a field not labeled "id" (I'm looking at you parent_id...), then you need to set this in your model. You can do this with :
field_name = models.AutoField(primary_key=True)
If you do not do this, then Django will look for the field "id", assuming that you have one and that it is your primary key. I think you are getting this error because it is looking for contracts.id which does not exist!
Check out the Django docs on primary-key-fields and legacy databses.

Related

Django - Can I add a calculated field that only exists for a particular sub-set or occurences of my model?

Imagine that you have a model with some date-time fields that can be categorized depending on the date. You make an annotation for the model with different cases that assign a different 'status' depending on the calculation for the date-time fields:
#Models.py
class Status(models.TextChoices):
status_1 = 'status_1'
status_2 = 'status_2'
status_3 = 'status_3'
special_status = 'special_status'
class MyModel(models.Model):
important_date_1 = models.DateField(null=True)
important_date_2 = models.DateField(null=True)
calculated_status = models.CharField(max_length=32, choices=Status.choices, default=None, null=True, blank=False,)
objects = MyModelCustomManager()
And the manager with which to do the calculation as annotations:
# managers.py
class MyModelCustomManager(models.Manager):
def get_queryset(self):
queryset = super().get_queryset().annotate(**{
'status': Case(
When(**{'important_date_1' is foo, 'then':
Value(Status.status_1)}),
When(**{'important_date_2' is fii, 'then':
Value(Status.status_2)}),
When(**{'important_date_1' is foo AND 'importante_date_2' is whatever, 'then':
Value(Status.status_3)}),
# And so on and so on
)
}
)
return queryset
Now, here's where it gets tricky. Only one of these sub-sets of occurrences on the model requires an ADDITIONAL CALCULATED FIELD that literally only exists for it, that looks something like this:
special_calculated_field = F('important_date_1') - F('importante_date_2') #Only for special_status
So, basically I want to make a calculated field with the condition that the model instance must belong to this specific status. I don't want to make it an annotation, because other instances of the model would always have this value set to Null or empty if it were a field or annotation and I feel like it would be a waste of a row in the database.
Is there way, for example to do this kind of query:
>>> my_model_instance = MyModel.objects.filter(status='special_status')
>>> my_model_instance.special_calculated_field
Thanks a lot in advance if anyone can chime in with some help.

Django Left join how

I fairly new to Django and stuck with creating a left join in Django. I tried so many, but none of them seems to be working:
The query I want to translate to Django is:
select ssc.id
,mgz.Title
,tli.id
,tli.Time
from Subscription ssc
join Person prs
on ssc.PersonID = prs.id
and prs.id = 3
join Magazine mgz
on mgz.id = ssc.MagazineID
and mgz.from <= date.today()
and mgz.until > date.today()
left join TimeLogedIn tli
on tli.SubscriptionID = ssc.id
and tli.DateOnline = date.today()
The model I'm using looks like this:
class Magazine(models.Model):
Title = models.CharField(max_length=100L)
from = models.Datefield()
until = models.Datefield()
Persons = models.ManyToManyField(Person, through='Subscription')
class Person(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
Magazines = models.ManyToManyField(Magazine, through='Subscription')
class Subscription(models.Model):
MagazineID = models.ForeignKey(Magazine,on_delete=models.CASCADE)
PersonID = models.ForeignKey(Person,on_delete=models.CASCADE)
class TimeLogedIn(models.Model):
SubscriptionID = models.ForeignKey('Subscription', on_delete=models.CASCADE)
DateOnline = models.DateField()
Time = models.DecimalField(max_digits=5, decimal_places=2)
Like I said, tried so many but no succes and now I don't know how to do this in Django ORM , is it even possible? I created already a raw-query and this is working ok, but how to create this in Django ORM?
You can use field lookups lte and gt to filter your objects and then values() method.
You can also querying in the opposite direction and use Q objects for null values:
from django.db.models import Q
Subscription.objects.filter(
PersonID_id=3,
MagazineID__from__lte=date.today(),
MagazineID__until__gt=date.today()
).filter(
Q(TimeLogedIn__DateOnline=date.today()) | Q(TimeLogedIn__DateOnline__isnull=True)
).values("id", "MagazineID__Title", "TimeLogedIn__id", "TimeLogedIn__Time")
OR from TimeLogedIn:
TimeLogedIn.objects.filter(DateOnline=date.today()).filter(
SubscriptionID__MagazineID__from__lte=date.today(),
SubscriptionID__MagazineID__util__gt=date.today()
).values(
"SubscriptionID_id", "SubscriptionID__MagazineID__Title", "id", "Time"
)
Querysets also have the query attribute that contains the sql query to be executed, you can see it like following:
print(TimeLogedIn.objects.filter(...).values(...).query)
Note: Behind the scenes, Django appends "_id" to the field name to create its database column name. Therefore it should be
subscription, instead of SubscriptionID.
You can also use prefetch_related() and select_related() to prevent multiple database hits:
SubscriptionID.objects.filter(...).prefetch_related("TimeLogedIn_set")
SubscriptionID.objects.filter(...).select_related("PersonID")

Django ORM: Object is not iterable (Error)

Can anyone explain why this is iterable:
User.objects.all()
this is valid and gives me a value (The current user's alias. session is storing the user id):
User.objects.get(id = request.session['currentuser']).alias)
But this is giving me the error saying it is 'not iterable?':
Poke.objects.get(user = User.objects.get(id = request.session['currentuser']).alias)
(This code is supposed to get a list of Poke entries where the user column matches the current user's alias.)
Here is the Poke model. It does not use ForeignKeys, as I was having trouble setting two of them without errors.
class Poke(models.Model):
id = models.IntegerField(primary_key=True)
user = models.CharField(max_length=100)
poker = models.CharField(max_length=100)
pokes = models.IntegerField()
class Meta:
app_label = "poke_app"
Get will retrieve a single object and therefore the result will not be iterable. See documentation.
Do you see an integer value when you print(request.session['currentuser'])?
If you will see a string then you shoud give an integer value
EX: userobj = User.objects.get(id=uid)
Oh sory
User.objects.get(id = request.session['currentuser']).alias)
You open ( and closed it after ['currentuser']) but why you close ) again after .alias ?

I need to query for a set of objects whose primary keys are contained inside of a list

As the title says, I need a way to perform this query. I have tried the following:
user_list_ids = []
user_lists = []
user_entries = OwnerEntry.objects.filter(name=request.user)
for user in user_entries:
user_list_ids.append(user.list_id)
user_lists = ListEntry.objects.filter(id__in=user_list_ids)
for user in user_entries:
user_list_ids.append(user.list_id)
user_lists = ListEntry.objects.filter(id__in=user_list_ids)
However, I get an error on the last line: int() argument must be a string or a number, not 'ListEntry'
Here are the relevant models:
class OwnerEntry(models.Model):
name = models.CharField(max_length=32)
list_id = models.ForeignKey(ListEntry)
class Meta:
ordering = ('name',)
class ListEntry(models.Model):
name = models.CharField(max_length=64)
# active_date = models.DateTimeField('date of last list activity')
expire_date = models.DateField('date of expiration')
create_date = models.DateField('date created')
to answer your question directly, please note that you have a list_id rather than list as a ForeignKey name (OwnerEntry model). In order to actually extract the fk value, you should use list_id_id instead (or rename list_id to list ;))
Please also note that django supports object references, like so:
someowner = OwnerEntry.objects.get( ... )
ownerslist = someowner.listentry_set.all()
cheers!
You can define OwnerEntry's foreign key to ListEntry as :
list_id = models.ForeignKey(ListEntry, related_query_name='owner_entry')
and then do this one-liner in your code:
user_lists = ListEntry.objects.filter(owner_entry__name=request.user)
What this does is exactly filter every ListEntry which has at least one owner_entry whose name is equal to request.user's.
The redefinition of the foreign key is just for the sake of giving a nice name to the query attribute.
For more details on queries that work with backward relationships: https://docs.djangoproject.com/en/dev/topics/db/queries/#lookups-that-span-relationships

Django ManyToManyField Error when saving in admin?

What is wrong with my code?
class Group(ImageModel):
title = models.CharField(verbose_name = "Title", max_length=7)
photos = models.ManyToManyField('Photo', related_name='+',
verbose_name=_('Photo'),
null=True, blank=True)
.....
pid = Photo.objects.get(image = str_path)
gid= Group.objects.get(id = self.id)
self.save_photos(gid, pid)
....
def save_photos(self, gid, pid):
group_photo = GroupPhotos(groupupload=gid.id,
photo=pid.id
)
group_photo.save()
and my GroupPhotos models is:
class GroupPhotos(models.Model):
groupupload = models.ForeignKey('Group')
photo = models.ForeignKey('Photo')
class Meta:
db_table = u'group_photos'
when i want to save it from admin panel i am getting value error sth like this:
Cannot assign "38": "GroupPhotos.groupupload" must be a "Group" instance.
with group_photo = GroupPhotos(groupupload=gid, photo=pid) defination it is working but there is no any changes in GroupPhotos table(group_photos). printing this print pid.id,' >>> ',gid.id i am getting true relation...
UPDATE:
I have been working since morning, but no progress... i have also tried this but nothing changed:
pid = Photo.objects.get(image = str_path)
ger = Group.objects.get(id = self.id)
ger.title = self.title
ger.save()
ger.photos.add(pid)
The error is here:
group_photo = GroupPhotos(groupupload=gid.id, photo=pid.id)
The arguments to groupupload and photo should be instances of Group and Photo respectively. Try the following:
group_photo = GroupPhotos(groupupload=gid, photo=pid)
In other words, when creating an object you need to pass arguments of the expected type and not an integer (which may be the primary key key of the desired object but it also might not, which is why you need to pass an object of the correct type).
i have solved my problem with adding through option to my manytomanyfield:
photos = models.ManyToManyField('Photo', related_name='+',
verbose_name=_('Photo'),
null=True, blank=True, through=GroupPhotos)
some info about ManyToManyField.through here:
Django will automatically generate a table to manage many-to-many
relationships. However, if you want to manually specify the
intermediary table, you can use the through option to specify the
Django model that represents the intermediate table that you want to
use.
The most common use for this option is when you want to associate extra data with a many-to-many relationship.

Categories

Resources