Andy Mikhailenko avatar Andy Mikhailenko committed 9def48f

Rename package autoslugfield to autoslug. Update distutils and licensing stuff, clean up.

Comments (0)

Files changed (11)

 egg-info
 ^build/
 ^dist/
+^temp/
 ~$
 \.pyc$
+                 GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+  This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+  0. Additional Definitions.
+
+  As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+  "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+  An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+  A "Combined Work" is a work produced by combining or linking an
+Application with the Library.  The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+  The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+  The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+  1. Exception to Section 3 of the GNU GPL.
+
+  You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+  2. Conveying Modified Versions.
+
+  If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+   a) under this License, provided that you make a good faith effort to
+   ensure that, in the event an Application does not supply the
+   function or data, the facility still operates, and performs
+   whatever part of its purpose remains meaningful, or
+
+   b) under the GNU GPL, with none of the additional permissions of
+   this License applicable to that copy.
+
+  3. Object Code Incorporating Material from Library Header Files.
+
+  The object code form of an Application may incorporate material from
+a header file that is part of the Library.  You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+   a) Give prominent notice with each copy of the object code that the
+   Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the object code with a copy of the GNU GPL and this license
+   document.
+
+  4. Combined Works.
+
+  You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+   a) Give prominent notice with each copy of the Combined Work that
+   the Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the Combined Work with a copy of the GNU GPL and this license
+   document.
+
+   c) For a Combined Work that displays copyright notices during
+   execution, include the copyright notice for the Library among
+   these notices, as well as a reference directing the user to the
+   copies of the GNU GPL and this license document.
+
+   d) Do one of the following:
+
+       0) Convey the Minimal Corresponding Source under the terms of this
+       License, and the Corresponding Application Code in a form
+       suitable for, and under terms that permit, the user to
+       recombine or relink the Application with a modified version of
+       the Linked Version to produce a modified Combined Work, in the
+       manner specified by section 6 of the GNU GPL for conveying
+       Corresponding Source.
+
+       1) Use a suitable shared library mechanism for linking with the
+       Library.  A suitable mechanism is one that (a) uses at run time
+       a copy of the Library already present on the user's computer
+       system, and (b) will operate properly with a modified version
+       of the Library that is interface-compatible with the Linked
+       Version.
+
+   e) Provide Installation Information, but only if you would otherwise
+   be required to provide such information under section 6 of the
+   GNU GPL, and only to the extent that such information is
+   necessary to install and execute a modified version of the
+   Combined Work produced by recombining or relinking the
+   Application with a modified version of the Linked Version. (If
+   you use option 4d0, the Installation Information must accompany
+   the Minimal Corresponding Source and Corresponding Application
+   Code. If you use option 4d1, you must provide the Installation
+   Information in the manner specified by section 6 of the GNU GPL
+   for conveying Corresponding Source.)
+
+  5. Combined Libraries.
+
+  You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+   a) Accompany the combined library with a copy of the same work based
+   on the Library, uncombined with any other library facilities,
+   conveyed under the terms of this License.
+
+   b) Give prominent notice with the combined library that part of it
+   is a work based on the Library, and explaining where to find the
+   accompanying uncombined form of the same work.
+
+  6. Revised Versions of the GNU Lesser General Public License.
+
+  The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+  Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+  If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
+django-autoslug is a pluggable application for Django web framework
+containing an extended version of SlugField class shipped with Django itself.
+django-autoslug is written by Andy Mikhailenko <andy at neithere dot net>.
+See the file AUTHORS for the complete list of authors of this application.
+
+Please feel free to file issues and/or submit patches.
+
+django-autoslug is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public License as
+published by the Free Software Foundation; either version 3 of the
+License, or (at your option) any later version.
+
+django-autoslug is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this program; see the file COPYING.LESSER. If not,
+see <http://gnu.org/licenses/>.
+See the follow URL to see all work planned for future releases:
+
+    http://bitbucket.org/neithere/django-autoslug/issues/?status=open
+
+Please feel free to file issues and/or submit patches.

autoslug/__init__.py

