Django ORM like select query in Pony ORM - python

I'm now to Pony ORM
and I have created my DB models like this:
class RSSSource(db.Entity):
title = Required(str, max_len=100)
link = Required(str, max_len=800)
key = Required(str, max_len=200)
description = Required(str, max_len=800)
is_deleted = Optional(bool, sql_default=False)
rss_content = Set('RSS', reverse='source')
subscriptions = Set("Subscription", reverse='source')
def __str__(self):
return self.title
class RSS(db.Entity):
title = Optional(str, max_len=300)
link = Optional(str, max_len=500)
description = Required(str, max_len=500)
source = Optional("RSSSource", reverse="rss_content")
pub_date = Optional(datetime)
is_deleted = Optional(datetime, sql_default=False)
likes = Set("Like", reverse="rss")
def __str__(self):
return self.title
class User(db.Entity):
first_name = Optional(str, max_len=100)
last_name = Optional(str, max_len=100)
username = Required(str, max_len=200, unique=True)
password = Required(str, max_len=500)
is_deleted = Optional(bool, sql_default=False)
subscriptions = Set("Subscription", reverse="user")
likes = Set("Like", reverse="user")
def __str__(self):
return self.username
class Subscription(db.Entity):
source = Optional("RSSSource", reverse="subscriptions")
user = Optional("User", reverse="subscriptions")
is_deleted = Optional(bool, sql_default=False)
now I want to perform a Django ORM-like select query. something like this:
select user.id
from Subscription where source.key = $key and (is_deleted is null or is_deleted = FALSE)
I couldn't find a way to do this. can anyone help, please?

I finally came up with something like this and it worked.
select user
from Subscription as s
left join RSSSource as rs on rs.id = s.source
where rs.key = $key and (s.is_deleted is null or s.is_deleted = FALSE)

Related

Django rest framework - NOT NULL constraint on a foreign Key

I have this Error :
IntegrityError at /api/post_flight_schedule/
NOT NULL constraint failed: flights_tailnumber.aircraft_type_id
When I try to add a new PosFlightSchedule object to DB over http://127.0.0.1:8000/api/pos_flight_schedule (Website/APIView)
I have the below serializer :
class PosFlightScheduleModelSerializer(ModelSerializer):
class Meta:
model = PosFlightSchedule
fields = ['pos_route_id', 'tail_number', 'pos_flight_number', 'pos_flight_departure_time', 'pos_flight_date',
'pax_count']
class PosFlightScheduleSerializer(serializers.Serializer):
pos_route_id = serializers.CharField(source='pos_route_id.route_id', read_only=False)
tail_number = serializers.CharField(source='tail_number.tail_number', read_only=False)
pos_flight_number = serializers.CharField(source='pos_flight_number.flight_number', read_only=False)
pos_flight_departure_time = serializers.CharField(source='pos_flight_departure_time.flight_departure_time', allow_null=True,
read_only=False)
pos_flight_date = serializers.CharField(source='pos_flight_date.flight_date', read_only=False)
pax_count = serializers.IntegerField(read_only=False)
def create(self, validated_data):
tail_number_data = validated_data.pop("tail_number")
tail_number = TailNumber.objects.create(**tail_number_data)
flight_number_data = validated_data.pop("pos_flight_number")
flight_number = FlightSchedule.objects.create(**flight_number_data)
flight_departure_time_data = validated_data.pop("pos_flight_departure_time")
print "DEP_TIME" + str(flight_departure_time_data)
flight_departure_time = FlightSchedule.objects.create(**flight_departure_time_data)
route_id_data = validated_data.pop("pos_route_id")
route_id = FlightScheduleDetail.objects.create(**route_id_data)
flight_date_data = validated_data.pop("pos_flight_date")
flight_date = FlightScheduleDetail.objects.create(**flight_date_data)
pax_count = validated_data.pop("pax_count")
schedule_obj = PosFlightSchedule.objects.create(**validated_data)
# if tail_number:
schedule_obj.set_tail_number(tail_number)
schedule_obj.set_pos_flight_number(flight_number)
schedule_obj.set_pos_flight_departure_time(flight_departure_time)
schedule_obj.set_pos_route_id(route_id)
schedule_obj.set_pos_flight_date(flight_date)
schedule_obj.set_pax_count(pax_count)
schedule_obj.save()
return schedule_obj
def update(self, instance, validated_data):
tail_number = validated_data.pop("tail_number")
flight_number = validated_data.pop("pos_flight_number")
flight_departure_time = validated_data.pop("pos_flight_departure_time")
route_id = validated_data.pop("pos_route_id")
flight_date = validated_data.pop("pos_flight_date")
pax_count = validated_data.pop("pax_count")
instance.__dict__.update(validated_data)
if tail_number:
instance.set_tail_number(tail_number)
if flight_number:
instance.set_pos_flight_number(flight_number)
if flight_departure_time:
instance.set_pos_flight_departure_time(flight_departure_time)
if route_id:
instance.set_pos_route_id(route_id)
if flight_date:
instance.set_pos_flight_date(flight_date)
if pax_count:
instance.set_pax_count(pax_count)
instance.save()
return instance
The model of the field which is giving error looks like :
class TailNumber(models.Model):
tail_number_id = models.AutoField(null=False, primary_key=True)
tail_number = models.CharField(max_length=20, null=False, blank=False, unique=True)
aircraft_type = models.ForeignKey(AircraftType, null=False, blank=False)
def __unicode__(self):
return u'%s' % self.tail_number
class Meta:
verbose_name_plural = "Tail Numbers"
I am not understanding what is going wrong here.
The error you get is probably due to the fact that the dictionary tail_number_data does not contain the keyword aircraft_type, which is expected by TailNumber.objects to create the row in the db, since you defined it with no possibility to be null
aircraft_type = models.ForeignKey(AircraftType, null=False, blank=False)
^^^^^
Check that the key "aircraft_type" does exist in the dictionary tail_number_data, or allow for it to be null. Furthermore, if you consider the latter option and that this information is supposed to come from a UI, you may also want to allow for aircraft_type to be blank. See differentiate null=True, blank=True in django for details.

