Django project, first models

This commit is contained in:
Raphael Michel
2014-09-09 16:38:33 +02:00
parent f76760862e
commit befe27cdd0
25 changed files with 423 additions and 0 deletions

10
src/.gitignore vendored Normal file
View File

@@ -0,0 +1,10 @@
*.sqlite3
*.db
*.py[cod]
*.swp
*.aux
*.log
*.toc
*~
.ropeproject
__pycache__/

0
src/__init__.py Normal file
View File

10
src/manage.py Executable file
View File

@@ -0,0 +1,10 @@
#!/usr/bin/env python
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tixl.settings")
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)

2
src/requirements.txt Normal file
View File

@@ -0,0 +1,2 @@
Django>=1.7
pyflakes

0
src/tixl/__init__.py Normal file
View File

96
src/tixl/settings.py Normal file
View File

@@ -0,0 +1,96 @@
"""
Django settings for tixl project.
For more information on this file, see
https://docs.djangoproject.com/en/dev/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/dev/ref/settings/
"""
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/dev/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '0ro^46+8k#dv3ej=oen-2ww)i30#$$^&x&eajyj&_&h)$nc6@5'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
TEMPLATE_DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'tixlbase',
'tixlcontrol',
'tixlpresale',
)
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
ROOT_URLCONF = 'tixl.urls'
WSGI_APPLICATION = 'tixl.wsgi.application'
# Database
# https://docs.djangoproject.com/en/dev/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Internationalization
# https://docs.djangoproject.com/en/dev/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Authentication
AUTH_USER_MODEL = 'tixlbase.User'
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/dev/howto/static-files/
STATIC_URL = '/static/'
try:
from local_settings import *
except ImportError:
pass

10
src/tixl/urls.py Normal file
View File

@@ -0,0 +1,10 @@
from django.conf.urls import patterns, include, url
from django.contrib import admin
urlpatterns = patterns('',
# Examples:
# url(r'^$', 'tixl.views.home', name='home'),
# url(r'^blog/', include('blog.urls')),
url(r'^admin/', include(admin.site.urls)),
)

14
src/tixl/wsgi.py Normal file
View File

@@ -0,0 +1,14 @@
"""
WSGI config for tixl project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/dev/howto/deployment/wsgi/
"""
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tixl.settings")
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

0
src/tixlbase/__init__.py Normal file
View File

3
src/tixlbase/admin.py Normal file
View File

@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

View File