+# -*- coding: utf-8 -*-
+#
+#  Copyright (c) 2008—2009 Andy Mikhailenko
+#
+#  This file is part of django-autoslug.
+#
+#  django-autoslug is free software under terms of the GNU Lesser
+#  General Public License version 3 (LGPLv3) as published by the Free
+#  Software Foundation. See the file README for copying conditions.
+#
+
+__author__  = 'Andy Mikhailenko'
+__license__ = 'GNU Lesser General Public License (GPL), Version 3'
+__url__     = 'http://bitbucket.org/neithere/django-autoslugfield/'
+__version__ = '1.0'

autoslug/fields.py

+# -*- coding: utf-8 -*-
+#
+#  Copyright (c) 2008—2009 Andy Mikhailenko
+#
+#  This file is part of django-autoslug.
+#
+#  django-autoslug is free software under terms of the GNU Lesser
+#  General Public License version 3 (LGPLv3) as published by the Free
+#  Software Foundation. See the file README for copying conditions.
+#
+
+# django
+from django.db.models.fields import DateField, SlugField
+
+# app
+from autoslug.settings import slugify
+
+class AutoSlugField(SlugField):
+    """
+    AutoSlugField is a slug field that can automatically do the following on save:
+    - populate itself from another field (using 'populate_from'),
+    - use custom slugify() function (can be defined in settings), and
+    - preserve uniqueness of the value (using 'unique' or 'unique_with').
+    
+    None of the tasks is mandatory, i.e. you can have auto-populated non-unique fields,
+    manually entered unique ones (absolutely unique or within a given date) or both.
+
+    Uniqueness is preserved by checking if the slug is unique with given constraints
+    (unique_with) or globally (unique) and adding a number to the slug to make
+    it unique. See examples below.
+    
+    IMPORTANT: always declare attributes with AutoSlugField *after* attributes
+    from which you wish to 'populate_from' or check 'unique_with' because autosaved
+    dates and other such fields must be already processed before checking occurs.
+    
+    Usage examples:
+    
+    # slugify but allow non-unique slugs
+    slug = AutoSlugField()
+
+    # globally unique, silently fix on conflict ("foo" --> "foo-1".."foo-n")
+    slug = AutoSlugField(unique=True)
+    
+    # autoslugify value from title attr; default editable to False
+    slug = AutoSlugField(populate_from='title')
+    
+    # same as above but force editable=True
+    slug = AutoSlugField(populate_from='title', editable=True)
+
+    # ensure that slug is unique with given date (not globally)
+    slug = AutoSlugField(unique_with='pub_date')
+    
+    # ensure that slug is unique with given date AND category
+    slug = AutoSlugField(unique_with=('pub_date','category'))
+    
+    # mix above-mentioned behaviour bits
+    slug = AutoSlugField(populate_from='title', unique_with='pub_date')
+
+    Please don't forget to declare your slug attribute after the fields
+    referenced in `populate_from` and `unique_with`.
+    """
+    def __init__(self, *args, **kwargs):
+        kwargs['max_length'] = kwargs.get('max_length', 50)
+
+        if kwargs['unique'] and kwargs['unique_with']:
+            #raise KeyError, 'AutoSlugField cannot
+
+        # autopopulated slug is not editable unless told so
+        self.populate_from = kwargs.pop('populate_from', None)
+        if self.populate_from:
+            kwargs.setdefault('editable', False)
+
+        # unique_with value can be string or tuple
+        self.unique_with = kwargs.pop('unique_with', ())
+        if isinstance(self.unique_with, basestring):
+            self.unique_with = (self.unique_with,)
+        
+        # backward compatibility
+        if kwargs.get('unique_with_date'):
+            from warnings import warn
+            warn('Using unique_with_date="foo" in AutoSlugField is deprecated, '\
+                 'use unique_with=("foo",) instead.', DeprecationWarning)
+            self.unique_with += (kwargs['unique_with_date'],)
+
+        # force full uniqueness unless more granular is specified
+        if not self.unique_with:
+            kwargs.setdefault('unique', True)
+
+        # Set db_index=True unless it's been set manually.
+        if 'db_index' not in kwargs:
+            kwargs['db_index'] = True
+        super(SlugField, self).__init__(*args, **kwargs)
+
+    def pre_save(self, instance, add):
+        # get currently entered slug
+        value = self.value_from_object(instance)
+        
+        # autopopulate (unless the field is editable and has some value)
+        if value:
+            slug = slugify(value)
+        elif self.populate_from: # and not self.editable:
+            slug = slugify(getattr(instance, self.populate_from))
+
+        if not slug:
+            # no incoming value,  use model name
+            slug = instance._meta.module_name
+
+        assert slug, 'slug is defined before trying to ensure uniqueness'
+
+        # ensure the slug is unique (if required)
+        if self.unique or self.unique_with:
+            slug = self._generate_unique_slug(instance, slug)
+
+        assert slug, 'value is filled before saving'
+
+        setattr(instance, self.name, slug) # XXX do we need this?
+
+        return slug
+        #return super(AutoSlugField, self).pre_save(instance, add)
+
+    def _generate_unique_slug(self, instance, slug):
+        """
+        Generates unique slug by adding a number to given value until no model
+        is found with such slug. If unique_with (a tuple of field names) was
+        specified for the field, all these fields are included together
+        in the query when looking for a "rival" model instance.
+        """
+        def _get_lookups(instance):
+            "Returns a dict'able tuple of lookups to ensure slug uniqueness"
+            for field_name in self.unique_with:
+                field = instance._meta.get_field(field_name)
+                value = getattr(instance, field_name)
+                if not value:
+                    raise ValueError, 'Could not check uniqueness of %s.%s with'\
+                        ' respect to %s.%s because the latter is empty. Please'\
+                        ' ensure that "%s" is declared *after* all fields it'\
+                        ' depends on (i.e. "%s"), and that they are not blank.'\
+                        % (instance._meta.object_name, self.name,
+                           instance._meta.object_name, field_name,
+                           self.name, '", "'.join(self.unique_with))
+                if isinstance(field, DateField):    # DateTimeField is a DateField subclass
+                    for part in 'year', 'month', 'day':
+                        lookup = '%s__%s' % (field_name, part)
+                        yield (lookup, getattr(value, part))
+                else:
+                    yield (field_name, value)
+        lookups = tuple(_get_lookups(instance))
+        model = instance.__class__
+        field_name = self.name
+        index = 1
+        orig_slug = slug
+        # keep changing the slug until it is unique
+        while True:
+            try:
+                # raise model.DoesNotExist if current slug is unique
+                rival = model.objects.get(**dict(lookups + ((self.name, slug),) ))
+                # not unique, but maybe the "rival" is the instance itself?
+                if rival.id == instance.id:
+                    raise model.DoesNotExist
+                # the slug is not unique; change once more
+                index += 1
+                slug = '%s-%d' % (orig_slug, index)
+            except model.DoesNotExist:
+                # slug is unique, no model uses it
+                return slug