how to select data between 2 dates using sql queries in django?

models.py
My models.py
class Custom_user_model(User):
daily_target = models.IntegerField()
monthly_target = models.IntegerField()
yearly_target = models.IntegerField()
weekly_target = models.IntegerField()
call_target = models.IntegerField()
email_target = models.IntegerField()
meeting_target = models.IntegerField()
added_under = models.IntegerField()
profile_pic = models.TextField()
doj = models.DateTimeField(default='')
location_id = models.IntegerField()
locked = models.BooleanField()
default_currency = models.IntegerField()
date_change_permission = models.BooleanField()
deal_back_log = models.BooleanField()
created_date=models.DateTimeField(auto_now_add=True)
role_id=models.IntegerField()
profile_pic = models.FileField(upload_to='.')
objects = UserManager()
//This custom_user model is the extension of django's default user model.
class Deal(models.Model):
a_choices = ((0,'yes'),(1,'no'))
approved = models.IntegerField(choices=a_choices,default=1)
user_id = models.IntegerField()
company_id = models.IntegerField()
contact_id = models.IntegerField()
deal_title=models.CharField(max_length=200)
deal_value = models.CharField(max_length=20)
currency_id = models.IntegerField()
process_id = models.IntegerField()
expected_close_date = models.DateField(default='')
closed_date = models.DateField()
deal_milestone=models.IntegerField()
created=models.DateTimeField(auto_now_add=True)
last_modified=models.DateTimeField(auto_now_add=True)
s_choices = ((0,'active'),(1,'won'),(2,'junk'),(3,'lost'))
status = models.IntegerField(choices=a_choices,default=0)
type = models.CharField(max_length=50, default='deal')
source = models.CharField(max_length=50,default='O')
class user_Roles(models.Model):
code = models.CharField(max_length=20)
description = models.CharField(max_length=30)
permitted_menus = models.CharField(max_length=200)
created = models.DateTimeField(auto_now_add=True)
Using user_roles model, I have assigned permission for accessing data to the newly created user based on his/her role. I want to get the created deals which are added by the users having role_id = 2 and deals created date between the specified dates .
### views.py
st_date, end_date = week_magic(date.today())
cur = connection.cursor()
cur.execute("select *, CONCAT(au.first_name,' ',au.last_name) as full_name from myapp_custom_user_model mu left join auth_user au on mu.user_ptr_id = au.id INNER JOIN myapp_user_roles ml on ml.id= 2 and ml.id = mu.role_id LEFT JOIN (SELECT user_id,SUM( deal_value ) AS cnt FROM myapp_deal where status = 1 and DATE_FORMAT(closed_date,'%Y-%m-%d') BETWEEN " '%s' " and " '%s' " GROUP BY user_id)d ON mu.user_ptr_id = d.user_id where mu.locked !=1 and mu.role_id = 2 order by COALESCE( d.cnt, 0 ) DESC",(st_date,end_date))
users = dictfetchall(cur)
cur.close()
While executing the query it shows unsupported format error. So I used one more % symbol in the same query as follows:
cur.execute("select *, CONCAT(au.first_name,' ',au.last_name) as full_name from myapp_custom_user_model mu left join auth_user au on mu.user_ptr_id = au.id INNER JOIN myapp_user_roles ml on ml.id= 2 and ml.id = mu.role_id LEFT JOIN (SELECT user_id,SUM( deal_value ) AS cnt FROM myapp_deal where status = 1 and DATE_FORMAT(closed_date,'%%Y-%%m-%%d') BETWEEN " '%s' " and " '%s' " GROUP BY user_id)d ON mu.user_ptr_id = d.user_id where mu.locked !=1 and mu.role_id = 2 order by COALESCE( d.cnt, 0 ) DESC" %(st_date,end_date))
It doesn't give any error but the result is empty even though there is data because of this syntax: DATE_FORMAT(closed_date,'%%Y-%%m-%%d'). How to solve this?
First of all you should use ForeignKey fields for role_id in Custom_user_model and user_id in Deal. The same is probably true for some of the other _id fields in your models.
class Custom_user_model(User):
...
role = models.ForeignKey('Role')
...
class Deal(models.Model):
...
user = models.ForeignKey('Custom_user_model')
...
After that you can do your query like this:
# get deals from users with role_id=2
query = Deal.objects.filter(user__role_id=2)
# add filter for deals created by that user created between
start_date, end_date = week_magic(date.today())
query = query.filter(created__between=(start_date, end_date))

