Django ForeignKey TemplateSyntaxError and ProgrammingError - django

This is are my models i want to relate. i want for collection to appear in the form of occurrence.
class Collection(models.Model):
id = models.AutoField(primary_key=True, null=True)
code = models.CharField(max_length=100, null=True, blank=True)
address = models.CharField(max_length=100, null=True, blank=True)
collection_name = models.CharField(max_length=100)
def __unicode__(self):
return self.collection_name
class Meta:
db_table = u'collection'
ordering = ('collection_name',)
class Occurrence(models.Model):
id = models.AutoField(primary_key=True, null=True)
reference = models.IntegerField(null=True, blank=True, editable=False)
collection = models.ForeignKey(Collection, null=True, blank=True, unique=True),
modified = models.DateTimeField(null=True, blank=True, auto_now=True)
class Meta:
db_table = u'occurrence'
Every time i go to check the Occurrence object i get this error
TemplateSyntaxError at /admin/hotiapp/occurrence/
Caught an exception while rendering: column occurrence.collection_id does not exist
LINE 1: ...LECT "occurrence"."id", "occurrence"."reference", "occurrenc..
And every time i try to add a new occurrence object i get this error
ProgrammingError at /admin/hotiapp/occurrence/add/
column occurrence.collection_id does not exist
LINE 1: SELECT (1) AS "a" FROM "occurrence" WHERE "occurrence"."coll...
What am i doing wrong? or how does ForeignKey works?

The problem is that you have not updated your database table definition since adding the ForeignKey. syncdb doesn't do this for you, as the documentation clearly states. You need to update the SQL manually, or use a tool like South.

Are you sure you mean
collection = models.ForeignKey(Collection, null=True, blank=True, unique=True),
Nullable and Unique? This may not be possible in some databases.
Generally, the unique constraint doesn't seem to make much sense here.
Are you trying to force a 1-to-1 relationship? Use the OneToOneField. http://docs.djangoproject.com/en/1.1/ref/models/fields/#django.db.models.OneToOneField

Related

Django, Sqlalchemy: Cannot drop table ganalytics_article because other objects depend on it

I have this models in my Django ganalytics app:
class Article(models.Model):
id = models.IntegerField(unique=True, primary_key=True)
article_title = models.CharField(max_length=250)
article_url = models.URLField(max_length=250)
article_pub_date = models.DateField()
class Company(models.Model):
company_name = models.CharField(max_length=250)
class Author(models.Model):
author_sf_id = models.CharField(max_length=20, null=True)
author_name = models.CharField(max_length=250)
class AuthorArticleCompany(models.Model):
author = models.ForeignKey(Author,
to_field="id",
on_delete=models.CASCADE,
related_name='authorarticle_author_id')
company = models.ForeignKey(Company,
to_field="id",
on_delete=models.CASCADE,
related_name='authorarticle_company_id')
article = models.ForeignKey(Article,
to_field="id",
on_delete=models.CASCADE,
related_name='authorarticle_article_id')
class Ganalytics(models.Model):
article = models.ForeignKey(Article,
on_delete=models.CASCADE,
related_name='ganalytics_author_id')
totalview = models.IntegerField()
totalinteractions = models.IntegerField()
class Unsubscribers(models.Model):
email = models.EmailField()
reasonwhy = models.CharField(max_length=90)
I am running pandas to_sql to upload the database:
authorarticlecompanydf.to_sql("ganalytics_authorarticlecompany", con=engine, if_exists="append", index=False)
articledf.to_sql("ganalytics_article",con=engine,if_exists="replace",index=False)
company_name.to_sql("ganalytics_company",con=engine,if_exists="replace",index=False)
authordf.to_sql("ganalytics_author", con=engine,if_exists="replace", index=False)
I am getting this error message:
DETAIL: constraint ganalytics_ganalytic_article_id_d37f2464_fk_ganalytic on table ganalytics_ganalytics depends on table ganalytics_article
constraint ganalytics_authorart_article_id_7f4ff374_fk_ganalytic on table ganalytics_authorarticlecompany depends on table ganalytics_article
HINT: Use DROP ... CASCADE to drop the dependent objects too.
[SQL:
DROP TABLE ganalytics_article]
I have tried to change the on_delete field to different values but it wont help.
What am I doing wrong?
What is the command you are running to get the error? The bottom line is Ganalytics depends on Article via the FK between them. By dropping Article first you are breaking that dependency. You either need to DROP Ganalytics first and then Article or follow the hint DROP ... CASCADE. Though be aware that will DROP Ganalytics also.
UPDATE
Another option would be to drop the FK between the two tables. Then you would not have the dependency issue.

Django query set giving attribute_error when trying to get a set with multiple foreign keys