autoslug/settings.py

+# -*- coding: utf-8 -*-
+#
+#  Copyright (c) 2008—2009 Andy Mikhailenko
+#
+#  This file is part of django-autoslug.
+#
+#  django-autoslug is free software under terms of the GNU Lesser
+#  General Public License version 3 (LGPLv3) as published by the Free
+#  Software Foundation. See the file README for copying conditions.
+#
+
+from django.conf import settings
+
+""" the AUTOSLUG_SLUGIFY_FUNCTION setting allows to define
+a custom slugifying function. Value can be a string or a callable.
+Default value is 'django.template.defaultfilters.slugify'.
+"""
+
+# use custom slugifying function if any 
+slugify = getattr(settings, 'AUTOSLUG_SLUGIFY_FUNCTION', None)
+
+if not slugify:
+    try:
+        # more i18n-friendly slugify function (supports Russian transliteration)
+        from pytils.translit import slugify
+    except ImportError:
+        # fall back to Django's default one
+        slugify = 'django.template.defaultfilters.slugify'
+
+# find callable by string
+if isinstance(slugify, str):
+    from django.core.urlresolvers import get_callable
+    slugify = get_callable(slugify)

autoslugfield/__init__.py

-# -*- coding: utf-8 -*-
-
-__author__  = 'Andy Mikhailenko'
-__license__ = 'GNU Lesser General Public License (GPL), Version 3'
-__url__     = 'http://bitbucket.org/neithere/django-autoslugfield/'
-__version__ = '0.9'

autoslugfield/fields.py

