I'm trying to work with severals objects to achieve an action.
My models.py
class LogBook(models.Model):
name = models.CharField()
class LogMessage(models.Model):
logbook = models.ForeignKey(LogBook, on_delete=models.CASCADE)
class LogDone(models.Model):
logmessage = models.ForeignKey(LogMessage)
done_status = models.BooleanField(default=False)
My view :
def logmessage_done(request, logmessage_id, log_id, token ):
log = get_object_or_404(LogBook, pk=log_id)
logmessages = LogMessage.objects.filter(logbook=log)
logdone = LogDone.objects.get_or_create(logmessage=logmessages)
logdone.done_status = True
logdone.update()
My url :
"done/<int:logmessage_id>/<int:log_id>/<str:token>"
What I want to achieve :
I want to change the status of the logdone object which is link to the logmessage object but I am not sure I have access object correctly.
What error I have :
The QuerySet value for an exact lookup must be limited to one result using slicing.
Change your view like this:
def logmessage_done(request, logmessage_id, log_id, token ):
log = get_object_or_404(LogBook, pk=log_id)
logmessages = LogMessage.objects.filter(logbook=log)
for log_message in logmessages:
LogDone.objects.update_or_create(logmessage=log_message,defaults={"done_status": True})
Here , log returns a single object with id . logmessages returns a queryset with logbook = the log returned in first query. Have to use update_or_create method
Related
I have a Django model which needs to have more than 1 images and more than 1 files (numbers may vary as per requirement), for which I adjusted my Admin Panel accordingly like this
models.py
class MasterIndividualMembers(models.Model):
individualmemberId = models.CharField(primary_key=True, max_length=100, default=1)
...
...
def __str__(self):
return self.firstname + " " + self.lastname
class IndividualMemberPhotos(models.Model):
individualmemberId = models.ForeignKey(MasterIndividualMembers, default=None,on_delete=models.CASCADE)
image = models.ImageField(upload_to="individualmemberphotos/")
class IndividualMemberCatalogue(models.Model):
individualmemberId = models.ForeignKey(MasterIndividualMembers, default=None,on_delete=models.CASCADE)
files = models.FileField(upload_to="individualmembercatalogue/")
admin.py
class IndividualMemberPhotosAdmin(admin.StackedInline):
model = IndividualMemberPhotos
class IndividualMemberCatalogueAdmin(admin.StackedInline):
model = IndividualMemberCatalogue
#admin.register(MasterIndividualMembers)
class MasterIndividualMembersAdmin(admin.ModelAdmin):
inlines = [IndividualMemberPhotosAdmin,IndividualMemberCatalogueAdmin]
class Meta:
model = MasterIndividualMembers
For the views I simply make a function to provide details of all the Images, Document and that User
views.py
#csrf_exempt
#api_view(['POST'])
#permission_classes([IsAuthenticated])
def get_individualmember(request):
if request.method == 'POST':
try:
individualmemberId = request.POST.get('individualmemberId')
result = {}
result['individualMemberDetails'] = json.loads(serializers.serialize('json', [MasterIndividualMembers.objects.get(individualmemberId=individualmemberId)]))
result['individualPhotoDetails'] = json.loads(serializers.serialize('json', IndividualMemberPhotos.objects.filter(individualmemberId__individualmemberId = individualmemberId)))
result['individualCatalogueDetails'] = json.loads(serializers.serialize('json', IndividualMemberCatalogue.objects.filter(individualmemberId__individualmemberId = individualmemberId)))
except Exception as e:
return HttpResponseServerError(e)
Problem: While fetching the details for any individual member, it throws an error get() returned more than one IndividualMemberPhotos -- it returned 2!, which is expected to have more than 1 objects.
How can I make the Restframework to provide me details of all image object together.
Instead of using get() which strictly returns a single element, use filter() which returns 0 or more elements.
As documented in https://docs.djangoproject.com/en/3.2/topics/db/queries/#retrieving-a-single-object-with-get
filter() will always give you a QuerySet, even if only a single object
matches the query - in this case, it will be a QuerySet containing a
single element.
If you know there is only one object that matches your query, you can
use the get() method on a Manager which returns the object directly:
The behavior you are experiencing is actually documented here https://docs.djangoproject.com/en/3.2/ref/models/querysets/#django.db.models.query.QuerySet.get
If get() finds more than one object, it raises a
Model.MultipleObjectsReturned exception:
Can anyone explain why this is iterable:
User.objects.all()
this is valid and gives me a value (The current user's alias. session is storing the user id):
User.objects.get(id = request.session['currentuser']).alias)
But this is giving me the error saying it is 'not iterable?':
Poke.objects.get(user = User.objects.get(id = request.session['currentuser']).alias)
(This code is supposed to get a list of Poke entries where the user column matches the current user's alias.)
Here is the Poke model. It does not use ForeignKeys, as I was having trouble setting two of them without errors.
class Poke(models.Model):
id = models.IntegerField(primary_key=True)
user = models.CharField(max_length=100)
poker = models.CharField(max_length=100)
pokes = models.IntegerField()
class Meta:
app_label = "poke_app"
Get will retrieve a single object and therefore the result will not be iterable. See documentation.
Do you see an integer value when you print(request.session['currentuser'])?
If you will see a string then you shoud give an integer value
EX: userobj = User.objects.get(id=uid)
Oh sory
User.objects.get(id = request.session['currentuser']).alias)
You open ( and closed it after ['currentuser']) but why you close ) again after .alias ?
I have this error, how can I fix this?
get() returned more than one Event -- it returned 2!
Can you guys help me understand what that means and maybe tell me in advance how to avoid this error in future?
MODEL
class Event (models.Model):
name = models.CharField(max_length=100)
date = models.DateField(default='')
dicript = models.CharField(max_length=50, default='Описание отсутствует')
category = models.ForeignKey(Category,on_delete=models.CASCADE)
adress = models.TextField(max_length=300)
user = models.ForeignKey(User,related_name="creator",null=True)
subs = models.ManyToManyField(User, related_name='subs',blank=True)
#classmethod
def make_sub(cls, this_user, sub_event):
event, created = cls.objects.get_or_create(
user=this_user
)
sub_event.subs.add(this_user)
VIEWS
def cards_detail (request,pk=None):
# if pk:
event_detail = Event.objects.get(pk=pk)
subs = event_detail.subs.count()
# else:
# return CardsView()
args = {'event_detail':event_detail,'subs':subs}
return render(request,'events/cards_detail.html',args)
class CardsView (TemplateView):`
template_name = 'events/cards.html'
def get (self,request):
events = Event.objects.all()
return render(request,self.template_name,{'events':events })
def subs_to_event (request,pk=None):
event = Event.objects.filter(pk=pk)
Event.make_sub(request.user,event)
return redirect('events:cards')
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
try:
instance = Instance.objects.get(name=name)
except (ObjectDoesNotExist, MultipleObjectsReturned):
pass
get() raises MultipleObjectsReturned if more than one object was found,more info here.
the error is cause by event_detail = Event.objects.get(pk=pk), check your event pk is unique.
Basically, the cls object is getting more than one value on the get part of the 'get_or_create()'. get() returns only a single object whereas filter returns a dict(ish).
Put it in a try/except instead. So you'll have:
try:
event, created = cls.objects.get_or_create(
user=this_user
)
except cls.MultipleObjectsReturned:
event = cls.objects.filter(user=this_user).order_by('id').first()
This way if multiple objects are found, it handles the exception and changes the query to a filter to receive the multiple object queryset. No need to catch the Object.DoesNotExist as the create part creates a new object if no record is found.
I also face the same error:
get() returned more than one -- it returned 4!
The error was that I forgot to make a migration for the newly added fields in the model.
I'm trying to implement a simple function to like a post.
I have 4 models defined using Google App Engine; User, Blogpost, Like, Comments
below is the snippets:
class LikePost(db.Model):
user = db.ReferenceProperty(User)
blogpost = db.ReferenceProperty(Blogpost)
date = db.DateTimeProperty(auto_now_add = True)
class Comment(db.Model):
user = db.ReferenceProperty(User)
blogpost = db.ReferenceProperty(Blogpost)
content = db.TextProperty(required = True)
date = db.DateTimeProperty(auto_now_add = True)
I tried to call the method to like a post using below:
class LikePost(Handler):
def get(self,post_id):
blogpost = self.get_blogpost(post_id)
user = self.get_user_object()
if blogpost and user:
like = LikePost(user = user, blogpost = blogpost)
like.put()
self.redirect('/%s' % post_id)
else:
self.redirect('/login')
The reference to the method is as follow:
def get_user_object(self):
cookie = self.request.cookies.get('user_id')
if cookie:
user_id = check_secure_val(cookie)
if user_id:
user_id = cookie.split('|')[0]
key = db.Key.from_path('User', int(user_id))
user = db.get(key)
return user
def get_blogpost(self, post_id):
key = db.Key.from_path('Blogpost', int(post_id))
blogpost = db.get(key)
return blogpost
I got an error when trying to run the above :
__init__() got an unexpected keyword argument 'blogpost'
Anyone can explain what went wrong ?
You have defined your model as
class LikePost(db.Model):
Then you have defined your handler has
class LikePost(Handler):
Notice that they have the same name. So inside your get method what's in scope is your Handler subclass, which apparently does not expect a blogpost keyword argument to it's __init__ method. Simplest solution, rename one or the other or
from models import LikePost as LP
and use that
I've got an API endpoint called TrackMinResource, which returns the minimal data for a music track, including the track's main artist returned as an ArtistMinResource. Here are the definitions for both:
class TrackMinResource(ModelResource):
artist = fields.ForeignKey(ArtistMinResource, 'artist', full=True)
class Meta:
queryset = Track.objects.all()
resource_name = 'track-min'
fields = ['id', 'artist', 'track_name', 'label', 'release_year', 'release_name']
include_resource_uri = False
cache = SimpleCache(public=True)
def dehydrate(self, bundle):
bundle.data['full_artist_name'] = bundle.obj.full_artist_name()
if bundle.obj.image_url != settings.NO_TRACK_IMAGE:
bundle.data['image_url'] = bundle.obj.image_url
class ArtistMinResource(ModelResource):
class Meta:
queryset = Artist.objects.all()
resource_name = 'artist-min'
fields = ['id', 'artist_name']
cache = SimpleCache(public=True)
def get_resource_uri(self, bundle_or_obj):
return '/api/v1/artist/' + str(bundle_or_obj.obj.id) + '/'
The problem is, the artist field on Track (previously a ForeignKey) is now a model method called main_artist (I've changed the structure of the database somewhat, but I'd like the API to return the same data as it did before). Because of this, I get this error:
{"error": "The model '<Track: TrackName>' has an empty attribute 'artist' and doesn't allow a null value."}
If I take out full=True from the 'artist' field of TrackMinResource and add null=True instead, I get null values for the artist field in the returned data. If I then assign the artist in dehydrate like this:
bundle.data['artist'] = bundle.obj.main_artist()
...I just get the artist name in the returned JSON, rather than a dict representing an ArtistMinResource (along with the associated resource_uris, which I need).
Any idea how to get these ArtistMinResources into my TrackMinResource? I can access an ArtistMinResource that comes out fine using the URL endpoint and asking for it by ID. Is there a function for getting that result from within the dehydrate function for TrackMinResource?
You can use your ArtistMinResource in TrackMinResource's dehydrate like this (assuming that main_artist() returns the object that your ArtistMinResource represents):
artist_resource = ArtistMinResource()
artist_bundle = artist_resource.build_bundle(obj=bundle.obj.main_artist(), request=request)
artist_bundle = artist_resource.full_dehydrate(artist_bundle)
artist_json = artist_resource.serialize(request=request, data=artist_bundle, format='application/json')
artist_json should now contain your full artist representation. Also, I'm pretty sure you don't have to pass the format if you pass the request and it has a content-type header populated.