Custom sql for Django model - python

A bit of background...
I'm trying to create a custom auth backend and extend the user model. I'm using the following as a blue print:
blog post by Scott Barnham
For whatever reason, the ORM is generating invalid sql. It seems to want to do a inner join back to itself and it's failing because it can't find a field named user_ptr_id for the join.
If you do a search for this, it seems that I might not be the only one. And there is actually a reference to this in a comment on the blog post above. But, I can't seem to fix it.
It seems like I should be able to override the SQL that is getting generated. Is that correct? From what I can tell, it seem like I might do this with a custom Object manager. Correct?
However, I can't seem to find a good example of what I want to do. Everything that I see is wanting to inherit and chain them. That's not really what I want to do. I sort of just want to say something like:
hey Django! on a select, use this SQL statement. etc
Is this possible? Maybe my "googlin'" is off today, but I can't seem to find it. That leads me to believe I'm using wrong terms or something.
Please note: I'm using Django 1.3.1 with Python 2.6.5 and PostgreSQL 9.1

David,
Yes, you can override the behavior of a model by implementing an overriding Manager in the object. I found a great blog by Greg Allard on A Django Model Manager for Soft Deleting Records which runs through a soft delete, to set a field deleted to True/False and only show objects that are not deleted, or all with deleted objects.
With that in mind, I would think you could override your object's all(), or filter() methods to get what you want. As an aside, everytime I have used a pointer, "ptr" is evident in the name of the field, it is because of class inheritance. For example, class Animal():..., class Man(Animal): Man extends or is a subclass of Animal. In the database, the Man table will have an animal_ptr_id which "extends" the animal table's tuple with that id as a Man with ANIMAL fields and MAN fields JOINed.

Related

Benefits of foreign key over integerfield

I'm not sure if this is an appropriate question here. I know the answer but I don't really know why, and I need proof when I raise this to my team.
We have a number of Blog Posts on a Django Site. It's possible to "clone" one of those blog posts to copy it to another site. The way the current developer did that was to take the pk of the original post and store it as an IntegerField on the cloned post as clone_source. Therefore to get a story's clones, we do:
clones = BlogPost.all_sites.filter(clone_source=pk)
It seems to me that this would be much better structured as a foreign key relationship.
Am I right? Why or why not?
Deleted objects
If you ever decided to delete the original post, you'd need a separate query to handle whatever you expect to do with the cloned posts instead of using the on_delete kwarg of a FK.
Its an extra query
As noted in the comments, foreign keys allow you to traverse the relationships directly through the ORM relationship methods.
Data structure visualisation tools
These won't be able to traverse any further down from an integer field since it will believe it is at a leaf node.
Throughout all of this though, the elephant in the room is that a "clone" is still just duplicated data so I wonder why you don't just let a blog post be referenced more than once then you don't need to worry about how you store clones.

Global Variables in Django Admin Site

This was my original question, but it was not answered and so I thought Id post again with some of the strategies that I have tried, and be a little more specific.
I want to create a dynamic admin site, that based on if the field is blank or not will show that field. So I have a model that has a set number of fields, but for each individual entry will not contain all of the fields in my model and I want to exclude based on if that field is blank. My project is about bridges, and so to put it in practical terms I have a model that has every bridge part in it (this roughly is equivalent to 100), but each individual bridge (mapped to each unique brkey) will not have all 100 bridge parts. And so, I can prepopulate all of the fields it does have, but then the admin site has 100 other fields, and I would like to not display those fields that were not used on my admin site for that specific bridge, but those fields will differ with pretty much every bridge.
Like I said before, I have a unique bridge identifier(a unique 15 digit string), that correlates to each bridge, and then all of the various different variables that describe the bridge.
I have it set up now that the user will go to a url with the unique bridgekey and then this will create an entry of that bridge. So (as i am testing on my local machine) it would be like localhost/home/brkey and that code in my views.py that corresponds to that url is
Is this a final route that I have to take? I am very new to JavaScript and so I do not want to take this route but I will if I have to. Also does Django use Javascript in anyway that is syntactically different? If so I cannot find any Django documentation on incorporating Javascript into my admin site.
A final option that I have exhausted is to use global variables. Instead of having the url that creates the entry in my Views.py, I placed it in my admins.py, and had my modelAdmin class in there as well, so like this.
admins.py
-set up global variable
bridgekey_unique = " "
If I can find a way to either pass that unique bridge key to my modelAdmin class, or figure out if that said field is blank because the bridge doesnt have that part, I will be able to achieve what I want without using Javascript. I have tried a lot of variations of all two of theses strategies to no avail, but have not tried the JavaScript idea as I dont really know any javascript at all.
Sorry for the lengthy post, but people said I wasnt specific enough. Any help would be greatly appreciated.
I didn't read all of that - sorry, there's too much. But I did notice your comment that you expect to access in your modeladmin definition a variable that you set in your view. That can't possibly work.
Anything at class level is always executed when the module containing the class is first imported. That is when the server process starts up, so there is no possible way anything done in the view can have happened yet.
You almost never want to have any logic at class level. You need to put it in methods, which are called at the relevant time. In this case, you probably need to use the get_fields method.
Edit
Looking further up at your attempt at a get_fields method, I can't see at all what you are trying to do here. 'prestressed_concrete_deck' is a literal string, and could never be None, so neither of your conditions can ever be true. And as to your question about what the parameters are, the documentation for that method explains clearly that obj is the object being edited.

Creating a dynamic ORM resource in tastypie