-# -*- coding: utf-8 -*-
-
-# Original snippet: http://djangosnippets.org/snippets/728/
-# Reworked by Andy Mikhailenko <neithere at gmail dot com> in Sep 2008
-
-# django
-from django.db.models.fields import DateField, SlugField
-
-# app
-from autoslugfield.settings import slugify
-
-class AutoSlugField(SlugField):
-    """ A slug field which can automatically do the following two tasks on save:
-    - populate itself from another field (using 'populate_from'), and
-    - preserve uniqueness of the value (using 'unique' or 'unique_with_date').
-    
-    None of the tasks is mandatory, i.e. you can have auto-populated non-unique fields,
-    manually entered unique ones (absolutely unique or within a given date) or both.
-
-    If both unique_with and unique_with_date are declared,
-    
-    IMPORTANT NOTE: always declare attributes with AutoSlugField *after* attributes
-    from which you wish to 'populate_from' or check 'unique_with_date' because autosaved
-    dates and other such fields must be already processed before using them from here.
-    
-    Usage examples:
-
-    # force unique=True, silently fix on conflict
-    slug = AutoSlugField()
-    
-    # autoslugify value from title attr; default editable to False
-    slug = AutoSlugField(populate_from='title')
-    
-    # same as above but force editable=True
-    slug = AutoSlugField(populate_from='title', editable=True)
-    
-    # force unique=False but ensure that slug is unique for given date
-    slug = AutoSlugField(unique_with=('pub_date',))
-    
-    # mix above-mentioned behaviour bits
-    slug = AutoSlugField(unique_with=('pub_date',), populate_from='title')
-
-    # ensure uniqueness for more than one field (intersection will be checked)
-    slug = AutoSlugField(unique_with=('pub_date','category'), populate_from='title')
-    """
-    def __init__(self, *args, **kwargs):
-        kwargs['max_length'] = kwargs.get('max_length', 50)
-
-        # autopopulated slug is not editable unless told so
-        self.populate_from = kwargs.pop('populate_from', None)
-        if self.populate_from:
-            kwargs.setdefault('editable', False)
-
-        # unique_with value can be string or tuple
-        self.unique_with = kwargs.pop('unique_with', ())
-        if isinstance(self.unique_with, basestring):
-            self.unique_with = (self.unique_with,)
-        
-        # backward compatibility
-        if kwargs.get('unique_with_date'):
-            from warnings import warn
-            warn('Using unique_with_date="foo" in AutoSlugField is deprecated, '\
-                 'use unique_with=("foo",) instead.', DeprecationWarning)
-            self.unique_with += (kwargs['unique_with_date'],)
-
-        # force full uniqueness unless more granular is specified
-        if not self.unique_with:
-            kwargs.setdefault('unique', True)
-
-        # Set db_index=True unless it's been set manually.
-        if 'db_index' not in kwargs:
-            kwargs['db_index'] = True
-        super(SlugField, self).__init__(*args, **kwargs)
-
-    def pre_save(self, instance, add):
-        # get currently entered slug
-        value = self.value_from_object(instance)
-        
-        # autopopulate (unless the field is editable and has some value)
-        if value:
-            slug = slugify(value)
-        elif self.populate_from: # and not self.editable:
-            slug = slugify(getattr(instance, self.populate_from))
-
-        if not slug:
-            # no incoming value,  use model name
-            slug = instance._meta.module_name
-
-        assert slug, 'slug is defined before trying to ensure uniqueness'
-
-        # ensure the slug is unique (if required)
-        if self.unique or self.unique_with:
-            slug = self._generate_unique_slug(instance, slug)
-
-        assert slug, 'value is filled before saving'
-
-        setattr(instance, self.name, slug) # XXX do we need this?
-
-        return slug
-        #return super(AutoSlugField, self).pre_save(instance, add)
-
-    def _generate_unique_slug(self, instance, slug):
-        """
-        Generates unique slug by adding a number to given value until no model
-        is found with such slug. If unique_with (a tuple of field names) was
-        specified for the field, all these fields are included together
-        in the query when looking for a "rival" model instance.
-        """
-        def _get_lookups(instance):
-            "Returns a dict'able tuple of lookups to ensure slug uniqueness"
-            for field_name in self.unique_with:
-                field = instance._meta.get_field(field_name)
-                value = getattr(instance, field_name)
-                if not value:
-                    raise ValueError, 'Could not check uniqueness of %s.%s with'\
-                        ' respect to %s.%s because the latter is empty. Please'\
-                        ' ensure that "%s" is declared *after* all fields it'\
-                        ' depends on (i.e. "%s"), and that they are not blank.'\
-                        % (instance._meta.object_name, self.name,
-                           instance._meta.object_name, field_name,
-                           self.name, '", "'.join(self.unique_with))
-                if isinstance(field, DateField):    # DateTimeField is a DateField subclass
-                    for part in 'year', 'month', 'day':
-                        lookup = '%s__%s' % (field_name, part)
-                        yield (lookup, getattr(value, part))
-                else:
-                    yield (field_name, value)
-        lookups = tuple(_get_lookups(instance))
-        model = instance.__class__
-        field_name = self.name
-        index = 1
-        orig_slug = slug
-        # keep changing the slug until it is unique
-        while True:
-            try:
-                # raise model.DoesNotExist if current slug is unique
-                rival = model.objects.get(**dict(lookups + ((self.name, slug),) ))
-                # not unique, but maybe the "rival" is the instance itself?
-                if rival.id == instance.id:
-                    raise model.DoesNotExist
-                # the slug is not unique; change once more
-                index += 1
-                slug = '%s-%d' % (orig_slug, index)
-            except model.DoesNotExist:
-                # slug is unique, no model uses it
-                return slug

