models.py
class EmployeeReportRequestForm(forms.Form):
EMPLOYEECHOICE = []
employees = User.objects.filter(group_name='rep')
for employee in employees:
EMPLOYEECHOICE.append([employee.get_username(), employee.get_full_name()])
employee_choice = forms.CharField(max_length=50, widget=forms.Select(choices=EMPLOYEECHOICE))
start_date = forms.DateField(widget=forms.SelectDateWidget())
end_date = forms.DateField(widget=forms.SelectDateWidget())
Trying make a form that allows someone to make a selection from a list of users in a particular group, I figured this would work, but it is not. The most info I'm able to get error wise is
"django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet."
I'm assuming my issue is trying to query the User database from within a Model and that I need to run the lines of code that generate the EMPLOYEECHOICE list in a view and then somehow pass that to the Model? Or just define the widget to be used in the View?
models.py
class EmployeeRequestForm(forms.Form):
def __init__(self):
self.choice_list = [('test', 'test'),]
self.employees = User.objects.filter(groups__name='rep')
for self.x in self.employees:
self.choice_list.append([self.x.get_username(), self.x.get_full_name()])
self.CHOICES = self.choice_list
super (EmployeeRequestForm, self).__init__()
self.fields['employee_choice'].widget = forms.Select(choices=self.CHOICES)
employee_choice = forms.CharField(max_length=100)
start_date = forms.DateField(widget=forms.SelectDateWidget())
end_date = forms.DateField(widget=forms.SelectDateWidget())
Figured out what I was doing wrong, needed to define the choices within the init method. Not sure if this is the best way to do it, but it works.
in my django projects, I have a two class like following:
class DataTag(models.Model):
title = models.CharField(max_length=120, unique=True)
relations = models.ManyToManyField('DataTag',
related_name='related_data_tags', blank=True)
and the another class is:
class Data(models.Model):
tags = models.ManyToManyField('DataTag',related_name = 'data')
def tag_name(self):
if self.tags.all():
return self.tags.all()[0].title
return ''
both my models work, but now I want to write a test for main_tag_name, and checking if this function returns a true value or not.until now I write the following:
from unittest import TestCase
class DataTest(TestCase):
def test_tag_name(self):
self.data = Data.objects.create()
self.tag1 = DataTag.objects.create()
I am new on writing test. please help me for writing this test.
Thanks in advance
What you can do:
Create a Data object:
data_object = Data.objects.create()
Now, create a tag for this:
data_object.tags.create(name='Foo')
You can assert that the relationship exists: self.assertTrue(data_objects.tags.exists())
And now you can assert that tag_name returns what you expect: self.assertEqual(data_object.tag_name, 'Foo')
In my project, i have 2 models:
class Product(models.Model):
name = models.CharField(max_length=200)
class Material(models.Model):
name = models.CharField(max_length=200)
product = models.ForeignKey(Product)
Now, I want to make a copy of Product and keep all of the assigned materials.
This is what I tried:
new_product = Product.object.get(pk='someexistingpk')
new_product.pk = None
new_product.name += ' (Copy)'
new_product.save()
Another variant I tried:
new_product = deepcopy(Product.object.get(pk='someexistingpk'))
new_product.pk = None
new_product.name += ' (Copy)'
new_product.save()
But in both cases, the resulting model_set is empty. None of the attached items are kept.
new_product.material_set.all()
<QuerySet []>
How can I resolve this? Ideally without iterating over every item in the original material_set.
Given that ForeignKeys, can not have multiple assignments, it only makes sense that they are not copied over, as that would break the original object.
So, when copying over the Product, one should also do the same for the related objects. Like this:
new_prod = deepcopy(prod)
new_prod.pk = None
new_prod.save()
for mat in prod.material_set.all():
new_mat = deepcopy(mat)
new_mat.pk = None
new_mat.product = new_prod
new_mat.save()
Now, it results in a nice Queryset with all of the material objects attached, as expected.
new_prod.material_set.all()
<QuerySet [<Material: 1.01 Katoen cats and dogs>, <Material: 1.0 Hour-cost>, <Material: 2.0 lint>, <Material: 1.0 Katoen cats and dogs>]>
From my understanding you are trying to duplicate a model. The way I approached this problem in my project was using dynamic models and inheritance. If you use inheritance, all the fields are going to be automatically copied to the new model.
from MyApp.models import Product
class Meta:
pass
setattr(Meta, 'app_label', 'MyApp')
attrs = {'__module__': module, 'Meta': Meta}
model = type('ProductCopy', (Product,), attrs)
So here the new model that is created is called ProductCopy and will have a table on your Django Admin page.
To learn more about dynamic models you can take a look at this documentation.
I am running into a database issue in my unit tests. I think it has something to do with the way I am using TestCase and setUpData.
When I try to set up my test data with certain values, the tests throw the following error:
django.db.utils.IntegrityError: duplicate key value violates unique constraint
...
psycopg2.IntegrityError: duplicate key value violates unique constraint "InventoryLogs_productgroup_product_name_48ec6f8d_uniq"
DETAIL: Key (product_name)=(Almonds) already exists.
I changed all of my primary keys and it seems to be running fine. It doesn't seem to affect any of the tests.
However, I'm concerned that I am doing something wrong. When it first happened, I reversed about an hour's worth of work on my app (not that much code for a noob), which corrected the problem.
Then when I wrote the changes back in, the same issue presented itself again. TestCase is pasted below. The issue seems to occur after I add the sortrecord items, but corresponds with the items above it.
I don't want to keep going through and changing primary keys and urls in my tests, so if anyone sees something wrong with the way I am using this, please help me out. Thanks!
TestCase
class DetailsPageTest(TestCase):
#classmethod
def setUpTestData(cls):
cls.product1 = ProductGroup.objects.create(
product_name="Almonds"
)
cls.variety1 = Variety.objects.create(
product_group = cls.product1,
variety_name = "non pareil",
husked = False,
finished = False,
)
cls.supplier1 = Supplier.objects.create(
company_name = "Acme",
company_location = "Acme Acres",
contact_info = "Call me!"
)
cls.shipment1 = Purchase.objects.create(
tag=9,
shipment_id=9999,
supplier_id = cls.supplier1,
purchase_date='2015-01-09',
purchase_price=9.99,
product_name=cls.variety1,
pieces=99,
kgs=999,
crackout_estimate=99.9
)
cls.shipment2 = Purchase.objects.create(
tag=8,
shipment_id=8888,
supplier_id=cls.supplier1,
purchase_date='2015-01-08',
purchase_price=8.88,
product_name=cls.variety1,
pieces=88,
kgs=888,
crackout_estimate=88.8
)
cls.shipment3 = Purchase.objects.create(
tag=7,
shipment_id=7777,
supplier_id=cls.supplier1,
purchase_date='2014-01-07',
purchase_price=7.77,
product_name=cls.variety1,
pieces=77,
kgs=777,
crackout_estimate=77.7
)
cls.sortrecord1 = SortingRecords.objects.create(
tag=cls.shipment1,
date="2015-02-05",
bags_sorted=20,
turnout=199,
)
cls.sortrecord2 = SortingRecords.objects.create(
tag=cls.shipment1,
date="2015-02-07",
bags_sorted=40,
turnout=399,
)
cls.sortrecord3 = SortingRecords.objects.create(
tag=cls.shipment1,
date='2015-02-09',
bags_sorted=30,
turnout=299,
)
Models
from datetime import datetime
from django.db import models
from django.db.models import Q
class ProductGroup(models.Model):
product_name = models.CharField(max_length=140, primary_key=True)
def __str__(self):
return self.product_name
class Meta:
verbose_name = "Product"
class Supplier(models.Model):
company_name = models.CharField(max_length=45)
company_location = models.CharField(max_length=45)
contact_info = models.CharField(max_length=256)
class Meta:
ordering = ["company_name"]
def __str__(self):
return self.company_name
class Variety(models.Model):
product_group = models.ForeignKey(ProductGroup)
variety_name = models.CharField(max_length=140)
husked = models.BooleanField()
finished = models.BooleanField()
description = models.CharField(max_length=500, blank=True)
class Meta:
ordering = ["product_group_id"]
verbose_name_plural = "Varieties"
def __str__(self):
return self.variety_name
class PurchaseYears(models.Manager):
def purchase_years_list(self):
unique_years = Purchase.objects.dates('purchase_date', 'year')
results_list = []
for p in unique_years:
results_list.append(p.year)
return results_list
class Purchase(models.Model):
tag = models.IntegerField(primary_key=True)
product_name = models.ForeignKey(Variety, related_name='purchases')
shipment_id = models.CharField(max_length=24)
supplier_id = models.ForeignKey(Supplier)
purchase_date = models.DateField()
estimated_delivery = models.DateField(null=True, blank=True)
purchase_price = models.DecimalField(max_digits=6, decimal_places=3)
pieces = models.IntegerField()
kgs = models.IntegerField()
crackout_estimate = models.DecimalField(max_digits=6,decimal_places=3, null=True)
crackout_actual = models.DecimalField(max_digits=6,decimal_places=3, null=True)
objects = models.Manager()
purchase_years = PurchaseYears()
# Keep manager as "objects" in case admin, etc. needs it. Filter can be called like so:
# Purchase.objects.purchase_years_list()
# Managers in docs: https://docs.djangoproject.com/en/1.8/intro/tutorial01/
class Meta:
ordering = ["purchase_date"]
def __str__(self):
return self.shipment_id
def _weight_conversion(self):
return round(self.kgs * 2.20462)
lbs = property(_weight_conversion)
class SortingModelsBagsCalulator(models.Manager):
def total_sorted(self, record_date, current_set):
sorted = [SortingRecords['bags_sorted'] for SortingRecords in current_set if
SortingRecords['date'] <= record_date]
return sum(sorted)
class SortingRecords(models.Model):
tag = models.ForeignKey(Purchase, related_name='sorting_record')
date = models.DateField()
bags_sorted = models.IntegerField()
turnout = models.IntegerField()
objects = models.Manager()
def __str__(self):
return "%s [%s]" % (self.date, self.tag.tag)
class Meta:
ordering = ["date"]
verbose_name_plural = "Sorting Records"
def _calculate_kgs_sorted(self):
kg_per_bag = self.tag.kgs / self.tag.pieces
kgs_sorted = kg_per_bag * self.bags_sorted
return (round(kgs_sorted, 2))
kgs_sorted = property(_calculate_kgs_sorted)
def _byproduct(self):
waste = self.kgs_sorted - self.turnout
return (round(waste, 2))
byproduct = property(_byproduct)
def _bags_remaining(self):
current_set = SortingRecords.objects.values().filter(~Q(id=self.id), tag=self.tag)
sorted = [SortingRecords['bags_sorted'] for SortingRecords in current_set if
SortingRecords['date'] <= self.date]
remaining = self.tag.pieces - sum(sorted) - self.bags_sorted
return remaining
bags_remaining = property(_bags_remaining)
EDIT
It also fails with integers, like so.
django.db.utils.IntegrityError: duplicate key value violates unique constraint "InventoryLogs_purchase_pkey"
DETAIL: Key (tag)=(9) already exists.
UDPATE
So I should have mentioned this earlier, but I completely forgot. I have two unit test files that use the same data. Just for kicks, I matched a primary key in both instances of setUpTestData() to a different value and sure enough, I got the same error.
These two setups were working fine side-by-side before I added more data to one of them. Now, it appears that they need different values. I guess you can only get away with using repeat data for so long.
I continued to get this error without having any duplicate data but I was able to resolve the issue by initializing the object and calling the save() method rather than creating the object via Model.objects.create()
In other words, I did this:
#classmethod
def setUpTestData(cls):
cls.person = Person(first_name="Jane", last_name="Doe")
cls.person.save()
Instead of this:
#classmethod
def setUpTestData(cls):
cls.person = Person.objects.create(first_name="Jane", last_name="Doe")
I've been running into this issue sporadically for months now. I believe I just figured out the root cause and a couple solutions.
Summary
For whatever reason, it seems like the Django test case base classes aren't removing the database records created by let's just call it TestCase1 before running TestCase2. Which, in TestCase2 when it tries to create records in the database using the same IDs as TestCase1 the database raises a DuplicateKey exception because those IDs already exists in the database. And even saying the magic word "please" won't help with database duplicate key errors.
Good news is, there are multiple ways to solve this problem! Here are a couple...
Solution 1
Make sure if you are overriding the class method tearDownClass that you call super().tearDownClass(). If you override tearDownClass() without calling its super, it will in turn never call TransactionTestCase._post_teardown() nor TransactionTestCase._fixture_teardown(). Quoting from the doc string in TransactionTestCase._post_teardown()`:
def _post_teardown(self):
"""
Perform post-test things:
* Flush the contents of the database to leave a clean slate. If the
class has an 'available_apps' attribute, don't fire post_migrate.
* Force-close the connection so the next test gets a clean cursor.
"""
If TestCase.tearDownClass() is not called via super() then the database is not reset in between test cases and you will get the dreaded duplicate key exception.
Solution 2
Override TransactionTestCase and set the class variable serialized_rollback = True, like this:
class MyTestCase(TransactionTestCase):
fixtures = ['test-data.json']
serialized_rollback = True
def test_name_goes_here(self):
pass
Quoting from the source:
class TransactionTestCase(SimpleTestCase):
...
# If transactions aren't available, Django will serialize the database
# contents into a fixture during setup and flush and reload them
# during teardown (as flush does not restore data from migrations).
# This can be slow; this flag allows enabling on a per-case basis.
serialized_rollback = False
When serialized_rollback is set to True, Django test runner rolls back any transactions inserted into the database beween test cases. And batta bing, batta bang... no more duplicate key errors!
Conclusion
There are probably many more ways to implement a solution for the OP's issue, but these two should work nicely. Would definitely love to have more solutions added by others for clarity sake and a deeper understanding of the underlying Django test case base classes. Phew, say that last line real fast three times and you could win a pony!
The log you provided states DETAIL: Key (product_name)=(Almonds) already exists. Did you verify in your db?
To prevent such errors in the future, you should prefix all your test data string by test_
I discovered the issue, as noted at the bottom of the question.
From what I can tell, the database didn't like me using duplicate data in the setUpTestData() methods of two different tests. Changing the primary key values in the second test corrected the problem.
I think the problem here is that you had a tearDownClass method in your TestCase without the call to super method.
In this way the django TestCase lost the transactional functionalities behind the setUpTestData so it doesn't clean your test db after a TestCase is finished.
Check warning in django docs here:
https://docs.djangoproject.com/en/1.10/topics/testing/tools/#django.test.SimpleTestCase.allow_database_queries
I had similar problem that had been caused by providing the primary key value to a test case explicitly.
As discussed in the Django documentation, manually assigning a value to an auto-incrementing field doesn’t update the field’s sequence, which might later cause a conflict.
I have solved it by altering the sequence manually:
from django.db import connection
class MyTestCase(TestCase):
#classmethod
def setUpTestData(cls):
Model.objects.create(id=1)
with connection.cursor() as c:
c.execute(
"""
ALTER SEQUENCE "app_model_id_seq" RESTART WITH 2;
"""
)
I keep getting these inner join errors when I try to delete an object. It's a programming error, and an exception value of "column main_reviewerauthoranswer.screener_id does not exist
LINE 1: ...viewerauthoranswer" INNER JOIN "main_reader" ON ( "main_revi..."
I'm using south. I'm migrating just fine. Creating instances just fine. But if I try to delete something I keep getting those errors. I don't know if something changed in django 1.6 with through tables? I'm very confused.
So this is what I"m doing. Empty database. I create a reader in the admin, I give the reader a genre ( I create it in the admin). Save. No problem. Ok, try to delete the reader I get
column main_reviewerauthoranswer.screener_id does not exist
LINE 1: ...viewerauthoranswer" INNER JOIN "main_reader" ON ( "main_revi...
If i try to delete the genre I just created for that reader I get a
column main_reviewerauthoranswer.screener_id does not exist
LINE 1: ...viewerauthoranswer" INNER JOIN "main_reader" ON ( "main_revi...
So obviously there is something wrong with my ReviewAuthorAnswer model. But I dont' see what
My models looks like this:
class DateDocumentation(models.Model):
modified_at = models.DateTimeField(auto_now=True)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
abstract = True
class Author(DateDocumentation):
user = models.OneToOneField(User, null=True)
class Reader(DateDocumentation):
user = models.OneToOneField(User)
favorite_genre = models.ForeignKey('Genre')
class Genre(models.Model):
title = models.CharField(max_length=100
class Book(DateDocumentation):
author = models.ForeignKey('Author')
book = models.FileField(upload_to='books/')
genre = models.ForeinKey('Gengre')
class Blurbreview(DateDocumentation):
reader = models.ForeignKey("Reader")
review = models.ForeignKey("Review")
class Review(DateDocumentation):
book = models.ForeignKey('Book')
blurb_readers = models.ManyToManyField("Reader",
through="blurbreview",
related_name='blurb_readers')
readers = models.ManyToManyField("Reader",
help_text="Readers that downloaded this book",)
class BaseQuestion(DateDocumentation):
review = models.ForeignKey("Review")
reviewer = models.ForeignKey("Reader")
class AuthorQuestion(DateDocumentation):
review = models.ForeignKey('Review')
class ReviewerAuthorAnswer(DateDocumentation):
question = models.ForeignKey('AuthorQuestion')
screener = models.ForeignKey('Reader')
You may have to rebuild the database. When you import new data, make sure that you run foreign_key_check=0; before the query.
I ran into this issue several times when I mistakenly tried importing data into an emptied database.