Save generic images from XML nodes - django

I'm trying to update my records using XML...so far the first part of the task is done....what I'm wondering is how to get my images onto the saved object (I'm using imagekit for the image handling BTW). My models look like this:
class Photo(ImageModel):
name = models.CharField(max_length=100)
original_image = models.ImageField(upload_to='photos')
num_views = models.PositiveIntegerField(editable=False, default=0)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
class IKOptions:
spec_module = 'my_app.specs'
cache_dir = 'photos'
image_field = 'original_image'
save_count_as = 'num_views'
class Room(models.Model):
...
images = generic.GenericRelation('Photo', blank=True, null=True)
...
The XML that I'm using for this is as below:
<room>
<sq_ft>...</sq_ft>
<size>...</size>
<bedrooms>...</bedrooms>
<images>
<image>photos/IMG_3406.JPG</image>
<image>photos/IMG_3416.JPG</image>
<image>photos/IMG_3409.JPG</image>
</images>
</room>
My question is how to get the images for a given room when looping through the XML file and save them against that record.
UPDATE 1
I've tried this bit so far:
if room.getElementsByTagName('image'):
photo = ""
for v in room.getElementsByTagName('images'):
photo = v.childNodes[0].nodeValue
room_photo = Photo.objects.create(content_object = room,
object_id = room.id, original_image = photo)
This does save the photo (somewhat), but then the original_image field is always blank, meaning that I'm doing something wrong in the above piece of code. Any ideas?

Have you taken a look at xml_models? Not sure if it's exactly right for you because I'm not 100% sure of what you're asking. However, it does take care of relationships with models that use XML very smoothly, so may solve your problem incidentally :-)
I think xml_models will work for you. Let me know!

Figured this out as the solution finally:
imagelist = room.getElementsByTagName('image')
if imagelist:
for child in imagelist:
photo = child.childNodes[0].nodeValue
room_photo = Photo.objects.create(content_object = room,
object_id = room.id, original_image = photo)
Thought this might help someone with a similar problem later on.

Related

Django: Run a function if certain condition is met

I have a Word model, where a user can add words and various fields, like this (shortened version):
class Word(models.Model):
target_word = models.CharField()
source_word = models.CharField()
add_to_review = models.BooleanField(default=True)
example_sentence = models.CharField()
image = models.ImageField(upload_to='images/',blank=True)
audio = models.FileField(upload_to='audio/',blank=True)
I also have a Flashcard model where a user can add and study flashcards. Here I show only the relevant code:
class FlashcardManager(models.Manager):
def create_flashcard(self, user, question, answer, deck_name):
try:
deck = Deck.objects.get(owner=user, name=deck_name)
except ObjectDoesNotExist:
deck = Deck(owner=user, name=deck_name)
deck.save()
self.create(owner=user, question=question, answer=answer,
deck=deck)
return deck
class Flashcard(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE)
deck = models.ForeignKey(Deck, on_delete=models.CASCADE)
question = models.TextField()
answer = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
last_shown_at = models.DateTimeField(auto_now_add=True)
next_due_date = models.DateTimeField(default=timezone.now)
difficulty = models.FloatField(default=2.5)
consec_correct_answers = models.IntegerField(default=0)
objects = FlashcardManager()
def __str__(self):
return self.question
When a user creates a new word, I want to give them the option of automatically creating a flashcard using the info provided. In other words, question = target_word, answer = source_word, and the deck name can either be some default value, or I can add a field to the Word model. Is there a way I can do this by using the add_to_review field of the Word model and the create_flashcard method of the FlashcardManager model? I've tried adding a function to my Word model that runs if add_to_review is true. I don't get any errors, but nothing happens.
I know one option would be to just combine the two models... but I do have my own reasons for keeping them seperate. I might still do that, but I was just wondering if what I am trying to do is possible / feasible? I'm not really sure what exactly to google, so haven't been able to find any info on this. So any advice would be great, thanks!
Not sure if this is the best way, but it worked. Initially I had problems with the signal not being called, but this got fixed when I moved it to my models.py file instead of having it separate in a signals.py file.
#receiver(post_save, sender=Word)
def flash_from_word(sender, created, instance, **kwargs):
if created:
flash_wanted = Word.objects.filter(add_to_review=True)
instance._meta.model.objects.all()
target_word = instance.target_word
source_word = instance.source_word
deck_name = instance.deck_name
user = instance.user
if flash_wanted:
flash = Flashcard.objects.create(owner=user, question=target_word,answer=source_word,deck=Deck.objects.get(name=deck_name,owner=user))
post_save.connect(flash_from_word, sender=Word)

Django substract two fields from related model

With this models:
class Vine(models.Model):
autor = models.ForeignKey(Viner,related_name='autor')
titulo = models.CharField(max_length=450)
estado = models.CharField(choices=ESTADOS_VINE, max_length=30)
objects = models.Manager()
custom_object = managers.VineManager()
and the model for the votes
class Voto(models.Model):
user = models.ForeignKey(MyUser)
submit_date = models.DateTimeField(auto_now_add=True)
vine = models.ForeignKey(Vine)
valoracion = models.BooleanField(default=False)
and the class for the Favorites (This is working fine yet)
class Favorito(models.Model):
date = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='favoritos')
I have this 'query' in Django.
vines = Vine.custom_object.filter(estado=2).\
annotate(favoritosCount=Count('favoritos', distinct=True)).\
filter(voto__valoracion=False).annotate(disLikesCount=Count('voto', distinct=True))\
.annotate(likesCount=Count('voto', distinct=True)).filter(voto__valoracion=True)
But the second filter is not working because of the first.
Basically what I want is to get the sum of 'positive votes' - 'negative votes' as a field and order by it.
Could anyone please help me?
Thank you in advance
AFAIK you can't do that query with the ORM. You might be able to do it with a raw query.
I think It's easier if you add a count field to your Vine model and order by it. Then update that count field every time there's a new Voto.
Something like this:
from django.db.models import F
class Vine(models.Model):
...
votos = models.IntegerField()
class Meta:
ordering = ('votos',)
class Voto(models.Model):
...
def save(self):
"""When saving new Voto instance, update related Vine."""
if not self.pk:
new_vote = 1 if self.valoracion else -1
self.vine.update(votos=F('votos') + new_vote)
return super(Voto, self).save()
PS: If you want to know more about that F expression.

