django model inheritance & FK, could not create unique index - django

I want to be able to have a foreign key to a parent class, thereby allowing queries of the children classes as well. All other solutions are nightmarish.
I have tried to make this (Destination is also a parent class that has a # of children classes I want to relate to):
class Destination(PolymorphicModel)
class Account(Destination)
class Organization(Destination)
class Person(Destination)
class Transaction(models.Model)
destination = models.ForeignKey(Destination, verbose_name="Destination", null=True, blank=True,
related_name="CompletedTransaction_Destination_FK")
I am referencing destination in other places as well.
This is the error message I get when I try to migrate:
psycopg2.IntegrityError: could not create unique index "baseapp_organization_organization_destination_ptr_id_key"
DETAIL: Key (organization_destination_ptr_id)=(1) is duplicated.
I would love it if I could make the destination class
abstract = True
but then I can't have a foreign key. I need to be able to choose all of those destinations, and they need to remain distinct, real models in the database.
I have also tried GenericRelations, but that proved to be a nightmare as I said earlier.
It feels like I could just get around this error somehow though, any help?

The solution, and I'm guessing it would apply to other errors where the index could not be created, was to wipe the database an delete all the migrations. It was a pain to be sure, but now I can do:
destinations = Destination.objects.all()
and it will give me all the objects, as according to django polymorphic

Related

Request changes/additions to data in another app

To make a long story short, I am very grateful for hints on how I can accomplish the following. I have an app A that I don't want to change. I have an app B that needs to select data from A or to request data to be added/changed if necessary. Think of B as an app to suggest data that should end in A only after review/approval. By itself, B is pretty useless. Furthermore, a significant amount of what B's users will enter needs to be rejected. That's why I want A to be protected so to say.
# in app A
class Some_A_Model(models.Model): #e.g., think artist
some_value = models.TextField()
# in app B
class MyCustomField(models.ForeignKey):
...
class Some_B_Model(models.Model): # e.g., think personal preference
best_A = MyCustomField('Some_A_Model')
worst_A = MyCustomField('Some_A_Model')
how_many_times_I_like_the one_better_than_the_other = models.FloatField()
class Mediator(models.Model):
# already exists: generic foreign key
content_type = models.ForeignKey(
ContentType,
on_delete=models.CASCADE
)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey(
'content_type',
'object_id'
)
#does not yet exist or needs to be changed:
add_or_change = PickledObjectField()
Django should create a form for Some_B_Model where I can select instances of Some_A_Model for best_A and worst_A, respectively; if, however, my intended best_A is not yet in A's database, I want to be able to request this item to be added. And if I find worst_A is present but has a typo, I want to be able to request this item to be corrected. An editor should be required to review/edit the data entered in B and either reject or release all the associated changes to A's database as an atomic transaction. I don't want any garbage in A and refrain from adding some status field to track what is considered valid, requiring filtering all the time. If it's in A, it must be good.
I figured I need to define a MyCustomField, which could be a customized ForeignKey. In addition, I need some intermediate model ('mediator' maybe?) that MyCustomField would actually be pointing to and that can hold a (generic) ForeignKey to the item I selected, and a pickled instance of the item I would like to see added to A's database (e.g., a pickled, unsaved instance of Some_A_model), or both to request a change. Note that I consider using PickledObjectField from 'django-picklefield', but this is not a must.
As there is only some documentation on custom model fields but not on the further steps regarding form fields and widgets, it seems I have to dig through django's source to find out how to tie my intended functionality into its magic. That's where I am hoping for some comments and hints. Does my plan sound reasonable to you? Is this a known pattern, and if so, what is it called? Maybe someone has already done this or there is a plugin I could look into? What alternatives would you consider?
Many thanks in advance!
Best regards

django migrate from URLField to foreign key without south

I have a model that have a URLField field and I need to make a migration that turns this field into a foreign key, where the string is a unique field of the other object, and, if the object does not exist create it.
for example, turn this:
class Event_UserVisit(Event_Base):
dest_url = models.URLField(max_length=1000)
into this:
class Event_UserVisit(Event_Base):
dest_url = models.ForeignKey(Page)
I've never done a manual migration like this and didn't find any tutorial or instructions to do something like this.
obviously doing a naive migration return errors like this:
django.db.utils.ProgrammingError: column "source_url_id" cannot be cast automatically to type integer
what's the best approach to do it?
note: I need to do this on a production db with lots of data, so I can't have long down time and can't lose any data.
thanks! :)
I don't think you can do this at the ORM level in one go (unless someone corrects me) You would need create a new FK maybe dest_url2 run migrations, then write a script to migrate the data. Next,delete dest_url again run migrations. Then rename dest_url2 to dest_url Django will detect the name change here.
However, I don't understand why you are linking an FK ID on page to a field called dest_url. A PK in Page should not be a 1000 max URL! It has no order and would make indexing hard and slow down your app. It would make more sense do have...
class Event_UserVisit(Event_Base):
page = models.ForeignKey(Page, related_name='eventvisits')
The I assume Page looks something like this...
class Page(models.Model):
dest_url = models.URLField(max_length=1000)

Before syncdb, delete field from standard Django model

