I'm trying to create a one-to-one relationship matching a table with property billing records to another with physical addresses, but I keep getting this error. When I search for the error, nothing shows that is relevant to this situation.
I've no idea what "[<PropertyRecord: 242811400004>]" is referencing since it isn't a PIN number and doesn't exist in any tables.
Also, I've been through the data and there are no null values on the pin in either table.
Getting this error:
{
error: "The object '[<PropertyRecord: 242811400004>]' has an empty attribute 'pin' and doesn't allow a default or null value."
}
Models:
class PropertyRecord(models.Model):
pin = models.BigIntegerField(db_index=True, max_length=20)
date_added = models.DateField(null=True)
last_chgdte = models.DateField()
name = models.CharField(db_index=True, max_length=30, null=True)
address1 = models.CharField(max_length=100, null=True)
address2 = models.CharField(max_length=100, null=True)
city = models.CharField(max_length=50, null=True)
state = models.CharField(max_length=2, null=True)
zip = models.CharField(max_length=10, null=True)
class Meta:
unique_together = ("pin", "last_chgdte")
select_on_save = True
def __str__(self):
return str(self.pin)
class PropertyAddress(models.Model):
pin = models.BigIntegerField(db_index=True, max_length=20, unique=True)
street_address = models.CharField(max_length=50, null=True)
city_name = models.CharField(max_length=50, null=True)
zip_code = models.IntegerField(max_length=5, null=True)
class Meta:
select_on_save = True
def __str__(self):
return str(self.pin)
Resources:
class PropertyAddressResource(ModelResource):
class Meta:
queryset = PropertyAddress.objects.all()
class PropertyRecordResource(ModelResource):
full_address = fields.ToOneField(
PropertyAddressResource,
attribute=lambda bundle: PropertyRecord.objects.filter(pin=bundle.obj.pin),
full=True,
null=True
)
class Meta:
queryset = PropertyRecord.objects.all()
resource_name = 'propertyrecords'
I can't imagine that joining tables wouldn't be a common need, so it should have a simple solution.
Rather, I was able to get around the issue by using dehydrate, which feels overly complicated but works. +1 to this being a PITA with the extra step to serialize the data.
def dehydrate(self, bundle):
query_data = PropertyAddress.objects.filter(pin=bundle.obj.pin)
results = serialize('json', query_data, fields=('street_address', 'city_name', 'zip_code'))
bundle.data['full_address'] = json.loads(results)
return bundle
Related
I've setup a relationship using django's ForeignKey against 2 unmanaged tables like so:
class Product(BaseModel):
publish_name = models.CharField(unique=True, max_length=40)
# this works:
associated_country = models.ForeignKey('geonames.Countryinfo', models.DO_NOTHING, db_column='published_country', blank=True, null=True)
# this doesn't:
associated_continent = models.ForeignKey('geonames.Continentcodes', on_delete=models.DO_NOTHING, db_column='published_continent' blank=True, null=True)
class Meta:
managed = True
db_table = 'product'
class Continentcodes(models.Model):
code = models.CharField(max_length=2, primary_key=True, unique=True)
name = models.TextField(blank=True, null=True)
geoname_id = models.ForeignKey('Geoname', models.DO_NOTHING, blank=True, null=True, unique=True)
class Meta:
managed = False
db_table = 'geoname_continentcodes'
class Countryinfo(models.Model):
iso_alpha2 = models.CharField(primary_key=True, max_length=2)
country = models.TextField(blank=True, null=True)
geoname = models.ForeignKey('Geoname', models.DO_NOTHING, blank=True, null=True)
neighbours = models.TextField(blank=True, null=True)
class Meta:
ordering = ['country']
managed = False
db_table = 'geoname_countryinfo'
verbose_name_plural = 'Countries'
When I go to edit an entry in the django admin page for 'Products' I see this:
InvalidCursorName at /admin/product/6/change/ cursor
"_django_curs_140162796078848_sync_5" does not exist
The above exception (column geoname_continentcodes.geoname_id_id does
not exist LINE 1: ...ntcodes"."code", "geoname_continentcodes"."name",
"geoname_c...
^ HINT: Perhaps you meant to reference the column
"geoname_continentcodes.geoname_id"
It looks like it's trying to reference geoname_continentcodes.geoname_id_id for some reason. I have tried adding to='code' in the ForeignKey relationship, but it doesn't seem to effect anything.
Additionally, the associated_country relationship seems to work just fine if I comment out the associated_continent field. The associated_continent is the column that is giving some problem.
Here is some more context about what the table looks like in the database:
Removing the '_id' as the suffix is the fix. In this case geoname_id changed to geoname fixes this. Why? I have no idea. Django is doing something behind the scenes that is not clear to me. Here is the updated model:
class Continentcodes(models.Model):
code = models.CharField(max_length=2, primary_key=True, unique=True)
name = models.TextField(blank=True, null=True)
# remove '_id' as the suffix here
geoname = models.ForeignKey('Geoname', models.DO_NOTHING, blank=True, null=True, unique=True)
class Meta:
managed = False
db_table = 'geoname_continentcodes'
Django adds _id to the end to differentiate between the object and the id column in the table, geoname_id will return the table id where as geoname will return the object.
I am having 4 models linked with a foreign key,
class CustomUser(AbstractUser):
username = None
email = models.EmailField(('email address'), unique=True)
phone_no = models.CharField(max_length=255, unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = CustomUserManager()
def __str__(self):
return self.email
class personal_profile(models.Model):
custom_user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
picture = models.ImageField(default='profile_image/pro.png', upload_to='profile_image', blank=True)
role = models.CharField(max_length=255, blank=True, null=True)
gender = models.CharField(max_length=255, blank=True, null=True)
date_of_birth = models.DateField(blank=True, null=True)
def __str__(self):
return str(self.pk)
class academia_profile(models.Model):
custom_user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
education_or_certificate = models.CharField(max_length=255, blank=True, null=True)
university = models.CharField(max_length=255, blank=True, null=True)
def __str__(self):
return str(self.pk)
class contact_profile(models.Model):
custom_user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
country = models.CharField(max_length=255, blank=True, null=True)
state = models.CharField(max_length=255, blank=True, null=True)
city = models.CharField(max_length=255, blank=True, null=True)
def __str__(self):
return str(self.pk)
For extracting the data of those four models, I need to extract it by querying 4 times differently and then by passsing for different variables to HTML templates it something a hectic plus would be reducing the performance speed (I am sure!)
My current queries be like
user_base = CustomUser.objects.get(id=user_id)
user_personal = personal_profile.objects.get(custom_user=user_id)
academia = academia_profile.objects.get(custom_user=user_id)
contact = contact_profile.objects.get(custom_user=user_id)
Is it possible to get all of the four queries values in a single variable by hitting a single join query in ORM ?
also, I want to extract just the country from contact_profile and picture from personal_profile in the join query.
Select_related() can able to work here but how? that's what I am not getting.
You are looking for prefetch_related:
Returns a QuerySet that will automatically retrieve, in a single batch, related objects for each of the specified lookups.
user_base = (
CustomUser
.objects
.prefetch_related( #<-- THIS!
"personal_profile_set",
"academia_profile_set",
"contact_profile_set")
.get(id=user_id))
personal_profile = user_base.personal_profile_set.all()[0]
academia_profile = user_base.academia_profile_set.all()[0]
contact_profile = user_base.contact_profile_set.all()[0]
Btw, if you have only one personal_profile, academia_profile, contact_profile per CustomUser, consider changing ForeignKey by OneToOneField and use select_related.
I use Django2 and sqlite in windows 10 for a course management website.
when I tried to query the database in view.py using
query_results_3 = CourseInfo.objects.values('title', code=course_code[:5])
error occurs:
ValueError: The annotation 'code' conflicts with a field on the model.
model.py:
class CourseInfo(TimeStampedModel): # school or center
code = models.CharField(max_length=20, unique=True, db_index=True)
title = models.CharField(max_length=200)
school = models.ForeignKey(School, on_delete=models.SET_NULL, blank=True, null=True)
postgraduate = models.BooleanField(default=False) # indicate Postgraduate course
discipline = models.ForeignKey(Discipline, on_delete=models.SET_NULL, blank=True, null=True) # should not be null
pattern = models.CharField(max_length=120, choices=PRESENTATION_PATTERN, blank=True, null=True,
help_text="Presentation Pattern")
type = models.CharField(max_length=2, choices=(('PT', 'Part-Time'), ('FT', 'Full-Time'), ('OL', 'Online')))
available = models.BooleanField(default=True) # mean Active or Retired
semesters = models.ManyToManyField('Semester', through="Course") # auto have semestercourse_set
def __str__(self):
return "{} - {}".format(self.code, self.title)
class Meta:
constraints = [models.UniqueConstraint(fields=['code', 'type'], condition=models.Q(available=True),
name='unique_course_type')]
ordering = ['code', ]
How to change my code to let the error disapear?
You should do:
query_results_3 = CourseInfo.objects.filter(code=YOUR_CONDITION).values('title')
I need to log the transaction of the item movement in a warehouse. I've 3 tables as shown in the below image. However Django response error:
ERRORS:
chemstore.ItemTransaction: (models.E007) Field 'outbin' has column name 'bin_code_id' that is used by another field.
which is complaining of multiple uses of the same foreign key. Is my table design problem? or is it not allowed under Django? How can I achieve this under Django? thankyou
DB design
[Models]
class BinLocation(models.Model):
bin_code = models.CharField(max_length=10, unique=True)
desc = models.CharField(max_length=50)
def __str__(self):
return f"{self.bin_code}"
class Meta:
indexes = [models.Index(fields=['bin_code'])]
class ItemMaster(models.Model):
item_code = models.CharField(max_length=20, unique=True)
desc = models.CharField(max_length=50)
long_desc = models.CharField(max_length=150, blank=True)
helper_qty = models.DecimalField(max_digits=10, decimal_places=4)
unit = models.CharField(max_length=10, blank=False)
def __str__(self):
return f"{self.item_code}"
class Meta:
verbose_name = "Item"
verbose_name_plural = "Items"
indexes = [models.Index(fields=['item_code'])]
class ItemTransaction(models.Model):
trace_code = models.CharField(max_length=20, unique=False)
item_code = models.ForeignKey(
ItemMaster, related_name='trans', on_delete=models.CASCADE, null=False)
datetime = models.DateTimeField(auto_now=False, auto_now_add=False)
qty = models.DecimalField(max_digits=10, decimal_places=4)
unit = models.CharField(max_length=10, blank=False)
action = models.CharField(
max_length=1, choices=ACTION, blank=False, null=False)
in_bin = models.ForeignKey(
BinLocation, related_name='in_logs', db_column='bin_code_id', on_delete=models.CASCADE, null=False)
out_bin = models.ForeignKey(
BinLocation, related_name='out_logs', db_column='bin_code_id', on_delete=models.CASCADE, null=False)
remarks = models.TextField(blank=True)
def __str__(self):
return f"{self.trace_code} {self.datetime} {self.item_code} {dict(ACTION)[self.action]} {self.qty} {self.unit} {self.in_bin} {self.out_bin}"
you have same db_column in two fields so change it
in_bin = models.ForeignKey(
BinLocation, related_name='in_logs', db_column='bin_code_id', on_delete=models.CASCADE, null=False)
out_bin = models.ForeignKey(
BinLocation, related_name='out_logs', db_column='other_bin_code', on_delete=models.CASCADE, null=False) /*change db_column whatever you want but it should be unique*/
If are linked to the same model name, You should use different related_name for each foreign_key filed . here is the exemple :
address1 = models.ForeignKey(Address, verbose_name=_("Address1"),related_name="Address1", null=True, blank=True,on_delete=models.SET_NULL)
address2 = models.ForeignKey(Address, verbose_name=_("Address2"),related_name="Address2", null=True, blank=True,on_delete=models.SET_NULL)
thank you for everyone helped. According to Aleksei and Tabaane, it is my DB design issue (broken the RDBMS rule) rather than Django issue. I searched online and find something similar: ONE-TO-MANY DB design pattern
In my case, I should store in bin and out bin as separated transaction instead of both in and out in a single transaction. This is my solution. thankyou.
p.s. alternative solution: I keep in bin and out bin as single transaction, but I don't use foreign key for bins, query both in bin and out bin for the bin selection by client application.
i'm trying to post a transaction via django rest framework, however it shows error in django log as below:
IntegrityError at /api/item_trans/
NOT NULL constraint failed: chemstore_itemtransaction.bin_code_id
it has no problem if I post the same data from the Django admin web.
therefore I suppose the problem has happened at DRF
any help is welcome, thank you
models.py
class BinLocation(models.Model):
bin_code = models.CharField(max_length=10, unique=True)
desc = models.CharField(max_length=50)
def __str__(self):
return self.bin_code
class Meta:
indexes = [models.Index(fields=['bin_code'])]
class ItemMaster(models.Model):
item_code = models.CharField(max_length=20, unique=True)
desc = models.CharField(max_length=50)
long_desc = models.CharField(max_length=150, blank=True)
helper_qty = models.DecimalField(max_digits=10, decimal_places=4)
unit = models.CharField(max_length=10, blank=False)
def __str__(self):
return self.item_code
class Meta:
verbose_name = "Item"
verbose_name_plural = "Items"
indexes = [models.Index(fields=['item_code'])]
class ItemTransaction(models.Model):
# trace_code YYMMDDXXXX where XXXX is random generated
trace_code = models.CharField(max_length=20, unique=False)
item_code = models.ForeignKey(
ItemMaster, on_delete=models.CASCADE, related_name='+', blank=False, null=False)
datetime = models.DateTimeField(auto_now=False, auto_now_add=False)
qty = models.DecimalField(max_digits=10, decimal_places=4)
unit = models.CharField(max_length=10, blank=False)
action = models.CharField(
max_length=1, choices=ACTION, blank=False, null=False)
bin_code = models.ForeignKey(
BinLocation, related_name='+', on_delete=models.CASCADE, blank=False, null=False)
remarks = models.TextField(blank=True)
def __str__(self):
return f"{self.trace_code} {self.datetime} {self.item_code} {dict(ACTION)[self.action]} {self.qty} {self.unit} {self.bin_code}"
serializers.py
class ItemMasterSerializer(serializers.ModelSerializer):
class Meta:
model = ItemMaster
fields = '__all__'
class ItemTransactionSerializer(serializers.ModelSerializer):
item_code = serializers.SlugRelatedField(
slug_field='item_code',
read_only=True
)
bin_code = serializers.SlugRelatedField(
slug_field='bin_code',
read_only=True,
allow_null=False
)
class Meta:
model = ItemTransaction
fields = '__all__'
You might need to use 2 fields, one for reading data and the other for creating and updating your data with its source to the main. In your case you could try this:
class ItemTransactionSerializer(serializers.ModelSerializer):
item_code_id = ItemMasterSerializer(read_only=True)
item_code = serializers.PrimaryKeyRelatedField(
queryset=ItemMaster.objects.all(),
write_only=True,
source='item_code_id'
)
bin_code_id = BinLocationSerializer(read_only=True
bin_code = serializers.PrimaryKeyRelatedField(
queryset= BinLocation.objects.all(),
write_only=True,
source='bin_code_id'
)
Since you have null=False in both of your ForeignKeys, DRF expects the corresponding ID. You seem to be getting the error NOT NULL constraint because you are not passing the ID in DRF. So you need to fix that for both bin_code_id and the item_code_id.