0

Thanks in advanced, for viewing and answering my question,

Images:

theProblem: https://drive.google.com/file/d/0Bw4K4uUse4DYWHZmYW9kZWJtcE0/edit?usp=sharing

thePosibleSolution: (this is a photoshoped image of what i want to do) https://drive.google.com/file/d/0Bw4K4uUse4DYcjZ1TnBVdUk4R3M/edit?usp=sharing

Background:

In my django module i have 3 tables, Movies, Metadata and a junction table called MoviesMetadata. Movies stores movies titles (The Fight Club), Metadata stores metadata names (Date, Director, Actors, Revenue, etc.) and the type of that Metadata (text, date, users, decimal, integer). Finally, the junction table joins a Movie with Multiple Metadatas and the Values for that Movie's Metadata depending of the Metadata's type (textValue, integerValue, usersValue, decimalValue, etc.).

Problem:

The problem is that when somebody add a Metadata (Date) to a Movie (The Fight Club) the expected result is that the dateValue field have some content (1999/10/15) but also the user can add content in the textValue or another value type that is not the type of that Metadata. At the end, the values for the Metadata Date for the movie The Fight Club can be 1999/10/15 (dateValue field), admin (usersValue field), 36,000,000.00 (decimalValue field), etc.

Question:

  1. How to erase or don't allow users to add data in the wrong fields?
  2. In the template (post form), How to show only the Movie field, the Metadata field and the correct value field?

Code:

class Movies(models.Model):
    name = models.CharField(max_length=100)
    metadata = models.ManyToManyField(Metadata, through='MoviesMetadata')

    def __str__(self):
        return str(self.name)


class MoviesMetadata(models.Model):
    movie = models.ForeignKey(Movies)
    metadata = models.ForeignKey(Metadata)
    textValue = models.CharField(max_length=100, blank=True, null=True)
    dateValue = models.DateField(auto_now=False, auto_now_add=False, blank=True, null=True)
    userValue = models.ForeignKey(User, blank=True, null=True)
    decimalValue = models.DecimalField(max_digits=18, decimal_places=2, blank=True, null=True)

    def _value(self):
        '''
        @property returns only the values from the selected fieldtype,
        ignore the other fieldtypes values.
        '''
        if self.metadata.fieldtype == '0':
            return self.textValue
        elif self.metadata.fieldtype == '1':
            return self.dateValue
        elif self.metadata.fieldtype == '2':
            return self.userValue
        else:
            return self.decimalValue
    value = property(_value)

    def __str__(self):
        return ('%s: %s' % (self.metadata, self.value))


class Metadata(models.Model):
    name = models.CharField(max_length=100)
    METADATA_FIELD_TYPE = (
        ('0', 'Text Value'),
        ('1', 'Date Value'),
        ('2', 'User Value'),
        ('3', 'Decimal Value'),
    )
    fieldtype = models.CharField(max_length=1, choices=METADATA_FIELD_TYPE, default='0')

    def __str__(self):
        return ('%s (%s)' % (self.name, self.get_fieldtype_display()))
iDevFS
  • 483
  • 1
  • 10
  • 16
  • You are using an anti-pattern [EAV](http://stackoverflow.com/a/24157781/3404097). Do not have a table of metatdata. Just have attributes of movies be fields/columns of Movies. The [DBMS](http://stackoverflow.com/a/23950836/3404097) is designed to manage data and metadata. – philipxy Jun 19 '14 at 03:39

1 Answers1

0

You are using a DBMS anti-pattern EAV. You are (trying to) build part of a DBMS into your program + database. The DBMS already exists to manage data and metadata. Use it.

Do not have a class/table of metatdata. Just have attributes of movies be fields/columns of Movies.

Your Metadata class/table suffers from this too in an additional way. Do not have a field/column that is a list that represents a row. Just have the list element names be Metadata field/column names. Except that per above you shouldn't have class/table Metadata. Because each such row is encoding the attributes of a movie. The particular fields/columns for movies should just be in Movies.

From one of the answers linked above:

The notion that one needs to use EAV "so every entity type can be extended with custom fields" is mistaken. Just implement via calls that update metadata tables sometimes instead of just updating regular tables: DDL instead of DML.

Community
  • 1
  • 1
philipxy
  • 14,867
  • 6
  • 39
  • 83
  • The thing is that i don't know all the possible metadatas. I want users to create their own. Please check the images i added also i change the question since i thought a possible solution. Thanks!!! – iDevFS Jun 19 '14 at 04:43
  • Yes that's what people always think. *Your program is exactly duplicating functionality in the DBMS so it cannot be a problem to use the DBMS.* (See my updated answer.) Read the link, research EAV. Django doesn't necessarily make that easy; but EAV is a burden too. Hope you'll get some Django answers. Your link looks like you solved your problem. – philipxy Jun 19 '14 at 05:16
  • Please don't be offended but **at this moment** i haven't understood quite well. Im just a librarian trying to build something. What i think you're telling me is that i shouldn't try to rebuild DBMS (textValue field, dateValue field, etc.) because "each such row is encoding the attributes of a movie." So instead of doing that i should add Metadata as fields/columns into the class/table Movies. – iDevFS Jun 19 '14 at 06:20
  • I hope clarify my answer. As you are doing this within Django, your options may be limited. I assume you've checked out [stackexchange](https://stackoverflow.com/questions/673199/disabled-option-for-choicefield-django). – philipxy Jun 20 '14 at 06:44