@@ -0,0 +1,101 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import django.utils.timezone
from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
('auth', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='User',
fields=[
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
('password', models.CharField(verbose_name='password', max_length=128)),
('last_login', models.DateTimeField(verbose_name='last login', default=django.utils.timezone.now)),
('is_superuser', models.BooleanField(verbose_name='superuser status', default=False, help_text='Designates that this user has all permissions without explicitly assigning them.')),
('identifier', models.CharField(unique=True, max_length=255)),
('username', models.CharField(max_length=120)),
('email', models.EmailField(blank=True, null=True, db_index=True, max_length=75)),
('is_active', models.BooleanField(default=True)),
('is_staff', models.BooleanField(default=False)),
('date_joined', models.DateTimeField(auto_now_add=True)),
],
options={
},
bases=(models.Model,),
),
migrations.CreateModel(
name='Event',
fields=[
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
('name', models.CharField(max_length=200)),
('slug', models.CharField(db_index=True, max_length=50)),
('locale', models.CharField(max_length=10)),
('currency', models.CharField(max_length=10)),
('date_from', models.DateTimeField()),
('date_to', models.DateTimeField(blank=True, null=True)),
('show_date_to', models.BooleanField(default=True)),
('show_times', models.BooleanField(default=True)),
('presale_end', models.DateTimeField(blank=True, null=True)),
('presale_start', models.DateTimeField(blank=True, null=True)),
('payment_term_days', models.IntegerField(default=14)),
('payment_term_last', models.DateTimeField(blank=True, null=True)),
],
options={
'ordering': ('date_from', 'name'),
},
bases=(models.Model,),
),
migrations.CreateModel(
name='Organizer',
fields=[
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
('name', models.CharField(max_length=200)),
('slug', models.CharField(unique=True, db_index=True, max_length=50)),
('owner', models.ForeignKey(blank=True, null=True, to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ('name',),
},
bases=(models.Model,),
),
migrations.AddField(
model_name='event',
name='organizer',
field=models.ForeignKey(to='tixlbase.Organizer', related_name='events'),
preserve_default=True,
),
migrations.AlterUniqueTogether(
name='event',
unique_together=set([('organizer', 'slug')]),
),
migrations.AddField(
model_name='user',
name='event',
field=models.ForeignKey(to='tixlbase.Event', blank=True, null=True, related_name='users'),
preserve_default=True,
),
migrations.AddField(
model_name='user',
name='groups',
field=models.ManyToManyField(verbose_name='groups', related_name='user_set', related_query_name='user', blank=True, to='auth.Group', help_text='The groups this user belongs to. A user will get all permissions granted to each of his/her group.'),
preserve_default=True,
),
migrations.AddField(
model_name='user',
name='user_permissions',
field=models.ManyToManyField(verbose_name='user permissions', related_name='user_set', related_query_name='user', blank=True, to='auth.Permission', help_text='Specific permissions for this user.'),
preserve_default=True,
),
migrations.AlterUniqueTogether(
name='user',
unique_together=set([('event', 'username')]),
),
]

View File

153
src/tixlbase/models.py Normal file
View File

@@ -0,0 +1,153 @@
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
class UserManager(BaseUserManager):
"""
This is the user manager for our custom user model. See the User
model documentation to see what's so special about our user model.
"""
def create_user(self, email, password=None):
user = self.model(email=email)
user.set_password(user)
user.save()
return user
def create_superuser(self, email, password=None):
if password is None:
raise Exception("You must provide a password")
user = self.model(email=email)
user.is_staff = True
user.is_superuser = True
user.set_password(user)
user.save()
return user
class User(AbstractBaseUser, PermissionsMixin):
"""
This is the user model used by tixl for authentication.
Handling users is somehow complicated, as we try to have two
classes of users in one system:
(1) We want global users who can just login into tixl and
buy tickets for multiple events -- we also need those
global users for event organizers who should not need
multiple users for managing multiple events.
(2) We want local users who exist only in the scope of a
certain event
The hard part is to find a primary key to identify all of these
users. Letting the users choose usernames is a bad idea, as
the primary key needs to be unique and there is no reason for a
local user to block a name for all time. Using e-mail addresses
is not a good idea either, for two reasons: First, a user might
have multiple local users (so they are not unique), and second,
it should be possible to create anonymous users without having
to supply an e-mail address.
Therefore, we use an abstract "identifier" field as the primary
key. The identifier is:
(1) the e-mail address for global users. An e-mail address
is and should be required for them and global users use
their e-mail address for login.
(2) "{username}@{event.id}.event.tixl" for local users, who
use their username to login on the event page.
The model's save() method automatically fills the identifier field
according to this scheme when it is empty. The __str__() method
returns the identifier.
The is_staff field is only True for system operators.
"""
identifier = models.CharField(max_length=255, unique=True)
username = models.CharField(max_length=120)
event = models.ForeignKey('Event', related_name="users",
null=True, blank=True)
email = models.EmailField(unique=False, db_index=True,
null=True, blank=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
date_joined = models.DateTimeField(auto_now_add=True)
objects = UserManager()
def __str__(self):
return self.identifier
def save(self, *args, **kwargs):
if self.identifier is None:
if self.event is None:
self.identifier = self.email
else:
self.identifier = "%s@%d.event.tixl" % (self.username, self.event.id)
super().save(*args, **kwargs)
USERNAME_FIELD = 'identifier'
REQUIRED_FIELDS = ['username']
class Meta:
unique_together = (("event", "username"),)
class Organizer(models.Model):
"""
This model represents an entity organizing events, like a company,
an organization or a person. It has one user as owner (who has
registered it) and can have any number of users with admin
authorization. Any organizer has a unique slug, which is a short
name (alphanumeric, all lowercase) being used in URLs.
"""
name = models.CharField(max_length=200)
slug = models.CharField(max_length=50,
unique=True,
db_index=True)
owner = models.ForeignKey(User, null=True, blank=True)
class Meta:
ordering = ("name",)
class Event(models.Model):
"""
This model represents an event. An event is anything you can buy
tickets for. It belongs to one orgnaizer and has a name and a slug,
the latter being a short, alphanumeric, all-lowercase name being
used in URLs. The slug has to be unique among the events of the same
organizer.
An event can hold several properties, such as a default locale and
currency.
The event has date_from and date_to field which mark the actual
datetime of the event itself. The show_date_to and show_times
fields are used to control the display of these dates. (Without
show_times only days are shown, now times.)
The presale_start and presale_end fields mark the time frame in
which tickets are sold for this event. These two dates override
every other restrictions to ticket sale if set.
The payment_term_days field holds the number of days after
submitting a ticket order, in which the ticket has to be paid.
The payment_term_last is the day all orders must be paid by, no
matter when they were ordered (and thus, ignoring payment_term_days).
"""
organizer = models.ForeignKey(Organizer, related_name="events")
name = models.CharField(max_length=200)
slug = models.CharField(max_length=50,
db_index=True)
locale = models.CharField(max_length=10)
currency = models.CharField(max_length=10)
date_from = models.DateTimeField()
date_to = models.DateTimeField(null=True, blank=True)
show_date_to = models.BooleanField(default=True)
show_times = models.BooleanField(default=True)
presale_end = models.DateTimeField(null=True, blank=True)
presale_start = models.DateTimeField(null=True, blank=True)
payment_term_days = models.IntegerField(default=14)
payment_term_last = models.DateTimeField(null=True, blank=True)
class Meta:
unique_together = (("organizer", "slug"),)
ordering = ("date_from", "name")

3
src/tixlbase/tests.py Normal file
View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

3
src/tixlbase/views.py Normal file
View File

@@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.

View File

3
src/tixlcontrol/admin.py Normal file
View File

@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

View File

3
src/tixlcontrol/tests.py Normal file
View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

3
src/tixlcontrol/views.py Normal file
View File

@@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.

View File

3
src/tixlpresale/admin.py Normal file
View File

@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

View File

3
src/tixlpresale/tests.py Normal file
View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

3
src/tixlpresale/views.py Normal file
View File

@@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.