How can i get the equivalent of this MySQL script in Django views? The depart_city, arrive_city, and travel_date will be inputed by the user.
Here is my Models
class Driver(models.Model):
first_name = models.CharField(max_length=30, null=True, blank=False)
last_name = models.CharField(max_length=30, null=True, blank=False)
class Schedule(models.Model):
depart_time = models.TimeField()
arrive_time = models.TimeField()
class TravelDate(models.Model):
start_date = models.DateField(null = True)
interval = models.IntegerField(null = True)
class Route(models.Model):
depart_city = models.CharField(max_length=50, null=True, blank=False)
arrive_city = models.CharField(max_length=50, null=True, blank=False)
driver = models.ForeignKey(Driver)
schedule = models.ForeignKey(Schedule)
traveldate = models.ForeignKey(TravelDate)
Here is my MySQL script. This works when i run it on MySQL workbench but I'm not sure how to translate this to Django Query
SELECT busapp_route.depart_city, busapp_route.arrive_city, busapp_driver.first_name, busapp_schedule.depart_time
FROM (((busapp_route INNER JOIN busapp_driver ON busapp_route.driver_id = busapp_driver.id)
INNER JOIN busapp_schedule ON busapp_route.schedule_id = busapp_schedule.id)
INNER JOIN busapp_traveldate ON busapp_route.traveldate_id = busapp_traveldate.id)
WHERE busapp_route.depart_city='Tropoje' AND busapp_route.arrive_city='Tirane'
AND (DATEDIFF('2017-11-26', busapp_traveldate.start_date) % busapp_traveldate.interval = 0);
Django doesn't support MySQL DATEDIFF natively. As a workaround, you could use something like this:
from django.db.models.expressions import RawSQL
routes = Route.objects\
.values('depart_city', 'arrive_city', 'driver__first_name', 'schedule__depart_time', 'traveldate__start_date')\
.annotate(datediff_mod=RawSQL("DATEDIFF(%s, busapp_traveldate.start_date) MOD busapp_traveldate.interval", ('2017-11-26', )))\
.filter(depart_city='Tropoje', arrive_city='Tirane', datediff_mod = 0)
I don't use MySQL so I couldn't test this, but I'm pretty sure it should work or maybe at least give you an idea how to implement it.
I don't think that it's a good idea, trying to solve this from the SQL side.
And what you're building there, is not trivial as there are a lot of things to keep in mind.
Your current Model setup lags some points:
What if a user searches for a travel in next year? With your model you'll have to create entries for all possible dates in the future, that's nearly unusable.
Think also about separating times and dates in different models, as they usually should be kept together, cause a ride from A to B at date x and time y is one object.
It might help to have a look at django-scheduler, they solved some troubles with the use of Events and Occurences. Have a look at their pretty good docs.
Related
I have merged two querysets (qs1 and qs2) which individually work fine, as follows:
qlist = [qs1, qs2]
results = list(chain(qs1, qs2))
So far, so good - the above works. But now I'm trying to order the results using the following:
qlist = [qs1, qs2]
results = sorted(chain(qs1, qs2), key=attrgetter('monthly_fee'))
The problem is that the second queryset (qs2) refers to the monthly_fee through a ForeignKey; whereas qs1 has 'monthly_fee' available. Here is qs2:
qs2 = Offer.objects.select_related('subscription')
qs2 = qs2.order_by(subscription__monthly_fee)
And the simplified models:
class Subscription(models.Model):
monthly_fee = models.IntegerField(null=False, blank=True, default=0)
name = models.CharField(max_length=120, null=True, blank=True)
class Offer(models.Model):
promotion_name = models.CharField(max_length=120, null=True, blank=True)
subscription = models.ForeignKey(Subscription)
discount = models.IntegerField(null=False, blank=True, default=0)
I've tried using .annotate() and .extra() to rename the subscription__monthly_fee in the query qs2 as follows:
qs2 = Offer.objects.select_related('subscription').annotate(monthly_fee=subscription__monthly_fee)
But then get the error
global name 'subscription__monthly_fee' is not defined
I am at the point of just hacking this by over-riding the .save() methods of my models to manually add the monthly_fee to each Offer instance whenever an object is created. But just wanted to check whether there isn't a better way ?
Thank you,
Michael
I've used an F expression to achieve this sort of renaming before. Try this:
from django.db.models import F
qs2 = Offer.objects.select_related('subscription').annotate(monthly_fee=F('subscription__monthly_fee'))
OK, I found a way to do this.
qs2 = Offer.objects.select_related('subscription').extra(select={'monthly_fee':'mobile_subscription.monthly_fee'})
where 'mobile' is the name of the Django app. I didn't realize that .extra DOES allow you to follow foreign keys but that you actually have to specify the actual database table and use SQL dot notation.
Is the above the actual correct way we are supposed to do it ? (i.e. dropping in raw SQL table names/fields)
I had been trying to use Django syntax such as .extra(select={'monthly_fee':'subscription__monthly_fee'}) which doesn't work!
I'm struggling with django querysets and GROUP BY queries, I know there are plenty of similar questions, but I really don't get it:/
I would like to be able to create a request similar to this one (SQLite):
SELECT MAX(fb_game_score.value), fb_game_fbuser.first_name, fb_game_fbuser.last_name
FROM fb_game_score
JOIN fb_game_game ON (fb_game_score.game_id = fb_game_game.id)
JOIN fb_game_fbuser ON (fb_game_game.user_id = fb_game_fbuser.id)
GROUP BY fb_game_fbuser.fb_user_id;
The query is quite simple, it lists the users scores by showing only the best score for each players.
For clarification here's the model classes:
class FBUser(AbstractUser):
fb_user_id = models.CharField(max_length=100, null=True)
oauth_token = models.CharField(max_length=1024, null=True)
expires = models.IntegerField(null=True)
highest_score = models.IntegerField(null=True)
class Game(models.Model):
identifier = models.CharField(max_length=100, db_index=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='games')
class Score(models.Model):
game = models.ForeignKey(Game, related_name='scores')
value = models.IntegerField()
date = models.DateTimeField(auto_now=True)
timestamp = models.FloatField(default=0)
inter = models.BooleanField(default=False)
There's no high-level group_by in the queryset. It's used in calls to aggregate and annotate but it is not available to you.
There's a low-level API which is not documented at all. You can get an internal query description:
queryset = ... #whatever query you'd want to group by
query = queryset.query
and then you can alter the group_by member -which is a list- by adding a field which you'd want to group by:
query.group_by.append('a_field')
But:
you have to seriously know what you're doing.
there's no guarantee of stability of this API.
The current alternative for this is falling back to a raw (django.db.connection.* methods) SQL query.
Edit: I just saw this 3rd-party application which could help you with reports. I don't know if you can use in-code reports, or you have to limit yourself to in-view reports (i.e.: don't know if you can process reports in code or just have them as final results).
I'm new here, working with Web Apps & SEO. StackOverflow has been a great resource in learning my way around Python & Django so a big thank you to the community. Now for my Question!
I have a couple of Django models:
class Subscription(models.Model):
hotel = models.ForeignKey("Hotel", related_name="subscriptions")
tier = models.ForeignKey("Tier")
enquiry_count = models.PositiveIntegerField(default=0)
start_date = models.DateField(null=True, blank=True)
end_date = models.DateField(null=True, blank=True)
and:
class Tier(models.Model):
name = models.CharField(max_length=32)
enquiry_limit = models.PositiveIntegerField(default=0)
I also have a Hotel Model that i'll show here in a very simlified form:
class Hotel(models.Model):
name = models.CharField("Hotel Name", max_length=128)
address = models.TextField("Address", blank=True)
town = models.CharField(max_length=64)
star = models.PositiveIntegerField(default=0, null=True, blank=True)
Each Hotel needs to have subscription to appear in my search results. Each Subscription has a Tier with a certain enquiry_limit.
A subscription runs out when it either reaches the end_date OR its enquiry_count maxes out. i.e. Reaches the enquiry_limit of its tier.
I found a straightforward way of doing this with F Objects and an exclude which works nicely on my dev machine:
self.premium_hotels = Hotel.objects.select_related().exclude(
Q(subscriptions__end_date__lte=datetime.date.today()) | Q(subscriptions__enquiry_count__gte=F('subscriptions__tier__enquiry_limit')))
This will not work on the live version of the site however as it is running Django 1.0. Any tips on how to achieve this query without F objects?
I realize that the obvious solution is to upgrade but we need this rolled out right away and I'll need time to prepare & test before we move to Django 1.3
Thanks in advance!
Without F objects you will not be able to do the query in a single step, your own option is to run the query without looking at the enquiry_limit and the post process the list to remove those hotels which have exceeded it.
Something like the code below should work.
hotels = Hotel.objects.select_related().exclude(
Q(subscriptions__end_date__lte=datetime.date.today()))
self.premium_hotels = []
for h in hotels:
for sub in h.subscriptions.filter(start_date__lte=datetime.now(), end_date__gte=datetime.now()):
if sub.enquiry_count < sub.tier.enquiry_limit:
self.premium_hotels.append(h)
break
Use extra on the queryset to insert custom SQL (see where / tables):
http://docs.djangoproject.com/en/dev/ref/models/querysets/#extra
e.g. (roughly - you'll need to match tables name etc in SQL)
self.premium_hotels = Hotel.objects.select_related().exclude(
Q(subscriptions__end_date__lte=datetime.date.today())).extra(tables=["myapp_tier"], where=['myapp_subscriptions.enquiry_count
Best bet it to run your query locally - look at what SQL it generates, that use that to figure out what to put in your call to extra
Hey, I have models like this:
class Galleries(models.Model):
creation_date = models.DateTimeField()
name = models.CharField(max_length=255, unique=True)
gallery_type = models.ForeignKey(Categories)
class Categories(models.Model):
handle = models.CharField(max_length=255, unique=True)
class Values(models.Model):
category = models.ForeignKey(Categories)
language = models.CharField(max_length=7)
category_name = models.CharField(max_length=50)
And now, I just want to reach the values of categories by starting from Galleries. For example: galleries = Galleries.objects.get(id=1). And now I want to reach somehow the values by using this "galleries" object... To get values with specific language would be much more better... I miss skills in Django ORM, so if you can, please point me to some docs or give some code example. Thanks!
galleries = Galleries.objects.get(id=1)
values = galleries.gallery_type.values_set.filter(language='language')
Interestingly, you used the exact wording that the docs use to refer to the related field lookups. I always found the definition strange to the gut, maybe because they put it in quotes.
FOLLOWING RELATIONSHIPS "BACKWARD"
http://docs.djangoproject.com/en/1.2/topics/db/queries/#following-relationships-backward
You may want to use the select_related method of objects so you reduce the number of queries you are making. select_related
gallery = Galleries.objects.select_related().get(id=1)
You can set a related name for the Values model in the category fk:
class Values(models.Model):
category = models.ForeignKey(Categories, related_name="categories")
language = models.CharField(max_length=7)
category_name = models.CharField(max_length=50)
now you can get your list of values for a specific language by doing
values = gallery.gallery_type.categories.filter(language="language")
i have a model that is having multiple many to many relation to another model it is as follows:
class Match(models.Model):
"""Model docstring"""
Match_Id = models.AutoField(primary_key=True)
Team_one = models.ManyToManyField('Team',related_name='Team one',symmetrical=False,)
Team_two = models.ManyToManyField('Team',related_name='Team two',symmetrical=False,)
stadium = models.CharField(max_length=255, blank=True)
Start_time = models.DateTimeField(auto_now_add=False, auto_now=False, blank=True, null=True)
Rafree = models.CharField(max_length=255, blank=True)
Judge = models.CharField(max_length=255, blank=True)
winner = models.ForeignKey('Team', related_name='winner',to_field='Team_Name')
updated = models.DateTimeField('update date', auto_now=True )
created = models.DateTimeField('creation date', auto_now_add=True )
what is the best way to implement model like this ?. all though django does not throw any errors when passing the model sql once syncdb is excuted it throws up errors saying there is no unique constraint matching given keys
Are you sure Team_one and Team_two should be ManyToMany fields? Surely, a match only has a single team on each side - in which case these should both be ForeignKeys.
Using spaces in related_name attribute makes me uneasy, but I think the real problem is connected to the use of to_field attribute on the winner field. As far as I know you can set database relations only to unique fields. It doesn't really make sense to relate to another object using a field that may not be unique.
I'm not sure what do you want to achieve by connecting through this particular field. You usually connect models using primary key fields. This still allows you to access any other field on the related object.