I'm looking to create a dynamic resource in tastypie. Basically the idea is that there are a lot of models to hook up, so this may help save time with the standard no-frills resources.
I have most of this working, however I'm having trouble with the related fields being populated. I'm overriding the constructor for a class that inherits from ModelResource, and in this constructor I'm attempting to set the tastypie relationships. However when I review my resource the data is not being populated.
setattr(self, field, fields.ForeignKey(class_thing, attribute=field, full=True))
Basically I'm using setattr in the constructor to try and hook up what the relationship should be. If I'm goofing off with the instance I can see this object is getting created but the resource output is not changing. Is anyone familiar enough with tastypie/doing something like this to give me a clue?
Thanks for your time.
Edit: Nevermind, just overrode dehydrate and did this from there.
Rather than go through the constructor (which is messy since tastypie/django does stuff there anyway) I did this through a dehydrate override which is kind of designed to do this.
The bundle.obj has all the associated data there, so basically I just serialized the related objects and add them to the bundle.data dictionary before returning the bundle. Seemed cleaner and worked like a charm.

Specifying model Meta data through decorators (django)

The problem: I wish to use Postgres Schemas to separate the tables of different parts of my django app at database level.
Aside
You can skip this section, but I think it's helpful to add context to these things. My app is working on a database of existing data (stored in the public schema, helpfully), which it's very important I don't modify. As such, I want to separate "my" data into a separate schema (to which django will be given read/write/play in the sand access), while restricting access to the public schema to read-only. I originally tried to solve this by separating my data out into a separate database and using database routing, but it turns out (if I'd only read the documentation) that django doesn't support cross database dependencies (which is fair enough I suppose), and my models have foreign keys into the read-only data.
The meat
There exists a workaround for Django's lack of schema support (which you can read about here) which is to specify the db_table attribute in your model's meta, like so:
class MyModel(models.Model):
attribute1 = models.CharField()
#Fool django into using the schema
class Meta:
db_table = 'schema_name\".\"table_name'
This is great, but I didn't really want to have to write this for every single model in my app - for a start, it doesn't seem pythonic, and also there's every chance of me forgetting when I have to add a new model.
My solution was the following snippet:
def SchemaBasedModel(cls):
class Meta:
db_table = '%s\".\"%s' % (schema_name, cls.__name__)
cls.Meta = Meta
return cls
#SchemaBasedModel
class MyModel(models.Model):
attribute1 = models.CharField()
...
When I then run python manage.py shell I get the following:
>>> from myapp import models
>>> myModel = models.MyModel
>>> myModel.Meta.db_table
'myschema"."mymodel'
>>>
"Looks good to me," I thought. I then ran: python manage.py sqlall myapp. Sadly, this yielded the original table names - that is, the table names as they were before I applied this meta info. When I went back and applied the meta info "by hand" (i.e. by adding Meta inner classes to all my models), things were as expected (new table names).
I was hoping somebody could enlighten me as to what was going on here? Or, more usefully, what's the "right" way to do this? I thought the decorator pattern I've talked about here would be just the ticket for this problem, but apparently it's a non-starter. How can I quickly and easily apply this meta info to all my models, without typing it out every single time?
Edit: Perhaps I was a little unclear when I asked this - I'm as interested in know what's "actually going on" (i.e. why things aren't working the way I thought they would - what did I misunderstand here?) as how to solve my problem (clear separation of "my" data from legacy data, preferably on a schema level - but it's not the end of the world if I have to dump everything into the public schema and manage permissions on a per-table basis).
Second Edit: The accepted answer doesn't necessarily tell me what I really want to know, but it is probably the right solution for the actual problem. Short answer: don't do this.
I didn't really want to have to write this for every single model in my app -
for a start, it doesn't seem pythonic,
That's false. Some things have to be written down explicitly. "Explicit is better than Implicit".
and also there's every chance of me forgetting when I have to add a new model
That's false, also.
You won't "forget".
Bottom Line: Don't mess with this kind of thing. Simply include the 2 lines of code explicitly where necessary.
You don't have that many tables.
You won't forget.
Also, be sure to use DB permissions. Grant SELECT permission only on your "legacy" tables (the tables you don't want to write to). Then you can't write to them.

Django Data Migration, using South with Inheritance

We are migrating the data in several instances of our Django project to a new schema.
The old schema had:
class Group(models.Model)
class User(models.Model)
And the new schema has:
class AccessEntity(models.Model)
class Group(AccessEntity)
class User(AccessEntity)
We are trying to use South to do a data migration for these groups and users. http://south.aeracode.org/docs/tutorial/part3.html
I've gathered that I'll need to use forward rules to specify how to migrate the Users but there are a few issues I've run up against.
The main issue is how to keep the ID of the User/Group the same if I were to create a new User object that extends the AccessEntity class.
Users & Groups are referenced to by objects they own or are assigned to them. If I change their ID that information would be lost. Is there a way of keeping the same ID for an object even though I need it to now extend from AccessEntity?
not sure if I understand your question correctly, but the way multi-table model inheritance works ist that there will be an implicit one-to-one field in the parent and child models. So both User and Group would use an ID field of AccessEntity if AccessEntity has such a field.
If you create AccessEntity such that it has a field ID you can assign to it when you write a forward (data)-migration. That way you can make sure that the AccessEntity gets the right ID.
If have written a longer multi-table inheritance tutorial and it looks like you are trying to do something similar.
And furthermore the answer to this question could also be helpful (note that some things in the original answer does will not work in new versions of django / south, see my tutorial / the answer at the bottom for changes).
What might be a problem in your case is that if you already have data in both User and Groups and the id field is auto-generated, IDs likely not be distinct, e.g. you are likely going to have both a User and a Group with ID==1. This could be a problem if you want to query based on those IDs and of course ID could not be a primary key for AccessEntity then.

Categories