Return QuerySet from a RawQuerySet - django

I am trying to create a queryset from a rawqueryset, but the changelist is always saying Something's wrong with your database installation. Make sure the appropriate database tables have been created, and make sure the database is readable by the appropriate user.
This is my attempt (is a simple query, but it will became more complex and I need a raw SQL query):
class MyModelAdmin(admin.ModelAdmin):
def queryset(self, request):
qs = MyModel.objects.raw('SELECT field1, field2 FROM MyTable)
return qs
Is there any way to show this raw query in my changelist view applying admin.site.register(MyModel, MyModelAdmin) in admin.py?

It's been a while, and versions seem to have changed a lot since then, however you used to be able to simple convert the qs itself to a string or the query attribute contained within the qs, and it would spell out the sql for you.
e.g. sql = str(qs) or sql = str(qs.query)
That being said, django modifies the table names. It's probably not MyTable you're looking for, but appname_my_table. Browse the django core to find out exactly what the naming specification is, or perhaps get it from model_instance._meta.db_name or similar property.
update: ok it seems I misunderstood the question, you don't want to 'print' the queryset to inspect the sql it generates at all, you need the ModelAdmin to pass a RawQuerySet instead of a regular QuerySet to its ChangeView.
Short answer: No, its not going to work that way. They are two very distinct classes.
It looks like they behave the same, because you can iterate them and when you do it turns out to contain proper model instances. However its missing a plethora of other functionality that the ModelAdmin's changeview has come to rely upon over time. I'm not even sure if it actually has a Manager.
The only option that comes to mind, is using either:
Use Model.objects.extra(...) instead of Model.objects.raw(...), so that it returns a proper QuerySet.
Create a view using your database software, Postgres or MySQL, what have you. And map that to a simple django Model.
You can try and recreate all the missing functionality by wrapping the RawQuerySet in a little proxy class that passes everything on to the RawQuerySet and implement the missing methods yourself. I do not recall which those were, probably you need to override __and__ and __or__, provide it with a custom manager, at the very least. I've done this before and its very possible but I guarantee a lot of work, especially if you expect ALL of the usual admin magic to work, think filterspecs, search, inline relationships. Expect to hurt your brain, or learn to live without most of the admins benefits you've come to love.
The thing is, using raw(...) basicly results in being entirely seperated from django's ORM, even though at first glance it fools you into thinking that this is not the case (primarily because its iterator returns proper Model instances). Ofcourse your ModelAdmin's ChangeView has not got the slightest clue of what to do with it.
Kind regards,

You can subclass models.Manager and create a method that executes raw SQL as a subquery in the where clause.
https://gist.github.com/carymrobbins/8477219

Related

Usage of latest() method with field types other than date field (Django)

I have just learned about the latest() method. I went to the django's documentation to find out more about it. In the docs it is written:
latest(field_name=None)
Returns the latest object in the table, by date, using the field_name provided as the date field.
However in the tutorial ,that I am following, this method is used together with field name for models.PositiveIntegerField() field(and the model does not specify get_latest_by). I have been trying to search for explanation and similar use of this method, where the field_name is different than date field.
I have found some information here where it is said that:
...it probably does work with other total-ordered types too, but not sure...
and
It does work with primary keys ...
Also I have found similar case here, where the latest() method is used with id field.
However still I did not find an answer whether it is ok to use this method with something other than date field? Is there any other method which is more appropriate for this kind of task?
Here's the source code for _earliest_or_latest, which powers the latest method. As you can see, it basically uses whatever field name you specify and tries its best to order your lookup by that field at the database level. It does this through the add_ordering method, which is documented in the source code here.
There's nothing fancy at all going on under the hood - Django is just passing an ORDER BY and letting the database try to sort things out. That's why you see inconsistent behavior between database environments, like how SQLite sorts nulls below non-nulls while MySQL and PostgreSQL do the reverse. Django isn't really ordering the queryset, it's the underlying database.
Things like dates, incremented IDs, etc. are easy for databases to order and therefore work well with latest. A UUIDField, on the other hand, probably wouldn't work so well.

Query on a Many to Many relationship using through in Django

I'm new in Django and I'm giving myself a big headhache trying to structure this query.
I have a BaseProfile connected with a OneToOne field to User.
I'm specializing the profile in CustomerProfile connected with a OneToOne field to BaseProfile.
A CustomerProfile has a ManyToMany relationship with other CustomerProfile (so itself) through a RelatedCustomer model.
In the RelatedCustomer I specify the from_customer and to_customer Foreign Keys.
Maybe with an image you can understand better.
My problem:
Given a user.id I need to know all the other user.id of the customers that he is connected to (so passing through from_customer and to_customer):
So basically, first I need to dig from User to RelatedCustomer using reverse lookup, take all the set, and then going back to know the user.id of each customer in the set.
EDIT2:
What I've reached so far:
# This gives me back a customer profile given a user.id (2)
cm = CustomerProfile.objects.get(base_profile__user=2)
# M2M lookup. Given one customer returns all the RelatedCustomer relations
# that he has as a part of the 'from' M2M
cm.from_photographer.all()
Chaining the previous two: given a user.id I obtain a queryset of CustomerRelated relations:
rel = CustomerProfile.objects.get(base_profile__user=2).from_photographer.all()
This gives me back something like:
[<CustomerRelated: from TestCustomer4 to TestCustomer2 >,
<CustomerRelated: from TestCustomer4 to TestCustomer3 >]
Where in this case the user having a user.id=2 is the TestCustomer4.
My question:
So far so good, but now having this set how can I get all the user.id of the to_customer?
That is, how do I get the user.id of TestCustomer2 and TestCustomer3?
Firstly, this is not how you query the database in django. Secondly (since you're learning), it would be good to point out that you can run dbshell to try out different things. And lastly, this kind of problem is described in the documentation.
I am telling you this, because as a beginner, I also felt that it was a little difficult to navigate through the whole thing. The best way to find things is just to use google, and add a django at the end.
I know how you feel, the documentation search sucks, right? Heh, I feel you, that is why you always search the way I described it. Once you get a hang of the documentation, you will feel that the documentation title page is a little more intuitive.
Okay, so now to the answer:
To access a ManyToMany, OneToOne or ForeignKey field, you need to use a __ commonly known as dunder.
So, this is how I would go about doing this. Please note that there are other ways, and potentially better ways of doing this:
thing_I_want = RelatedCustomer.objects.get(to_customer__id=2)
Note, however that if you wanted to get a list of customers you would use filter(). Here is an example (which uses number of purchases as an example):
things_I_want = RelatedCustomer.objects.filter(to_customer__no_of_purchases=16)
Also note that the great thing about filter is that you stack one filter on top of another. You can read more about these features in the documentation link I provide below.
That will get you what you want. Now, you might have more queries regarding this, and how it all works together. Not to fear, please click this documentation link to check it out.
EDIT
Seems like what you want to do can be done by django, but if you want to do it using sql, then that is possible too. For example, SomeModel.objects.raw("SQL_HERE"). The name of the tables are usually <app>_<model>.
However, what you are asking can also be done in django, using the ORM. But it will be tricky.
Ok, as usual whenever you get the answer it always look much more easier than what you were expecting.
I guess this worked for me:
User.objects.filter(base_profile__customer_profile__to_customer__in=
User.objects.get(id=2).base_profile.customer_profile.from_customer.all())
Many thanks to #Games Brainiac

Should I pass a dictionary to my template?

Being a newb I'm trying to work out what belongs where. I've got a ListView to list all users in the system, and it includes a get_queryset method -something along the lines of:
def get_queryset(self):
users = []
for user in User.objects.all():
a_user = {}
a_user['username'] = user.username
a_user['full_name'] = user.get_full_name()
a_user['num_of_friends'] = len(user.friends.all())
a_user['phone_num'] = user.get_profile().phone_num
a_user['has_subscription'] = bool(Subscription.objects.filter(subscriber=self.request.user))
users.append(a_user)
return users
So rather than returning a queryset of users I'm making this dictionary out of various chosen attributes of each user, and what a template designer gets is limited to only what I think they should have.
Is it better practice to instead pass user objects to the template, and let the template writer get whatever they need from them? I suppose the answer is Yes.
But, when it comes to the a_user['has_subscription'] line above, I assume the answer becomes No?
The way you've done it is totally fine. I've found it to be useful to separate my templates from my model by explicitly providing the information needed by the template in the view, which is essentially what you've done. It's a little bit weird to not be returning an actual queryset from a method called get_queryset, but I've also come to the conclusion based on criticisms like this that class-based views as they are currently implemented in Django should be considered a means to an end, as opposed to a dogmatic way of organizing your view code. The abstraction simply isn't as clean as say, the Django ORM.
If you really wanted something a little slicker, you could try using the values method to narrow your queryset, with an annotation to add in the subscription count. But there's probably not much point.
It depends on what you're trying to do with the array 'users'. Someone editing the template can only style and display the data in a certain way. The get_queryset function can provide the data for the template.

django design pattern/best practice: filtering a queryset

I have a page where I'm displaying the results of a queryset to the user.
What i'd like to do is allow the user to click on a link in order to apply a filter.
Currently what I do is have the links pass "get" parameters to the page in order to apply filters. The filters can be references to other models or custom filters (e.g. an unassigned filter)
In order to provide a decent user experience the implementation needs to do a few things
in the view:
check that the filter parameter passed is valid
check what type of filter it is (based on other models or a custom filter) in order to apply the correct condition to the queryset
(optional) a way to make the filters cumulative (i.e. you can keep adding filters)
in the Template:
display the correct resultset based on the filter choosen
when displaying the filters, recognize which filter we have applied so that the current applied filter is displayed as text not a hyperlink.
I'm thinking this must be common enough that someone must have like a design pattern or best practice figured out for this other than the obvious whack of if/else statements in the view and the template.
is there?
I find the way the Django admin handles this kind of functionality a great pattern. If you're not familiar, check out the list_filter option in the admin. It's similar to what you're describing, but yours is a bit more generic. Perhaps this will help you ponder some ideas?
First, for the actual querystring chunk, you're simply passing the Django-ORM lookup key and value pair. e.g., ?sites__id__exact=1, tags__in=words, etc. Since you want to allow for cross-model lookups, you'd need to provide another parts in the string to include the model name, not too tough.
For checking if the filter is valid, you can simply ensure that the model/field lookup is valid. By splitting the parts of each QS chunk, you can identify the model, the fieldname, the lookup, and the value. Then, use Django's built-in functionality to validate that fieldname exists on model. You can do this with ForeignKey's too. Here's how Django does it
You can keep adding filters pretty easily to this. You'll be providing your view and the form that's displaying these filters with some context, so it'll persist and re-populate for the user. Also, you could just as easily persist the query string. Basically, you'd have the same read / parsing functionality here at all times, nothing really different.
I think the keys are automating and keeping it as DRY as possible. Don't succumb to a bunch of if statements. It's really easy to pass these lookups into the ORM, safely too, and it's really easy to catch bad lookups and provide the user with a meaningful error message.
I hope that helps you on your path! :)

What do I use instead of ForiegnKey relationship for multi-db relation

I need to provide my users a list of choices from a model which is stored in a separate legacy database. Foreign keys aren't supported in django multi-db setups. The ideal choice would be to use a foreign key, but since thats not possible I need to some up with something else.
So instead I created an IntegerField on the other database and tried using choices to get a list of available options.
class OtherDBTable(models.Model):
client = models.IntegerField(max_length=20, choices=Client.objects.values_list('id','name'))
the problem I'm having is that the choices seem to get populated once but never refreshed. How do I ensure that whenever the client list changes that those newest options area available to pick.
What I was really looking for was a way that I could simulate the behavior of a Foreign key field, at least as far as matching up ID's go.
There wasn't a clear way to do this, since it doesn't seem like you can actually specify an additional field when you instantiate a model (you can with forms, easily)
In any case to deal with the problem, since the database is MySQL based, I ended up creating views from the tables I needed in the other database.
To build on #Yuji's answer - if you do self.fields['field'].choices = whatever in the model's __init__, whatever can be any iterable.
This means you can inherit from iterable, and have that object interface to your legacy database, or you can use a generator function (in case you are unfamiliar, look up the yield keyword).
Citing a Django's manual:
Finally, note that choices can be any iterable object -- not necessarily a list or tuple. This lets you construct choices dynamically. But if you find yourself hacking choices to be dynamic, you're probably better off using a proper database table with a ForeignKey. choices is meant for static data that doesn't change much, if ever.
Why dont you want just export data from the legacy database and to import it into the new one? This could be done periodically, if the legacy database still in use.