autoslugfield/settings.py

-# -*- coding: utf-8 -*-
-
-from django.conf import settings
-
-""" the AUTOSLUG_SLUGIFY_FUNCTION setting allows to define
-a custom slugifying function. Value can be a string or a callable.
-Default value is 'django.template.defaultfilters.slugify'.
-"""
-
-# use custom slugifying function if any 
-slugify = getattr(settings, 'AUTOSLUG_SLUGIFY_FUNCTION', None)
-
-if not slugify:
-    try:
-        # more i18n-friendly slugify function (supports Russian transliteration)
-        from pytils.translit import slugify
-    except ImportError:
-        # fall back to Django's default one
-        slugify = 'django.template.defaultfilters.slugify'
-
-# find callable by string
-if isinstance(slugify, str):
-    from django.core.urlresolvers import get_callable
-    slugify = get_callable(slugify)
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 #
-#  Copyright (c) 2009 Andy Mikhailenko and contributors
+#  Copyright (c) 2008—2009 Andy Mikhailenko and contributors
 #
-#  This file is part of Django AutoSlugField.
+#  This file is part of django-autoslug.
 #
-#  Django LJSync is free software under terms of the GNU Lesser
+#  django-autoslug is free software under terms of the GNU Lesser
 #  General Public License version 3 (LGPLv3) as published by the Free
 #  Software Foundation. See the file README for copying conditions.
 #
 
-" Django AutoSlugField setup "
+"django-autoslug setup"
 
 from distutils.core import setup
-from autoslugfield import __version__
+from autoslug import __version__
 
 setup(
-    name     = 'django-autoslugfield',
+    name     = 'django-autoslug',
     version  = __version__,
-    packages = ['autoslugfield'],
+    packages = ['autoslug'],
     
-    install_requires = ['python >= 2.4', 'django >= 1.0', 'pytils >= 0.2'],
+    requires = ['python (>= 2.4)', 'django (>= 1.0)'],
+    # in case you want to use slugify() with support for transliteration:
+    extras_require = ['pytils (>= 0.2)'],
     
     description  = 'An automated slug field for Django',
-    long_description = "A slug field which can automatically a) populate itself from another field, and b) preserve uniqueness of the value.",
+    long_description = "A slug field which can automatically a) populate itself "\
+                       "from another field, b) preserve uniqueness of the value "\
+                       "and c) use custom slugify() functions for better i18n.",
     author       = 'Andy Mikhailenko',
-    author_email = 'neithere@gmail.com',
-    url          = 'http://bitbucket.org/neithere/django-autoslugfield/',
-    download_url = 'http://bitbucket.org/neithere/django-autoslugfield/get/tip.zip',
+    author_email = 'andy@neithere.net',
+    url          = 'http://bitbucket.org/neithere/django-autoslug/',
+    download_url = 'http://bitbucket.org/neithere/django-autoslug/get/tip.zip',
     license      = 'GNU Lesser General Public License (LGPL), Version 3',
-    keywords     = 'django field slug transliteration i18n',
+    keywords     = 'django field slug auto transliteration i18n',
 )
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.