This is a follow-up question on Delete field from standard Django model. In short: a field can be dynamically deleted from a model that is already created, in this case the field User.email . So field email would be deleted from User without changing the code for User. See code below for example.
I can dynamically delete a a field from a model(1), but that happens when the server starts and is undone when it exists. Since syncdb doesn't require the server to be running, and generally seems to ignore the deletion code (somehow), this approach doesn't prevent the field from appearing in the database(2).
Is there a way to do delete the field from the model (without changing the file it's in, as it's a Django model), in a way that also makes it not appear in the database?
Thanks in advance!
Mark
EDIT: I problem is not that I am deleting the text "m = models.IntegerField()" from the model file and want the field removed from the database. The problem is that I am using the code below to remove a field from a model that has already been declared in another file. I do not think that creating a migration with South for every time I run syncdb is a solution(3).
Additional information:
1) Currently, the code is in models.py, but I suppose Where to put Django startup code? works.
2) I can delete it on post_syncdb signal with custom query, but I hope for something more elegant... Or elegant at all, more accurately.
3) If it even works at all, because obviously syncdb is still seeing the 'removed' field), so I think South would to as it's still somehow there.
This is the code (models.py):
class A(models.Model):
m = models.IntegerField()
for i, f in enumerate(A._meta.fields):
if f.name == 'm':
del A._meta.fields[i]
break
class B(A):
n = models.IntegerField()
for i, f in enumerate(B._meta.fields):
if f.name == 'm':
del B._meta.fields[i]
break
EDIT: I checked (with print) and the deletion code is executed on syncdb. It is executed before tables are created
django does a lot of meta class magic and i would guess that the meta class is responsible for defining the database table to back your model. Subsequently just deleting the field is not enough to alter the generated table.
as several people have pointed out, south is the way to deal with these problems.

How should I define models that will be owned by many different models?

Disclaimer: Django models sometimes confuse the heck out of me.
I have the following situation, which I'll express in JPA as it makes the most sense to me:
#Entity
public class Address {
/* fields omitted for brevity */
}
#Entity
public class User {
#OneToMany
private List<Address> addresses;
}
#Entity
public class Location {
#OneToOne
private Address address;
}
#Entity
public class MultiEvent {
#OneToMany
private List<Address> addresses;
}
How would I express the following in Django:
One User can have many Addresses, but Addresses don't need to have any reference back to their owner.
One Location has one Address, but again, the Address doesn't need to have any reference back to its owner.
Similar to the first scenario, one MultiEvent can have many Addresses, but each Address doesn't need to reference the MultiEvent that it belongs to.
How can I create the same scenario in Django? I get confused easily as there isn't a OneToMany field nor a ManyToOne field in Django, only the ForeignKey field. I also can't find the complete documentation for all accepted constructor parameters defined by ForeignKey which might explain why I'm feeling a bit lost.
One User can have many Addresses, but Addresses don't need to have any reference back to their owner.
You will need a foreign key in Address, pointing to a User. Give it a related_name so that you can refer to it in an intuitive way. Something like this,
class Address(models.Model):
user = models.ForeignKey(User, related_name='addresses')
u = User()
for a in u.addresses.all():
print a # loop through all addresses
One Location has one Address, but again, the Address doesn't need to have any reference back to its owner.
Use a One to one relationship, the back reference you get for free!
Similar to the first scenario, one MultiEvent can have many Addresses, but each Address doesn't need to reference the MultiEvent that it belongs to.
Same as the first, ForeignKey in Address to 'MultiEvent`
In django 'oneToMany' works out to ForeignKey.
I find that using related names can help ease confusion in this sense:
#models.py
class myModel(Model):
other_item = field(...)
class otherModel(Model):
mymodel = ForeignKey(myModel, related_name="otherModels")
#then you can access all the otherModels as:
#the orm adds this attribute to any instantiated models of myModel
#its the equivalent of otherModel.objects.filter(mymodel=model_instance)
myModelInstance.otherModels.all()
Unfortunately this means you always have to declare the relation in the "one" of the oneToMany relationship. But at the end of the day is proper database design.

Assigning values to a query result already set up with a foreign key

I have a database of exhibition listings related by foreign key to a database of venues where they take place. Django templates access the venue information in the query results through listing.venue.name, listing.venue.url, and so on.
However, some exhibitions take place in temporary venues, and that information is stored in the same database, in what would be listing.temp_venue_url and such. Because it seems wasteful and sad to put conditionals all over the templates, I want to move the info for temporary venues to where the templates are expecting info for regular venues. This didn't work:
def transfer_temp_values(listings):
for listing in listings:
if listing.temp_venue:
listing.venue = Venue
listing.venue.name = listing.temp_venue
listing.venue.url = listing.temp_venue_url
listing.venue.state = listing.temp_venue_state
listing.venue.location = listing.temp_venue_location
The error surprised me:
ValueError at /[...]/
Cannot assign "<class 'myproject.gsa.models.Venue'>": "Exhibition.venue" must be a "Venue" instance.
I rather thought it was. How do I go about accomplishing this?
The error message is because you have assigned the class Venue to the listing, rather than an instance of it. You need to call the class to get an instance:
listing.venue = Venue()