Django model doesn't save only after query - python

I've been working on Django for a while and now I came across this strange problem.
I'm adding a rating feature on a streaming website, for which I wrote a view that is called through a url:
url(r'^channel/rate/(?P<stream_id>[\d]*)/(?P<rate>[\d]*)/?$', 'eros.streaming.views.view_rate_channel',
name='view_rate_channel'),
def view_rate_channel(request,stream_id,rate):
if(stream_id and rate and request.user.is_authenticated()):
stream= Stream.objects.get(id=stream_id)
if stream not in request.user.channel.rated_streams.all():
if stream.channel.user != request.user:
channel=Channel.objects.get(stream=stream)
channel.rating= channel.rating+int(rate)
print("channel rating: "+str(channel.rating))
#this prints fine in any case
channel.n_voters = channel.n_voters +1
channel.save()
stream.rating= stream.rating+int(rate)
stream.n_voters= stream.n_voters+1
stream.save()
request.user.channel.rated_streams.add(stream)
request.user.channel.save()
return HttpResponseRedirect('/channel/'+str(stream.channel.id)+'/')
return HttpResponseRedirect('/channel/'+str(stream.channel.id)+'/')
When I check on the database, the changes I made on the Channel object after channel.save() are not saved, only the changes on the Stream object which I found weird.
So after doing some debugging I decided to comment this if, which I use so users can't rate a stream more than once:
##if stream not in request.user.channel.rated_streams.all():
And now the channel.save() is working!, the bad thing is that I can't let users to rate a stream more than once.
Heres a simplified version of the models:
class Channel(models.Model):
user = models.OneToOneField(User)
rating = models.IntegerField(default=0)
n_voters = models.IntegerField(default=0)
rated_streams = models.ManyToManyField('Stream', related_name="rated_streams")
description = models.TextField(default="")
class Stream(models.Model):
## I think that maybe this relation is what is causing me trouble (?):
channel = models.ForeignKey(Channel)
rating = models.IntegerField(default=0)
n_voters = models.IntegerField(default=0)
Is there any bad practice or bad query that I'm doing that is making this happen? Thanks a lot in advance.

Using channel = stream.channel instead of channel = Channel.objects.get(stream=stream) fixed this.

Related

Looping over a specific field in a django form

Learning Django by creating an eBay like bidding application.
One of my models is a simple bid class that will record every user's bid for a particular listing.
models.py
class Bid(models.Model):
bid = models.DecimalField(max_digits=10, decimal_places=2)
user = models.ForeignKey(User, on_delete=models.CASCADE)
listing = models.ForeignKey(Listing, on_delete=models.CASCADE)
forms.py
def listing_view(request, id):
form = BidForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
instance.user = request.user
instance.listing_id = id
# check bid is higher than starting bid or other bids or flash error message
current_bid = instance.bid
starting_bid = instance.listing.starting_bid
query = Bid.objects.all().filter(listing=id)
In forms.py, I am writing a view to validate that the bid the user entered is larger than existing bids. It's incomplete because I am stuck on creating this comparison.
The easy way is to loop over the 'query' variable and do the comparison, but is there a more elegant solution?
I found a solution using the all() function, something like:
all(current_bid > i in my_list)
But this only works for comparing against a list, not form objects
Is there a way to loop over query (i.e. for each in query) and get check whether current_bid is greater than all of the 'each.bid' in 1 line?
Something like this:
all(current_bid > i for i.bid in query)
Sadly, this doesn't work. I get a NameError - name 'i' is not defined.
Thanks!
This line here:
all(current_bid > i for i.bid in query)
needs to be changed to something like this:
all(current_bid > i.bid for i in query)
Sometimes list comprehensions are confusing so I like to imagine them as normal for loops. Here's my interpretation of what you're trying to do (no guarantees of correctness):
is_biggest_bid = True
for i in query:. # writing i.bid wouldn't make sense here
if i.bid > current_bid:
is_biggest_bid = False
break
Hope that helps.

Django 1.11 Image Gallery with Django Filer

