I'm writing a gallery field. The field subclasses ManyToManyField and adds its own ajax widget and stuff. I want to make this solution as compact as possible (I mean - I want to write as little code to reimplement this in another projects if possible).
I've decided to create an intermediate table (that provides a 'through' parameter to ManyToManyField), which will hold ordering information:
class IntermediateModel(models.Model):
from_content_type = models.ForeignKey(ContentType)
from_object_id = models.PositiveIntegerField()
from_content_object = generic.GenericForeignKey('from_content_type', 'from_object_id')
to_content_type = models.ForeignKey(ContentType)
to_object_id = models.PositiveIntegerField()
to_content_object = generic.GenericForeignKey('to_content_type', 'to_object_id')
order = models.PositiveIntegerField()
The following questions arise:
Is it possible to have a "through" model for m2m in django having both foreign keys pointing to a generic relations (like the one above)? If so - how to achieve this?
If it's possible to do this - can such model hold generic relations between more than one m2m field? Like: Class <-> Intermediate <-> Student, Gallery <-> Intermediate <-> Photo - both using Intermediate as 'through' model??
EDIT: just tested - I can ;) Can I use abstract classes with 'through' tables? I figured out - if the above mentioned complex scenario won't work I could just create two abstract classes that provide ordering and some other stuff and then always create normal subclasses to actually build some relations :)
If the difference between the intermediate models is just the way you handle them, maybe you just need to use it with "proxy" models. I mean, using Django model subclassing with a Meta option called "proxy" as True. This way, you can handle them separately, but having them stored in the same database table (if that is an option to your needs).
Read this. Maybe that is what you want. Instead of having 2 database tables with the same structure, you can have 1 table with 2 (or more) ways of accessing and handling them.
Related
To create a generic versioning for my models I have created a model Version:
class Version(models.Model):
version_number = models.IntegerField()
...
and an abstract models VersionedModel
class VersionedModel(models.Model):
...
versions = models.ManyToManyField(Version, related_name="%(app_label)s_%(class)s")
class Meta:
abstract = True
everything works but I would like to have the database check that each version is assigned to one and only one object.
What I can think of is to modify the field versions and use through to create and intermediate table where I could then use a unique index on version_id, but I am just back to the initial problem of creating a ForeingKey field to an abstract model.
I don't like using GenericForeignKey as they create all sort of headaches when working with graphene. I wondered if there is a way to model this in a different way, or to use some constraint I am not aware of, so that the database can provide completeness and uniqueness on its own.
I'm trying to design an Inventory table on a database (Django + PostgreSQL) and I came to a doubt as to which is the most "correct" way to implement multiple polymorphic relationships with other tables.
Basically, each entry needs to have an input field which can refer to any of a set of tables: for example, a product could have been purchased (and therefore this field should be a Foreign Key for the PurchaseOrder table), or it could have been produced/manufactured (i.e. ProductionOrder). Similarly, it will eventually have an output which could, for instance, refer to a SalesOrder (if the product is sold) or another ProductionOrder (if it is used to manufacture another thing).
Of course a single Foreign Key field cannot refer to entries in different tables, so what is the best way to achieve this? I read answers to similar questions, but the suggestions didn't seem to be well-suited for a case like this. Creating intermediate tables doesn't seem appropiate since sales and production orders don't belong to the same "superset", at least to me.
My current thought is to have as many fields as possible options (i.e. idProductionOrder, idSalesOrder) for both inputs and outputs, and add a -NAND- constraint to avoid both fields to contain data simultaneously. I see this could be a practical solution, but perhaps not a very neat one. Is there a better approach?
I think what you are looking for is the GenericForeignKey field. This can point to different models. Here an example based on your input:
class YourModel(models.Model):
limit = (models.Q(app_label = 'YourApp', model = 'ProductionOrder') |
models.Q(app_label = 'YourApp', model = 'SalesOrder ') |
models.Q(app_label = 'YourApp',model = 'ProductionOrder '))
content_type = models.ForeignKey(ContentType, limit_choices_to = limit)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
See the docu
If you want them to integrate nicely into the admin you should also consider using django-smart-selects.
If I have many Django models - all with the following common fields: -
created_by = models.ForeignKey(User)
modified_by = models.ForeignKey(User)
and I would like to query all models to find out which objects were created or modified by a specific user, is there a sane way to go about achieving this?
Or do I have to fall back to doing ModelA.objects.filter(created_by=userone) ModelB.objects.filter(created_by=userone) and so on?
I should mention that in reality these fields are in an abstract base class from which all other models inherit them. But let's pretend I didn't tell you what I just told you about the abstract base class, is there still a way to do what I want to do?
to expand on what akshar raaj is saying, you can simplify the code by having an array of models.
query_models = [ModelA, ModelB, ModelC, ModelD]
for query_model in query_models:
results = query_model.objects.filter(created_by=userone)
if len(results) > 0:
print '%s has it!!!' % query_model.__name__
You will have to operate on one model at a time. Djano ORM managers internally make use of a class called Queyset which talks with database and this class QuerySet instances have a model attribute on them which is synonymous to a single table. So, they can only talk with one table, though join operations are possible. But for your scenario you will have to make multiple calls to db.
orm is just an abstraction over database, think if you can do this directly with sql.
At sql:
select val from test union select val from test2 union......;
So there will be a lot of unions since you say you have a lot of models so doesn't make much sense to accomplish this with a single db call.
I think this is best explained with some simple model code (I'm writing this from scratch so possible syntax issues - unimportant here):
class Car(models.Model)
make = models.CharField(...)
model = models.CharField(...)
class StatisticType(models.Model):
name = models.CharField(...)
class Statistic(models.Model)
car = models.ForeignKey('Car')
stype = models.ForeignKey('StatisticType')
data = models.CharField(...)
class Meta:
unique_together = (('car', 'stype'),)
We have a car with some hard-coded stats and we have some database controlled statistics. I might add Colours, Wheel Size, etc. The point is it's editable from the admin so neither I or the client need to climb through the data, but it's limited so users can only pick one of each stat (you can't define "Colours" twice).
So I'm trying to write the data input form for this now and I want a list of optional ModelForms that I can chuck on the page. I've got the simplest ModelForm possible:
class StatisticForm(forms.ModelForm):
class Meta:
model = Statistic
The tricky part (in my head) is generating an instance of this ModelForm for each StatisticType, regardless of it existing yet. That is to say if a Car object doesn't have a Colour assigned to it, the form still shows. Similarly, if it does, that instance of a Statistic is loaded in the ModelForm.
In my view, how do I generate a list of these things, regardless of there being a pre-existing instance of any given Statistic?
This seems like it should be a stupidly simple thing to do but it's late on Friday and everything looks skwonky.
Sounds like you might want to leverage an inline model formset factory.
That would allow you to create as many instances of your Statistic object as you need. If you're needing to create instances of your StatisticType on the fly, that's a bit different.
When Django instantiates forms, for a foreign key, m2m or choice field, it will only accept choices that it deems "valid", and will complain if you add a choice using JavaScript that doesn't exist in a related model or set of choices server-side.
So, if you need to make StatisticTypes on the fly, and then populate formset instances with this new value, I would suggest using Knockout.js. It's very good at keeping lots of DOM elements in sync when data changes.
Does select_related work for GenericRelation relations, or is there a reasonable alternative? At the moment Django's doing individual sql calls for each item in my queryset, and I'd like to avoid that using something like select_related.
class Claim(models.Model):
proof = generic.GenericRelation(Proof)
class Proof(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
I'm selecting a bunch of Claims, and I'd like the related Proofs to be pulled in instead of queried individually.
There isn't a built-in way to do this. But I've posted a technique for simulating select_related on generic relations on my blog.
Blog content summarized:
We can use Django's _content_object_cache field to essentially create our own select_related for generic relations.
generics = {}
for item in queryset:
generics.setdefault(item.content_type_id, set()).add(item.object_id)
content_types = ContentType.objects.in_bulk(generics.keys())
relations = {}
for ct, fk_list in generics.items():
ct_model = content_types[ct].model_class()
relations[ct] = ct_model.objects.in_bulk(list(fk_list))
for item in queryset:
setattr(item, '_content_object_cache',
relations[item.content_type_id][item.object_id])
Here we get all the different content types used by the relationships
in the queryset, and the set of distinct object IDs for each one, then
use the built-in in_bulk manager method to get all the content types
at once in a nice ready-to-use dictionary keyed by ID. Then, we do one
query per content type, again using in_bulk, to get all the actual
object.
Finally, we simply set the relevant object to the
_content_object_cache field of the source item. The reason we do this is that this is the attribute that Django would check, and populate if
necessary, if you called x.content_object directly. By pre-populating
it, we're ensuring that Django will never need to call the individual
lookup - in effect what we're doing is implementing a kind of
select_related() for generic relations.
Looks like select_related and GRs don't work together. I guess you could write some kind of accessor for Claim that gets them all via the same query. This post gives you some pointers on raw SQL to get generic objects, if you need them
you can use .extra() function to manually extract fields :
Claims.filter(proof__filteryouwant=valueyouwant).extra(select={'field_to_pull':'proof_proof.field_to_pull'})
The .filter() will do the join, the .extra() will pull a field.
proof_proof is the SQL table name for Proof model.
If you need more than one field, specify each of them in the dictionnary.