First, here are my models. Each string has from 1 up to 3 performers, each performer linked to several strings:
class Performer(models.Model) :
name = models.CharField(max_length=60, default="None")
description = models.TextField(null=True, default=None)
class String(models.Model) :
index = models.IntegerField(null=True, default=None)
step = models.IntegerField(null=True, default=None)
process = models.CharField(max_length=100,null=True, default=None)
description = models.TextField(null=True, default=None)
performer = models.ForeignKey(Performer, related_name='performer', on_delete=models.CASCADE, null=True, default=None)
performer2 = models.ForeignKey(Performer, related_name='performer2', on_delete=models.CASCADE, null=True, default=None)
performer3 = models.ForeignKey(Performer, related_name='performer3', on_delete=models.CASCADE, null=True, default=None)
I need to make set of all Strings related to single performer. However, if I try to use string_set to get all Strings where any of the Performer foreign keys point to that string like so:
p = Performer.objects.get(name="smth")# so p is a performer object
s = p.string_set.all()
I get this issue:
AttributeError: 'Performer' object has no attribute 'string_set'
Also I've tryed to use filters with related name, but this gives me the same error. Is there a way to get a _set based off of one of any foreign key fields that all point to the same type?
By providing related_name in each of performer, performer2, performer3 relations you override the default related_name linking from Performer class which would be string_set. Now to get the String for each of these relations you would have to get them like the following:
p = Performer.objects.get(name="smth")# so p is a performer object
p.performer.all() #first one which would actually be a queryset
p.performer1.all() #second one which would actually be a queryset
p.performer2.all() #third one which would actually be a queryset
This would be true only if you have single String and single Performer related to each other but you should keep in mind that query like p.performer1.all() can actually return 2 or more String objects which would have a relation with this one Performer. This would make things even more cumbersome.
Keep in mind that the ForeignKey creates one-to-many relation...
The models structure you provide would have issues with doing filtering you want. The better model design would look like the following:
class Performer(models.Model) :
name = models.CharField(max_length=60, default="None")
description = models.TextField(null=True, default=None)
strings = models.ManyToManyField(String, related_name='performers')
class String(models.Model) :
index = models.IntegerField(null=True, default=None)
step = models.IntegerField(null=True, default=None)
process = models.CharField(max_length=100,null=True, default=None)
description = models.TextField(null=True, default=None)
This design would allow you to execute:
p = Performer.objects.get(name="smth")# so p is a performer object
s = p.strings.all()

Django get_or_create trying to create row, throwing IntegrityError?

I'm working in Django 1.7 and Postgres, and using the ORM to create some new rows. I am using get_or_create as follows:
p, created = Practice.objects.get_or_create(
code=row[1],
name=row[2],
address1=row[3],
address2=row[4],
address3=row[5],
address4=row[6],
postcode=row[7]
)
But when I try to run this I get:
django.db.utils.IntegrityError: duplicate key value violates unique constraint
DETAIL: Key (code)=(A82057) already exists
What's this about? I thought the point of get_or_create was to only try to create new rows if they didn't already exist.
My model looks like this:
class Practice(TimeStampedModel):
code = models.CharField(max_length=6, primary_key=True, db_index=True)
name = models.CharField(max_length=200)
address1 = models.CharField(max_length=200, null=True, blank=True)
address2 = models.CharField(max_length=200, null=True, blank=True)
address3 = models.CharField(max_length=200, null=True, blank=True)
address4 = models.CharField(max_length=200, null=True, blank=True)
postcode = models.CharField(max_length=9, null=True, blank=True)
def __str__(self):
return self.name
class Meta:
app_label = 'frontend'
ordering = ['name']
Is it something to do with the fact that I've set a manual primary key? I can't see anything in the Django docs about this restriction.
get_or_create attempts to do a get with all of the parameters you pass, not just the PK. So if there is an object with a matching PK but a different postcode, for example, the get will fail so a create will be attempted - but, since you have a manual PK, it will try to create a duplicate one using the data you have passed.
Generally speaking using a non-autoincrementing PK is a bad idea. But if you are just trying to look up against the PK only, use the defaults argument:
p, created = Practice.objects.get_or_create(
code=row[1],
defaults={
'name': row[2],
'address1': row[3],
'address2': row[4],
'address3': row[5],
'address4': row[6],
'postcode': row[7]
})

django prefetch_related not working