Problem
I need to display a gallery of images on a product page. This worked when we were at Django 1.6, but have since upgraded to Django 1.11 (Big Process). I am now stuck at how to get this to work within the new environment. Right now clicking Add Image brings up a pop up where I can select the image, and the regions associated with it (US, Canada, Spain, Etc..), but after clicking "Save" The popup title changes to Popup closing... and never closes - also the image is not added to the gallery. The image I upload itself IS added to the rest of the Images within filer, however it is not added to the ProductGallery Model.
What I've Got
Django: 1.11.7
Django-Filer: 1.2.7
Django-Suit: 0.2.25
Vanilla-Views: 1.0.4
I have Product models, these products have a many to many relationship to a ProductGallery model like so:
class Product(models.Model):
gallery = models.ManyToManyField('products.ProductGallery')
The ProductGallery is supposed to house Images and Videos allowing for upload of either, and providing one list to iterate through on the front end for display purposes.
The ProductGallery is defined as:
class ProductGallery(models.Model):
limit = models.Q(app_label='media', model='image') | models.Q(app_label='media', model='video')
order = models.PositiveIntegerField(default=0)
content_type = models.ForeignKey(ContentType, limit_choices_to=limit)
object_id = models.PositiveIntegerField(db_index=True)
content_object = generic.GenericForeignKey('content_type', 'object_id')
class Meta:
ordering = ('order',)
def __str__(self):
return six.text_type(self.content_object)
where media.image is defined as: (I'll ignore video for the time being)
class Image(CountryInfoModel, models.Model):
image = FilerImageField(null=True, blank=True)
def __str__(self):
return str(self.image.name or self.image.original_filename)
I've got a view for Adding new Media like so:
class AddMedia(LoginRequiredMixin, StaffuserRequiredMixin, JsonRequestResponseMixin, GenericView):
require_json = True
def post(self, request, *args, **kwargs):
object_id = self.request_json["objectId"]
object_var = self.request_json["objectVarName"]
content_type_id = self.request_json["contentType"]
order = self.request_json["order"]
media_id = self.request_json["mediaId"]
media_type = self.request_json["mediaType"]
content_type = _get_content_type_or_404(content_type_id)
content_object = _get_object_or_404(content_type, object_id)
model_var = getattr(content_object, object_var)
try:
if media_type.lower() == "image":
obj = Image.objects.get(pk=media_id)
elif media_type.lower() == "video":
obj = Video.objects.get(pk=media_id)
else:
raise Http404("Invalid mediaType parameter: {0}".format(media_type))
media_item = model_var.create(content_object=obj)
media_item.order = order
media_item.save()
except model_var.model.DoesNotExist:
pass
return self.render_json_response({'message': "Order successfully updated"})
And I think thats all the pieces there are to this. I am lost on why when I click "save" the Image is not saved to the ProductGallery model at all. I'd be happy to provide more context if needed, and any help is very much appreciated.
Just in case anyone else comes across this and wants to know how it was fixed.
It turns out that some of the django-admin template functionality had been overwritten and was causing some issues.
Specifically this project had overwritten parts of the save button functionality. The function dismissAddRelatedObjectPopup used to be named dismissAddAnotherPopup
These functions were overwritten to provide the custom functionality outlined above with the ProductGallery. Django went to call the function, but this was throwing an error on the popup related to something called SelectBoxwhich then broke the ajax call that was needed to save the model correctly.
Hopefully this can help someone in the future!

How to handle concurrency with django queryset get method?

I'm using django (1.5 with mysql) select_for_update method for fetching data from one model and serve this data to user upon request, but when two user request at simultaneously it returns same data for both of the user, see the sample code below
models.py
class SaveAccessCode(models.Model):
code = models.CharField(max_length=10)
class AccessCode(models.Model):
code = models.CharField(max_length=10)
state = models.CharField(max_length=10, default='OPEN')
views.py
def view(request, code):
# for example code = 234567
acccess_code = AccessCode.objects.select_for_update().filter(
code=code, state='OPEN')
acccess_code.delete()
SaveAccessCode.objects.create(code=code)
return
Concurrent request will generate two records of SaveAccessCode with same code, Please guide me how to handle this scenario in better way
You need to set some flag on the model when doing select_for_update, something like:
qs.first().update(is_locked=True)`
and before that should do select like
qs = self.select_for_update().filter(state='OPEN', is_locked=False).order_by('id')
Then after the user, I presume, has done something with it and saved, set the flag is_locked=False and save.
Also make the fetch_available_code as a #staticmethod.

How do I test a Django model with ImageSpecField?

I got a following model:
class Room(models.Model):
order = models.SmallIntegerField()
name = models.CharField(max_length=20)
background = models.ImageField(upload_to='room_background', blank=False, null=False)
background_preview = ImageSpecField(source='background', processors=[ResizeToFit(300, 400)])
def serialize(self):
room_dict = model_to_dict(self)
room_dict['background_preview_url'] = self.background_preview.url
return room_dict
I'm not using room object directly on my views, instead I convert them to dict, extending with the 'background_preview_url' key.
Now I want to write some Django tests, using serialized room objects. The issue is that if I just do:
test_room = Room(order=1)
test_room.save
test_room.serialize()
The ImageKit throws a MissingSource error, as there's no background image in my test room to generate preview from.
How do I better overcome that in my tests? Should I carry a fixture with the backgroud images?
Or should I write second serialize_for_test() method?
Or maybe I can instanciate the Room() with some test value for the background_preview field? - I tried this but the direct Room(background_preview='fake_url') didn't work.
Thanks.
The solution, which worked for me:
from django.core.files.uploadedfile import SimpleUploadedFile
test_room.image = SimpleUploadedFile(name='foo.gif', content=b'GIF87a\x01\x00\x01\x00\x80\x01\x00\x00\x00\x00ccc\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02D\x01\x00')
test_room.save

Django. Python. How to get current user's activity log?

I need to pass the current user's entire activity log to an html page, but it seems I cannot find any helpful solution regarding the same.
Is it possible? If yes, please direct me in the right way?
Thanks in advance!
Update:
I found a solution making use of a get() call to django's LogEntry model, but I am clueless as to what shall be the appropriate parameters for doing the same.
Yet another UPDATE:
I am looking for a way to access the activity log of a particular user from the django's log entries WITHOUT saving it to any database
Take a look below listed.....Hope it will help::
lets example::
Create Two Field in Models:
last_activity_ip = models.IPAddressField()
last_activity_date = models.DateTimeField(default = datetime(1960, 1, 1))
user = models.OneToOneField(User, primary_key=True)
Since the User and UserActivity models are now related one-to-one we can now type:
Run the Query Like this:
a = User.objects.get(username__exact='mpcabd')
print a.useractivity.last_activity_ip
b = UserActivity.objects.get(user=a)
print b.user.username
** To track the activity use this **
activity = None
try:
activity = request.user.useractivity
except:
activity = UserActivity()
activity.user = request.user
activity.last_activity_date = datetime.now()
activity.last_activity_ip = request.META['REMOTE_ADDR']
activity.save()
return
activity.last_activity_date = datetime.now()
activity.last_activity_ip = request.META['REMOTE_ADDR']
activity.save()
This question don't has a short answer, you can use sentry project by side of main django project. below link can helping you:
https://sentry.readthedocs.org/en/latest/

Categories