Let's say I have created a model in Django that looks like this:
class Book(models.Model):
author = models.CharField(max_length=64)
... (other attributes)
def author_pretty(self):
return "[··" + self.author + "··]"
I need to get from all objects in DB the method author_pretty, as of now I'm doing this:
authors = Book.objects.values_list('author', flat=True)
authors_pretty = ["[·" + author + "·]" for author in authors]
# or
books = Book.objects.all()
authors_pretty = [book.author_pretty() for book in books]
Is there any way of doing this in a single call? Django would still have to make a query to DB and the call the method, but maybe there is a cleaner solution that I'm missing.
It depends on how you are going to use it, if it is one by one on a template, use the method as a property
#property
def author_pretty(self):
return "[··" + self.author + "··]"
However if you want something cleaner and for some reason you need them all in once, take a look into Django Docs for Concat, Query Expressions and Annotate
from django.db.models.functions import Concat
from django.db.models import Value, CharField
Book.objects.all().annotate(author_pretty=Concat(Value(“[··”), “author”, Value(“··]”), output_field=CharField()))
And then you can use it in a for loop like a property
for author in authors:
print(author.author_pretty)
Related
I need to transfer all data from an SQL table to an html page. In SQLAlchemy I would do something like this:
class Author(db.Model):
id = db.Column(db.Integer, primary_key=True)
first = db.Column(db.String(80))
last = db.Column(db.String(80))
#app.route('/authors')
def get_authors():
authors = Author.query.all()
# Serialize the queryset
result = authors_schema.dump(authors)
return jsonify({'authors': result.data})
Is there a something like authors = Author.query.all() in peewee?
To my knowledge, a direct equivalent does not exist in peewee, though there is an all method in the Dataset extension, documented here. You can do this pretty easily using a list comprehension:
authors = [author for author in Author.select()]
Or even just authors = list(Author). However, if you're trying to return these as JSON, it won't work because your list of authors is populated by instances of Author and Flask's JSONEncoder will not work with this type out of the box. You can get around this by using peewee's dicts() method:
authors = [author for author in Author.select().dicts()]
The full example would look like this:
#app.route('/authors')
def get_authors():
authors = [author for author in Author.select().dicts()]
return jsonify(authors)
Instead of serializing using dicts I often use marshmallow. For example you create an author_schema like so:
from marshmallow import Schema, fields
class AuthorSchema(Schema):
id = fields.Integer(dump_only=True)
first = fields.String()
last = fields.String()
author_schema = AuthorSchema()
and use it like so (not showing imports):
#app.route('/authors')
def get_authors():
authors = author_schema(Author, many=True)
return jsonify(authors)
so i make this.
#app.route('/authors')
def get_authors():
authors = Author.select()
return render_template('aurhors.html', authors=authors)
And in html something like this.
{% for a in authors %}
<p>{{a.author_name}}</p>
{% endfor %}
I only in begining of studying python, so thank for help.
What you're looking for is .dicts(), a method well-hidden in the docs, which returns an iterable peewee-specific type:
response = {'authors': []}
authors = Author.select()
for author in authors.dicts():
response['authors'].append(author)
Something like this should work of you're working with APIs:
return list(Account.select().dicts());
I'm using Google App Engine with webapp2 and Python.
I have a User model with a deleted field:
class User(ndb.Model):
first_name = ndb.StringProperty()
last_name = ndb.StringProperty()
email = ndb.StringProperty()
deleted = ndb.BooleanProperty(default=False)
I'd like to get a User object by calling User.get_by_id() but I would like to exclude objects that have deleted field True. Is it possible to do this with the normal get_by_id() function?
If not, could I override it?
Or should I create a custom class method, smth like get_by_id_2() that does a normal .get() query like this: User.query(User.key.id()==id, User.deleted==False).get()?
Would you reccomend something else instead?
A query is significantly slower than a get, and is subject to eventual consistency. You should probably use the normal get_by_id and check deleted afterwards. You certainly could wrap that up in a method:
#classmethod
def get_non_deleted(cls, id):
entity = cls.get_by_id(id)
if entity and not entity.deleted:
return entity
I managed to get data from the tables MemberDeclareRecept and Member with the following config files. Here I am looking for the MemberDeclareRecept.pk. But how can I get all the data if I search the Member.CoId instead?
The MemberSearchByCode view gives all the members in the table but I can't get the specific member.
Here are my models
class Member(models.Model):
Name = models.CharField(max_length=40,null=True)
FirstName = models.CharField(max_length=40,null=True)
DateBirth = models.DateField(,null=True)
CoId = models.CharField(max_length=6,null=True)
class MemberDeclareRecept(models.Model):
SyMember=models.ForeignKey(Member,verbose_name='Name member ',null=True,related_name='Member')
DateDeclareRecept=models.DateField(('Date received',null=True)
And the serializers that are being used
class MemberDeclareSerializer(serializers.ModelSerializer):
member = serializers.StringRelatedField(read_only=True)
SyRecept=serializers.StringRelatedField(read_only=True)
class Meta:
model = MemberDeclareRecept
fields=('id','member','SyRecept')
And the views that I am currently using
class MemberDeclareDetail(generics.ListCreateAPIView):
queryset=MemberDeclareRecep.objects.all()
serializer_class =MemberDeclareSerializer
def get_object(self,pk):
try:
return self.queryset.get(pk=pk)
except MemberDeclareRecep.DoesNotExist:
raise Http404
def get(self, request, pk,format=None):
entries = self.get_object(pk)
serializer = MemberDeclareSerializer(entries)
return Response(serializer.data)
class MemberSearchByCode(generics.ListAPIView):
serializer_class =MemberSerializer
def get_queryset(self):
member=self.request.QUERY_PARAMS.get(Co_id',None)
if membre is not None:
queryset = queryset.filter(member__Name=member
return queryset
It appears as though you've found an answer, based on the comment, and it's included below.
class MemberSearch(generics.ListAPIView):
serializer_class=MemberDeclareSerializer
def get_queryset(self):
member = self.kwargs['Co_id']
return member_declare_recept.objects.filter(member__Co_id=member)
It is important to note that this is not filtering the queryset based on query parameters, this is filtering it based on parameters present in the url. If you were filtering it based on query parameters, which is useful if you will need to get a list of all objects at once, the url that you would be using would be like
/api/members/?company=[co_id]
Which would make the company id optional. In your case though, the id is being embedded within the url itself. This is typically referred to as hierarchal urls, and it's generally not recommended, but your urls end up like
/api/company/[co_id]/members
Which is preferable for some, and even required in certain cases.
Now, if you wanted to use the query parameter instead of the url parameter for filtering, only a slight change would be required in your code.
class MemberSearch(generics.ListAPIView):
serializer_class=MemberDeclareSerializer
def get_queryset(self):
company_id = self.request.query_parameters.get('company', None)
if not company_id:
return member_declare_recept.objects.all()
return member_declare_recept.objects.filter(member__Co_id=company_id)
This has the additional advantage of also being support directly through django-filter and the DjangoFilterBackend.
From all I've read, it appears this should Just Work, but it doesn't.
I have a custom model:
from django.db import models
from django.contrib.auth.models import *
class Feed(models.Model):
user = models.ForeignKey(User, blank=True, null=True)
link = models.CharField(max_length=200)
startDate = models.CharField(max_length=8)
endDate = models.CharField(max_length=8)
def __unicode__(self):
return str(self.id)
def __init__(self, link, sDate, eDate, user=None):
super(Feed, self).__init__()
self.link = link
self.startDate = sDate
self.endDate = eDate
self.user = user
And I'm also using the User model included in 'django.contrib.auth.models'.
When I create a feed, e.g.
feed = Feed(link, sDate, eDate)
feed.save()
(or a similar one with a user specified) it appears to store it in the database (I get its PK which keeps incrementing), but 'Feed.objects.all()' returns an empty list. Trying to filter by an existing pk also returns an empty list and trying to get() an existing pk gives me the following error
TypeError: __init__() takes at most 5 arguments (6 given)
Looking at how I should be retrieving objects from custom models, it appears that I've done everything I should, but that is clearly not the case...
Whoa.
Why are you overriding your model's __init__? There are very few good reasons to do this, and if you do, you must absolutely keep the interface the same- because that __init__ is called every time django pulls one of your models from the db (which is why you get the error when you call .get())
What are you hoping to accomplish with your __init__?
You should probably just delete your __init__ and then you can create Feed objects the normal, django way:
feed = Feed(link=link, startDate=sDate, endDate=eDate)
That line will create the correct feed object you want.
Did you try named arguments, e.g.
feed = Feed(link=link, startDate=sDate, endDate=eDate)
How did you use get()? It should also be used with named arguments, e.g.:
Feed.objects.get(pk=6)
In the models there is a many to many fields as,
from emp.models import Name
def info(request):
name = models.ManyToManyField(Name)
And in emp.models the schema is as
class Name(models.Model):
name = models.CharField(max_length=512)
def __unicode__(self):
return self.name
Now when i want to query a particular id say for ex:
info= info.objects.filter(id=a)
for i in info:
logging.debug(i.name) //gives an error
how should the query be to get the name
Thanks..
info.name is ManyToManyField so if you want all Name objects associated with it you have to use .all() method on it. Only then you'll get list (queryset) of Name objects:
info_list = info.objects.filter(id=a)
for info_object in info_list:
for name_object in info_object.name.all():
print name_object.name
Lukasz is right, but just so you know, it doesn't make sense to filter on an id unless you use info.object.filet(id__in=a) and a is a list of some sort. If you filter on a single id, you should be using objects.get(**kwargs) first of all, and it will return that specific Info instance instead of a QuerySet.