# HG changeset patch # User Harris Baptiste # Date 1471533766 -7200 # Node ID 8a41415e1ab12fc68d65bb4158684892a1f2a8a4 # Parent c68983a2efacd16a73519c5810c36059bbe81327# Parent 93b706801905876cf7414762f0c512a1ddff63b3 merge diff -r c68983a2efac -r 8a41415e1ab1 README.md --- a/README.md Thu Aug 18 17:20:22 2016 +0200 +++ b/README.md Thu Aug 18 17:22:46 2016 +0200 @@ -85,20 +85,22 @@ By default, the app is accessible through http://127.0.0.1:8000/home +### 3. Importing data from CSV -### 3. Fixture loaded data +Make sure to have the following in the same folder: -* User: contributeur1, password: firstuser -* User: contributeur2, password: seconduser +* All the images to import. The image names must match their respective item inventory number. +* A csv file that contains the metadata for the items you will import +* A json fixture file for initializing the collection in the database. (Optional if you want to import images in an existing collection) +* A json fixture file for the metacategories that will be linked to the collection. -* Collection (name): ingres -* Image (ref): 1234567890 # You will need to move napoleon.jpg into web/media/uploads in order for the app to load the image properly -* Annotation (guid): 34ae39ae-a9a2-4736-bc59-ba6f00e37f52 - -To access the loaded annotation, follow: +The following django manage.py command is used to import collection data and images: - /collections/ingres/images/26aec320-dcfe-4cbc-b912-6a6c13e8916e/annotations/34ae39ae-a9a2-4736-bc59-ba6f00e37f52/detail - /collections/ingres/images/26aec320-dcfe-4cbc-b912-6a6c13e8916e/annotations/34ae39ae-a9a2-4736-bc59-ba6f00e37f52/edit + python manage.py importimages <:export-csv-path> --encoding <:encoding> --collection-fixture <:collection_fixture_NAME> (OR --collection-id <:collection_id> --metacategories_fixture <:metacategories_fixture_NAME> -The annotation owner is contributeur1, if you try to edit it as another user, it will create the revision but will not publish it in the current state of the project. - +Notes: +* The export csv path will be used to find everything else (images and fixtures files). +* If the csv file is not encoded in utf-8, you MUST provide --encoding so the csv file can be read +* You MUST provide either --collection-fixture or --collection-id, else the command doesn't know to which collection the objects will belong to. +* The command will first parse the csv, then create the objects in the database (Item and ItemMetadata), then move the images to the settings.MEDIA_ROOT+/uploads/ folder after converting them to JPEG, then create the database objects for the images. The command will ignore any csv row that lacks an image or any csv row that already has a database entry for the collection (INV number is used to test if a database entry exists). + diff -r c68983a2efac -r 8a41415e1ab1 src/iconolab/forms/comments.py --- a/src/iconolab/forms/comments.py Thu Aug 18 17:20:22 2016 +0200 +++ b/src/iconolab/forms/comments.py Thu Aug 18 17:22:46 2016 +0200 @@ -8,13 +8,20 @@ from django.utils.encoding import force_text from django.utils import timezone from iconolab.models import MetaCategory +import logging + +logger = logging.getLogger(__name__) class IconolabCommentForm(XtdCommentForm): - metacategories = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, queryset=MetaCategory.objects.all(), required=False) email = forms.EmailField(required=False) - + metacategories = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, queryset=None, required=False) + def __init__(self, *args, **kwargs): super(IconolabCommentForm, self).__init__(*args, **kwargs) + self.collection = self.target_object.image.item.collection + logger.debug(self.fields) + self.fields["metacategories"].queryset = self.collection.metacategories.all() + logger.debug(self.fields["metacategories"].queryset) self.fields.pop('email') def get_comment_create_data(self): diff -r c68983a2efac -r 8a41415e1ab1 src/iconolab/management/commands/importimages.py --- a/src/iconolab/management/commands/importimages.py Thu Aug 18 17:20:22 2016 +0200 +++ b/src/iconolab/management/commands/importimages.py Thu Aug 18 17:22:46 2016 +0200 @@ -30,6 +30,12 @@ default=False, help='insert extracted data into the specified collection instead of trying to load a collection fixture', ) + parser.add_argument( + '--metacategories-fixture', + dest='metacategories_fixture', + default=False, + help='add metacategories to the created collection from a fixture file', + ) def handle(self, *args, **options): pp = pprint.PrettyPrinter(indent=4) @@ -60,6 +66,22 @@ raise ValueError("!!! Collection with primary key "+options.get("collection_id")+" was not found, aborting !!!") else: raise ValueError("!!! No collection fixture or collection id, aborting because we can't properly generate data. !!!") + + if options.get("metacategories_fixture"): + print("## Finding metacategories fixture json data in "+source_dir) + metacategories_fixture_path = os.path.join(source_dir, options.get("metacategories_fixture")) + if not os.path.isfile(metacategories_fixture_path): + print("### No "+options.get("metacategories_fixture")+".json file was found in the source directory") + raise ValueError("!!! Fixture file "+metacategories_fixture_path+" was not found !!!") + with open(metacategories_fixture_path) as metacategories_fixture_file: + metacategories_data = json.loads(metacategories_fixture_file.read()) + for metacategory in metacategories_data: + if options.get("collection_fixture") and metacategory["fields"].get("collection", False) != collection_data[0].get("pk"): + print(metacategory["fields"].get("collection", False)) + raise ValueError("!!! The fixture should only contain metacategories for the imported collection !!!") + elif options.get("collection_id") and metacategory["fields"].get("collection", False) != collection.id: + raise ValueError("!!! The fixture should only contain metacategories for the imported collection !!!") + # We read the csv csvreader = csv.DictReader(open(options.get("csv_path"), encoding=options.get("encoding")), delimiter=";") print("# Extracting data from csv file and storing it in standardized format") @@ -97,6 +119,20 @@ collection = Collection.objects.get( pk = collection_data[0]["pk"] ) + if collection.image: + collection_image_path = os.path.join(settings.MEDIA_ROOT, str(collection.image)) + if not os.path.isfile(collection_image_path): + print("### Moving collection image") + _ , collection_image_name = os.path.split(collection_image_path) + try: + col_im = ImagePIL.open(os.path.join(source_dir, collection_image_name)) + print("##### Generating or copying jpeg for "+collection_image_name) + col_im.thumbnail(col_im.size) + col_im.save(collection_image_path, "JPEG", quality=100) + except Exception as e: + print(e) + if options.get("metacategories_fixture"): + call_command("loaddata", metacategories_fixture_path) print("## Converting image and moving it to static dir, creating Image and Item objects") target_dir = os.path.join(settings.MEDIA_ROOT, "uploads") print("### Images will be stored in "+target_dir) diff -r c68983a2efac -r 8a41415e1ab1 src/iconolab/models.py --- a/src/iconolab/models.py Thu Aug 18 17:20:22 2016 +0200 +++ b/src/iconolab/models.py Thu Aug 18 17:22:46 2016 +0200 @@ -266,6 +266,22 @@ return self.revisions.filter(state=AnnotationRevision.AWAITING).distinct().count() @property + def accepted_revisions_count(self): + return self.revisions.filter(state=AnnotationRevision.ACCEPTED).distinct().count() + + @property + def rejected_revisions_count(self): + return self.revisions.filter(state=AnnotationRevision.REJECTED).distinct().count() + + @property + def studied_revisions_count(self): + return self.revisions.filter(state=AnnotationRevision.STUDIED).distinct().count() + + @property + def total_revisions_count(self): + return self.revisions.distinct().count() + + @property def collection(self): return self.image.collection @@ -495,7 +511,7 @@ (COLLECTION_ADMINS, 'collection admins'), ) - collection = models.ForeignKey(Collection) + collection = models.ForeignKey(Collection, related_name="metacategories") label = models.CharField(max_length=255) triggers_notifications = models.IntegerField(choices=NOTIFIED_USERS, default=NONE) diff -r c68983a2efac -r 8a41415e1ab1 src/iconolab/static/iconolab/css/iconolab.css --- a/src/iconolab/static/iconolab/css/iconolab.css Thu Aug 18 17:20:22 2016 +0200 +++ b/src/iconolab/static/iconolab/css/iconolab.css Thu Aug 18 17:22:46 2016 +0200 @@ -117,4 +117,29 @@ vertical-align: top; margin-top: 15px; margin-right: 15px; +} + +/* COLLECTION HOME PAGE */ +.image-list-wrapper{ + margin-top: 15px; + margin-left:10px; +} +li.image-list-li{ + margin-bottom: 5px; + width: 370px; + height: 350px; + vertical-align:middle; + padding:5px; +} +.image-list-image-container{ + position: relative; +} +.object-info{ + margin-bottom:10px; +} +.collection-home-item-btn{ + margin-bottom:5px; +} +.collection-home-tab{ + cursor: pointer; } \ No newline at end of file diff -r c68983a2efac -r 8a41415e1ab1 src/iconolab/templates/iconolab/collection_home.html --- a/src/iconolab/templates/iconolab/collection_home.html Thu Aug 18 17:20:22 2016 +0200 +++ b/src/iconolab/templates/iconolab/collection_home.html Thu Aug 18 17:22:46 2016 +0200 @@ -7,27 +7,60 @@ {% load iconolab_tags %} {% block content %} -

Fonds {{collection.verbose_name}}

- - -

Images du fonds

-