basically im trying to write a index route that returns the posts of a business that a user is subscribed to
the last line is throwing an error for the backref (business.posts)
# query that finds all the subscriptions of the logged in user
subscriptions_query = models.Subscription.select().join(models.User).where(models.User.id == current_user.id)
# gets the businesses being followed from the subscriptions
businesses_being_followed = [subscription.following for subscription in subscriptions_query]
post_dicts = [model_to_dict(business.posts) for business in businesses_being_followed]
this is my posts model
class Post(BaseModel):
business = ForeignKeyField(Business, backref='posts')
image = CharField()
content = CharField()
date = DateTimeField(default=datetime.datetime.now)
Your example is REALLY inefficient.
Can you just do:
(Post
.select()
.join(Business)
.join(Subscription)
.where(Subscription.user == the_user_id))
Related
I am using python with flask as a backend and I am trying to create a route to a table in my database based on user input. During one of my post requests a table is created in the database. I then want to create a connection to this table. The table name also depends on user input. I want to emphasize that I am able to create the tables in the database based on user input and now need to create the route to these tables.
Is there a way to create such route?
I understand that doing something like this may lead to security vulnerability so I am open to suggestions for different approaches.
I am attaching below my current python code for creating routes:
# Destination Class/model
class Destinations(db.Model):
ID = db.Column(db.Integer, primary_key=True)
city = db.Column(db.String(100))
country = db.Column(db.String(100))
def __init__(self, city, country):
self.city = city
self.country = country
# Destinations Schema
class DestinationsSchema(ma.Schema):
class Meta:
fields = ('ID', 'city', 'country')
# Init Destinations Schema
destination_schema = DestinationsSchema()
destinations_schema = DestinationsSchema(many=True)
# Create a Destination
#app.route('/destinations', methods=['POST'])
def add_destination():
city = request.json['city']
country = request.json['country']
new_destination = Destinations(city, country)
db.session.add(new_destination)
db.session.commit()
return destination_schema.jsonify(new_destination)
# Get All Destinations
#app.route('/destinations', methods=['GET'])
def get_destinations():
all_destinations = Destinations.query.all()
result = destinations_schema.dump(all_destinations)
return jsonify(result)
This is my answer to what I understood from your question. I hope it helps you:
You can put a variable in the url. Something like this:
#app.route('/destinations/<tablename>', methods=['GET'])
def get_destination(tablename):
destination = Destinations.query.filter_by(name=tablename)
result = destinations_schema.dump(destination )
return jsonify(result)
I'm new in Django. So, I want to join two models which are company and client and count the number of clients for each of the company. Here the SQL
SELECT Company_company.name, count(Client_client.cid)
FROM Company_company
LEFT JOIN Client_client
ON Company_company.comid = Client_client.comid_id
GROUP BY Company_company.name;
But since in Django, we use ORM. So I'm a little bit confusing since I'm a beginner. I already refer few SQL to ORM converter website such as Django ORM and do some try and error. But, I didn't know where the problem since I want the output from the ORM to be classified into a different array. Here is my code:
labels = []
data = []
queryClientCompany = client.objects.values('comid').annotate(c=Count('cid')).values('comid__name','c')
for comp in queryClientCompany:
labels.append(comp.comid__name)
data.append(comp.c)
Here some of the relevant things in the client and company models:
class client (models.Model):
#client info
cid = models.AutoField(primary_key = True)
comid = models.ForeignKey(company,related_name='companys',
on_delete = models.DO_NOTHING,verbose_name="Company",null = True, blank = True)
class company(models.Model):
comid = models.AutoField(_('Company'),primary_key = True)
#company info
name = models.CharField(_('Company Name'),max_length = 50)
The error stated that the comid__name is not defined. So actually how to append the result? I hope someone can help me. Thank you for helping in advanced.
You should query from the opposite side to perform the LEFT OUTER JOIN between company and client (and not client and company):
from django.db.models import Count
labels = []
data = []
queryClientCompany = company.objects.annotate(
c=Count('companys__cid')
)
for comp in queryClientCompany:
labels.append(comp.name)
data.append(comp.c)
The companys part is due to the related_name='copanys', but it does not make much sense to name this relation that way. The related_name=… parameter [Django-doc] specifies how to access the Clients for a given Company, so clients is a more appropriate value for the related_name:
class client (models.Model):
cid = models.AutoField(primary_key=True)
comid = models.ForeignKey(
company,
related_name='clients',
on_delete = models.DO_NOTHING,
verbose_name="Company",
null = True,
blank = True
)
then the query is:
from django.db.models import Count
labels = []
data = []
queryClientCompany = company.objects.annotate(
c=Count('clients__cid')
)
for comp in queryClientCompany:
labels.append(comp.name)
data.append(comp.c)
I work on a simple chat app. I need to query db for an user to get last message of user conversation to other users. Same as main page of whatsapp and telegram.
Model:
class CHAT(models.Model):
sender_uid = models.CharField(max_length=150, db_index=True)
receiver_uid = models.CharField(max_length=150, db_index=True)
message = models.TextField(verbose_name='Message Text')
created = models.IntegerField(default=created_time_epoch)
I tried this query:
message_list = self.model.objects.filter(Q(sender_uid=user_uid)|Q(receiver_uid=user_uid)).order_by('receiver_uid', 'sender_uid', '-created').distinct('receiver_uid', 'sender_uid')
Output:
<QuerySet [<CHAT: ted#ted.com Message: hello 4 To: saeed#saeed.com>, <CHAT: marshal#marshal.com Message: hello6 To: saeed#saeed.com>, <CHAT: saeed#saeed.com Message: hello 5 To: ted#ted.com>]>
My problem is I get two last message from each conversation (if both user send message to each other), In one of them user is sender and in other one user is receiver.
For now I handle it with below code:
message_send_list = list(self.model.objects.filter(sender_uid=user_uid).order_by('receiver_uid', '-created').distinct('receiver_uid'))
message_receive_list = list(self.model.objects.filter(receiver_uid=user_uid).order_by('sender_uid', '-created').distinct('sender_uid'))
temp_list = []
for s_message in message_send_list:
r_message = next((item for item in message_receive_list if item.sender_uid == s_message.receiver_uid), None)
if r_message is not None:
message_receive_list.pop(message_receive_list.index(r_message))
if s_message.created > r_message.created:
temp_list.append(s_message)
else:
temp_list.append(r_message)
else:
temp_list.append(s_message)
temp_list.extend(message_receive_list)
Output:
[<CHAT: saeed#saeed.com Message: hello 5 To: ted#ted.com>, <CHAT: marshal#marshal.com Message: hello6 To: saeed#saeed.com>]
My question is how can I get this result in one query? Problem is user can be sender and receiver of message and I can't distinguish which one is last message of conversation. How to filter or distinct on that?
Based on the description of the problem, you make it a bit too complex. You can obtain the other person with a conditional expression [Django-doc]. So by first making a "reduction" where we take the other person, we can then use a uniqueness filter for that:
from django.db.models import Case, F, When
last_messages = self.model.objects.filter(
Q(sender_uid=user_uid) | Q(receiver_uid=user_uid)
).annotate(
other=Case(
When(sender_uid=user_uid, then=F('receiver_uid')),
default=F('sender_uid'),
output_field=CharField()
)
).order_by('other', '-created').distinct('other')
Furthermor all Chat objects will have an extra attribute: other that thus contains the non-user_uid side.
I have two models: MetaModel and RelatedModel. I want to include the result of a RelatedModel lookup within a MetaModel query, and I'd like to do this within a single DB call.
I've tried to define a 'subquery' QuerySet for use in the main query, but that hasn't worked - it's still making two queries to complete the operation.
Note: I can't use a traditional ForeignKey relationship because the profile_id field is not unique. Uniqueness is a combination of profile_id and channel. This is an aggregation table and profile_id is not guaranteed to be unique across multiple third-party channels.
Any suggestions?
Models:
class Channel(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(
max_length=25,
)
class MetaModel(models.Model):
profile_id = fields.IntegerField()
channel = fields.ForeignKey(Channel))
metadata = fields.TextField()
class RelatedModel(models.Model):
related_id = fields.IntegerField()
profile_id = fields.IntegerField()
channel = fields.ForeignKey(Channel))
Dummy data
channel = Channel("Web site A")
channel.save()
sample_meta = MetaModel(profile_id=1234, channel=channel)
sample_related = RelatedModel(profile_id=1234, related_id=5678, channel=channel)
Query:
# Create a queryset to filter down to the single record we need the `profile_id` for
# I've limited to the only field we need via a `values` operation
related_qs = RelatedAccount.objects.filter(
related_id=5678,
channel=channel
).values_list("profile_id", flat=True)
# I'm doing an update_or_create as there is other data to store, not included for brevity
obj, created = MetaModel.objects.update_or_create(
profile_id=related_qs.first(), # <<< This var is the dynamic part of the query
channel=channel,
defaults={"metadata": "Metadata is added to a new or existing record."}
)
Regarding your note on uniqueness, you can use unique_together option in Django as described here in the documentation.
class MetaModel(models.Model):
profile_id = fields.ForeignKey(RelatedModel)
channel = fields.ForeignKey(Channel)
metadata = fields.TextField()
class Meta:
unique_together = ('profile_id', 'channel')
Then you can change your query accordingly and should solve your problem.
I have a model like below:
class StaffProfile(models.Model):
user = models.ForeignKey(User)
maas = models.FloatField()
maas_gunu = models.CharField(max_length=5)
When I try to insert data with a code like below:
staffprofilesay = StaffProfile.objects.filter(user = user_id).count()
if staffprofilesay > 0:
staffprofile = StaffProfile.objects.get(user = user_id)
else:
staffprofile = StaffProfile()
staffprofile.user = user_id
staffprofile.maas = calisan_formu.cleaned_data["maas"]
staffprofile.maas_gunu = calisan_formu.cleaned_data["maas_gunu"]
staffprofile.save()
I get an error like this:
Cannot assign "u'1'": "StaffProfile.user" must be a "User" instance.
What am I supposed to do?
PS: I'm using Django's User model
You need to assign a User object e.g.
from django.contrib.auth.models import User
user = User.objects.get(id=user_id)
staffprofile.user = user
user needs to be an instance of the User model, not a unicode object (which is what you are passing it).
Yes you have to pass User instance in staffprofile.user = user_id user id place.
As #david-s pointed out in a comment, if you don't have a user instance, you have to fetch from DB with an additional query.
Instead you can directly do is
staffprofile.user_id = user_id because Django behind the scene append _id in table for foreign keys so staffprofile.user will end staffprofile.user_id