I am trying to export all my database with a prefetch_related but I only get data from the main model.
My models:
class GvtCompoModel(models.Model):
gvtCompo= models.CharField(max_length=1000, blank=False, null=False)
...
class ActsIdsModel(models.Model):
year = models.IntegerField(max_length=4, blank=False, null=False)
...
class RespProposModel(models.Model):
respPropos=models.CharField(max_length=50, unique=True)
nationResp = models.ForeignKey('NationRespModel', blank=True, null=True, default=None)
nationalPartyResp = models.ForeignKey('NationalPartyRespModel', blank=True, null=True, default=None)
euGroupResp = models.ForeignKey('EUGroupRespModel', blank=True, null=True, default=None)
class ActsInfoModel(models.Model):
#id of the act
actId = models.OneToOneField(ActsIdsModel, primary_key=True)
respProposId1=models.ForeignKey('RespProposModel', related_name='respProposId1', blank=True, null=True, default=None)
respProposId2=models.ForeignKey('RespProposModel', related_name='respProposId2', blank=True, null=True, default=None)
respProposId3=models.ForeignKey('RespProposModel', related_name='respProposId3', blank=True, null=True, default=None)
gvtCompo= models.ManyToManyField(GvtCompoModel)
My view:
dumpDB=ActsInfoModel.objects.all().prefetch_related("actId", "respProposId1", "respProposId2", "respProposId3", "gvtCompo")
for act in dumpDB.values():
for field in act:
print "dumpDB field", field
When I display "field", I see the fields from ActsInfoModel ONLY, the starting model. Is it normal?
You haven't understood the arguments to prefetch_related. It's not a list of fields, but a list of models.
(Note that your field naming convention is also very misleading - respProposId1 and actId are not IDs, but actual instances of the models. Django has created an underlying field in each case by appending _id, so the db columns are respProposId1_id and actId_id. You should just call the fields resp_propos1 and resp_propos2 - also note that normal style is lower_case_with_underscore, not capWords.)
It is normal, that you are seeing fields from ActsInfoModel only. You can access related models via dot notation, like:
acts = ActsInfoModel.objects.all().prefetch_related("actId", "respProposId1", "respProposId2", "respProposId3", "gvtCompo")
for act in acts:
print act.respProposId1.respPropos
Related models are already prefetched, so it won't produce any additional queries. FYI, quote from docs:
Returns a QuerySet that will automatically retrieve, in a single
batch, related objects for each of the specified lookups.

Django models: Why the name clash?

Firstly, I know how to fix the problem, I'm just trying to understand why it's occuring. The error message:
users.profile: Reverse query name for field 'address' clashes with related field 'Address.profile'. Add a related_name a
rgument to the definition for 'address'.
And the code:
class Address(models.Model):
country = fields.CountryField(default='CA')
province = fields.CAProvinceField()
city = models.CharField(max_length=80)
postal_code = models.CharField(max_length=6)
street1 = models.CharField(max_length=80)
street2 = models.CharField(max_length=80, blank=True, null=True)
street3 = models.CharField(max_length=80, blank=True, null=True)
class Profile(Address):
user = models.ForeignKey(User, unique=True, related_name='profile')
primary_phone = models.CharField(max_length=20)
address = models.ForeignKey(Address, unique=True)
If I understand correctly, this line:
address = models.ForeignKey(Address, unique=True)
Will cause an attribute to be added to the Address class with the name profile. What's creating the other "profile" name?
What if I don't need a reverse name? Is there a way to disable it? Addresses are used for a dozen things, so most of the reverse relationships will be blank anyway.
Is there a way to copy the address fields into the model rather than having a separate table for addresses? Without Python inheritance (this doesn't make sense, and if an Model has 2 addresses, it doesn't work).
in the django docs it says:
If you'd prefer Django didn't create a backwards relation, set related_name to '+'. For example, this will ensure that the User model won't get a backwards relation to this model:
user = models.ForeignKey(User, related_name='+')
but I never tried it myself....
I'm not sure where the errant profile field is coming from… But one way to find out would be: temporary remove address = models.ForeignKey(…) from Profile, ./manage.py shell, from ... import Address then see what Address.profile will tell you.
I don't think there is any official way to inherit only the fields from some other Model without using inheritance… But you could fake it like this (where SourceModel is, eg, Address and TargetModel is, eg, Profile):
for field in SourceModel._meta.fields:
TargetModel.add_to_class(field.name, copy.deepcopy(field))
(this is coming from Django's ModelBase __new__ implementation)
I don't think it's possible to disable the reverse name.
I've just done a quick grep over the code and it doesn't look like there is any logic which will bypass setting up the related_name field on the related model.
For Example: Add just '+'
class GeneralConfiguration(models.Model):
created_at = models.DateTimeField(editable=False, default=settings.DEFAULT_DATE)
updated_at = models.DateTimeField(editable=False, default=settings.DEFAULT_DATE)
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.PROTECT, related_name='+')
updated_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.PROTECT, related_name='+')