Querying all objects that don't exist in another model

I have two models, Picture and SubmittedPicture as follows:
class Picture(models.Model):
user = models.ForeignKey(User)
pic = ImageField(upload_to='userpics/%Y/%m/%d/%H')
class SubmittedPicture(models.Model):
picture = models.ForeignKey(Picture, unique=True)
description = models.TextField()
submitted_time = models.DateTimeField(auto_now_add=True)
Now, I need to query for all Pictures which do not have a corresponding SubmittedPicture.
I tried several options, but none of them was functional.
I read through the Django-doc, but couldn't find something useful.
Thanks in advance!
Picture.objects.filter(submittedpicture__isnull=True)

Add a timestamp on a boolean field

I have a video object, which an administrator can feature. I want to be able to sort those featured videos by the date they were made featured.
Here are the models I currently have --
class VideoMedia(models.Model):
uploaded_by = models.ForeignKey('UserProfile')
video = models.ImageField(upload_to='videos')
info = models.ForeignKey('VideoInfo', blank = True, null=True)
class VideoInfo(models.Model):
title = models.CharField(max_length=256)
featured = models.BooleanField # need time also
...
My relevant view code looks like this --
video_set = VideoInfo.objects.all()
if sort == 'featured':
videos = video_set.filter(featured=1) # .order_by('timestamp') ?
I tried adding a FK to the featured field, but it makes it very difficult for me in the view/template to display the correct data.
class FeaturedVideos(models.Model):
video = models.ForeignKey(VideoMedia)
timestamp = models.DateTimeField(auto_now_add=True)
# in view
if sort == 'featured':
videos = FeaturedVideos.objects.order_by('timestamp')
# this doesn't work, because I need to be relative to the VideoInfo model
# for the information to display correctly in the template
What would be the most straightforward way to accomplish this task? Thank you.
In the past I have used a nullable datetimefield as a boolean. When it is null then you know it is false, and when it has a date you know it is true, and the date and time that field was set to True.
It is a cheap and easy way to get two uses out of one field. You can also add some simple properties to your model to make it easier when using templates. Here is a pretty quick example.
class VideoInfo(models.Model):
title = models.CharField(max_length=256)
featured = models.DateTimeField(null=True, blank=True)
#property
def is_featured(self):
if self.featured:
return True
else:
return False

Automatically update images

I'd like to implement a functionality in an app of mine, but I don't know how to go about it. What I want is this: I have a model class that uses imagekit to save its images, and I'd like to have the users being able to update the images easily for the vehicles without having to edit each respective vehicle record.
How they'll do this is that there will be a folder named originals and it'll contain folders for each vehicle in the format <stock_number>/PUBLIC If a user moves images into the PUBLIC folder for a vehicle, when the script is executed, it'll compare those images with the current ones and update them if those in the PUBLIC folder are newer. If the record has no images, then they will be added. Also, if the images have been deleted from the site_media directory, then their links should be deleted from the database.
How can I go about this in an efficient way? My models are as below:
class Photo(ImageModel):
name = models.CharField(max_length = 100)
original_image = models.ImageField(upload_to = 'photos')
num_views = models.PositiveIntegerField(editable = False, default=0)
position = models.ForeignKey(PhotoPosition)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
class IKOptions:
spec_module = 'vehicles.specs'
cache_dir = 'photos'
image_field = 'original_image'
save_count_as = 'num_views'
class Vehicle(models.Model):
objects = VehicleManager()
stock_number = models.CharField(max_length=6, blank=False, unique=True)
vin = models.CharField(max_length=17, blank=False)
....
images = generic.GenericRelation('Photo', blank=True, null=True)
Progress Update
I've tried out the code, and while it works, I'm missing something as I can get the image, but after that, they aren't transferred into the site_media/photos directory...am I suppossed to do this or imagekit will do this automatically? I'm a bit confused.
I'm saving the photos like so:
Photo.objects.create(content_object = vehicle, object_id = vehicle.id,
original_image = file)
My advice is running django script in a crontab job, lets say, 5 in 5 minutes.
The script would dive into the image folders and compare the images with the records.
A simplified example:
# Set up the Django Enviroment
from django.core.management import setup_environ
import settings
setup_environ(settings)
import os
from your_project.your_app.models import *
from datetime import datetime
vehicles_root = '/home/vehicles'
for stock_number in os.listdir(vehicles_root):
cur_path = vehicles_root+'/'+stock_number
if not os.path.isdir(cur_path):
continue # skip non dirs
for file in os.listdir(cur_path):
if not isfile(cur_path+'/'+file):
continue # skip non file
ext = file.split('.')[-1]
if ext.lower() not in ('png','gif','jpg',):
continue # skip non image
last_mod = os.stat(cur_path+'/'+file).st_mtime
v = Vehicle.objects.get(stock_number=stock_number)
if v.last_upd < datetime.fromtimestamp(last_mod):
# do your magic here, move image, etc.
v.last_upd = datetime.now()
v.save()