Django : get the last item of manytomanyfield

With these models :
class Message(models.Model):
text = models.CharField(max_length=200)
date_send = models.DateTimeField(auto_now_add=True,editable=False)
emeteur = models.ForeignKey(User,null=True,related_name="+")
class Meta :
abstract = True
class MessagePerso(Message) :
read_at = models.DateTimeField(("read at"), null=True, blank=True)
class Conversation(models.Model):
title = models.CharField(max_length=90)
creator = models.ForeignKey(User,null=True,related_name="CreatorConversation")
recipient = models.ForeignKey(User,null=True,related_name="RecipientConversation")
created_at = models.DateTimeField(auto_now_add=True,editable=False)
messages = models.ManyToManyField(MessagePerso)
So, for each Conversation I want the text of the last MessagePerso created (ManyToManyField in Conversation) and others informations.
So for now, I have this :
def .. :
u = request.user
conversations = Conversation.objects.filter(Q(creatorr=u)|Q(destinataire=u)).annotate(nbMsg=Count('messages'),date=Max('messages__date_send')).order_by('date','id')
I don't have the the text of last message created for each Conversation, how makes it ?
You can order your data by a date_send field ascending as follow:
class Message(models.Model):
text = models.CharField(max_length=200)
date_send = models.DateTimeField(auto_now_add=True,editable=False)
emeteur = models.ForeignKey(User,null=True,related_name="+")
class Meta :
abstract = True
ordering = ['date_send'] # default ordrer while fetching data
Than for each conversation's messages you fetch the last using .last():
def .. :
u = request.user
conversation_id_list = Conversation.objects.filter(Q(creatorr=u)|Q(destinataire=u)).values_list('id', flat=True)
message_list = list(()
for id in conversation_id_list:
last_message = MessagePerso.objects.filter(conversation_id=id).last()
message_list.append(last_message)
print(last_message.text)
if the number of conversation is kind of big and you want to minimize db queries you can use prefetch_related
def .. :
u = request.user
conversation_list = Conversation.objects.filter(Q(creatorr=u)|Q(destinataire=u)).preftech_related('messages')
messages_dict =dict()
for conversation in conversation_list:
messages_dict.update({
converstaion.id: conversation.messages.all()
})
last_message_list = list()
for conversation_id, message_list in messages_dict.items():
if message_list:
last_message = messages_dict.get(conversation_id)[len(message_list) -1:]
last_message_list.append(last_message)
print(last_message.text)

Django, subset of foreign key

I need a way to select a subset of a foreign key, but only limit it to a subset. This is the raw query that was used in the old PHP database;
SELECT a.name FROM character_trait b
LEFT JOIN trait a ON b.id_trait = a.id
WHERE b.id_character = 1
AND a.id_traittype = 10
All the tables, character, trait, traittype and character_trait are available, but I can't figure out how to do it in Djando. My idea was this;
traits = CharacterTrait.objects.filter( id_character = character, id_trait.id_traittype = 10 )
But that just gives an error "keyword can't be an expression". I can do it in a very ugly way and just iterate through the resulting 'traits' using a for loop like this;
traits = CharacterTrait.objects.filter( id_character = character )
for t in traits:
print t.id_trait.id_traittype.id
if t.id_trait.id_traittype.id == 10:
print "Got One"
Edit, the module definitions;
class Trait(models.Model):
id = models.IntegerField(primary_key=True) # AutoField?
id_traittype = models.ForeignKey(Traittype, null=True, db_column = 'id_traittype')
name = models.CharField(max_length=32)
class Meta:
managed = False
db_table = 'trait'
def __unicode__(self):
return self.name
class Traittype(models.Model):
id = models.IntegerField(primary_key=True) # AutoField?
name = models.CharField(max_length=64)
class Meta:
managed = False
db_table = 'traittype'
def __unicode__(self):
return self.name
class Trait(models.Model):
id = models.IntegerField(primary_key=True) # AutoField?
id_traittype = models.ForeignKey(Traittype, null=True, db_column = 'id_traittype')
name = models.CharField(max_length=32)
class Meta:
managed = False
db_table = 'trait'
def __unicode__(self):
return self.name
class CharacterTrait(models.Model):
id = models.IntegerField(primary_key=True) # AutoField?
##id_character = models.IntegerField()
## id_trait = models.IntegerField()
id_character = models.ForeignKey(Werewolfcharacter, null=True, db_column = 'id_character')
id_trait = models.ForeignKey(Trait, null=True, db_column = 'id_trait')
class Meta:
managed = False
db_table = 'character_trait'
def __unicode__(self):
return self.id_trait.name
I was going to suggest you needed to chain the filters, like
traits = CharacterTrait.objects.filter( id_character = character).filter(id_trait__id_traittype = 10 )
But looking back at some code,
traits = CharacterTrait.objects.filter( id_character = character, id_trait__id_traittype = 10 )
Should be sufficient, where the key thing is replacing the . with __ as suggested by dm03514
One simple possibilty, since you (presumably) already have the correct SQL in your PHP code, is simply to use raw SQL queries in Django.
You should read the docs on lookups that span relationships. You need to use the double-underscore syntax:
CharacterTrait.objects.filter(id_character=character, id_trait__id_traittype=10)

Specific Quote Issue

Here is my problem. I have a model Project, that has a quote field in it. When a new instance of project is created I need to append the last 2 digits of the year plus a hyphen onto the start of the "quote" field. Ex. 2010 = "10-". Im just not quite sure how to start it?
As of right now I have hard coded in "10-" in as a pre-quote field, but I do not want to have to do that.
models.py
class Project(models.Model):
client = models.ForeignKey(Clients, related_name='projects')
created_by = models.ForeignKey(User, related_name='created_by')
#general information
proj_name = models.CharField(max_length=255, verbose_name='Project Name')
pre_quote = models.CharField(max_length=3,default='10-')
quote = models.IntegerField(max_length=10, verbose_name='Quote #', unique=True)
desc = models.TextField(verbose_name='Description')
starts_on = models.DateField(verbose_name='Start Date')
completed_on = models.DateField(verbose_name='Finished On')
Anyone have to do this before? Or have any suggestions?
Try this:
def save(self):
today = datetime.date.today()
self.quote = "%s-%s" % (str(today.year)[2:4], self.quote)
Assuming you imported datetime.
Your existing quote field is set as an integer. You will need to set this as a text field. Once you do that, you can override the save() function to prepend "10-" to the field.
class Project(models.Model):
client = models.ForeignKey(Clients, related_name='projects')
created_by = models.ForeignKey(User, related_name='created_by')
proj_name = models.CharField(max_length=255, verbose_name='Project Name')
quote = models.TextField(max_length=10, verbose_name='Quote #', unique=True)
desc = models.TextField(verbose_name='Description')
starts_on = models.DateField(verbose_name='Start Date')
completed_on = models.DateField(verbose_name='Finished On')
def save(self):
self.quote = "10-" + self.quote

Categories