Documents classification with variable set of labels - django

I want to create a model where a user can define a set of labels for the purpose of classification of documents. Each label for that document should also have a probability (float) that that document belongs to that label.
So this is what I have for my model with 3 labels (news, business, sports):
class Document(models.Model):
document_name = models.CharField(max_length=100)
proba_label_news = models.DecimalField(max_digits=5)
proba_label_business = models.DecimalField(max_digits=5)
proba_label_sports = models.DecimalField(max_digits=5)
...
But of course there could be more labels what a user can define at the start of a classification project and what a developer can't foresee.
I tried manytomany as an alternative but when I create a Label model and define a new label as "news" than I can't have a different probability for each document label, right?
So what is the django way of solving this problem?

Yes, a many-to-many relationship could work. What you need to add is an intermediatiary 'through' model to store the probability for each document-label relationship. Something like this:
class Label(models.Model):
name = models.CharField(max_length=50)
class LabelProbability(models.Model):
label = models.ForeignKey(Label, on_delete=models.CASCADE)
document = models.ForeignKey("Document", on_delete=models.CASCADE)
probability = models.DecimalField(max_digits=5)
class Document(models.Model):
document_name = models.CharField(max_length=100)
labels = models.ManyToManyField(Label, through=LabelProbability)
Then when you want to add a label to a document, you would use the through_defaults argument to assign a probability. Do something like the following:
news = Label.objects.get(name="news")
document_1.labels.add(news, through_defaults={"probability":0.57})
You can read more about many-to-many fields, and using a through table in django docs here
An alternative approach
Alternatively, you could store the label and the probability together, something like this:
class Label(models.Model):
name = models.CharField(max_length=50)
probability = models.DecimalField(max_digits=5)
document = models.ForeignKey("Document", on_delete=models.CASCADE)
class Document(models.Model):
document_name = models.CharField(max_length=100)
This way, you just have two tables, and each label stores both the name of the label (allowing you to use any name), and the probability. You can add as many labels as you want pointing to the same document (just as before).

Related

best way to create feature field for a product in Django

a Mobile device has many features in different types.
RAM=4: int
fingerprint=yes : boolean
camera=face detection, touch focus, panorama ...
how to create field for features, create an app for features and declare each feature type ? :
class IntFeature(models.Model):
title = models.CharField()
value = models.IntegerField()
class BoolFeature(models.Model):
title = models.CharField()
value = models.BooleanField()
class CharFeature(models.Model):
title = models.CharField()
value = models.CharField()
i guess all you need is just one class with an extra field which you'll define the type that you'll refer to it to cast the value
class Feature(models.Model):
title = models.CharField()
value = models.CharField() # it should be a string
type = models.CharField() # it could be an object, array, json, int, boolean ..
UPDATE
it seems you want to assign a bunch of attributes - values to a given product, may be you should look at woocommerce to get the idea or better Oscar a django-based ecommerce solution

Mirror/inherit a module for outputting some fields of the original

Is it possible, in Django, to create a module which is linked via a OneToOneField to another one, which only outputs a single field of its parent?
Something like:
class Venue(models.Model): # this is the parent
venue_name = models.CharField(max_length=50)
venue_city = models.CharField(max_length=50)
venue_country = models.CharField(max_length=50)
class VenueCity(models.Model): # should this be (Venue)?
venue_city = # this is the OneToOneField linked to the venue_city field of the parent
I need this because it'd be very handy for using it with a select2 field (
django_select2 - limit the returned text to a specific field in module) and I cannot use a #property, only a proper module.
** Addition: widget code **
class VenueForm(forms.ModelForm):
class Meta:
model = Venue
fields = ['venue_name', 'venue_city', 'venue_country']
widgets = {
'venue_city': s2forms.ModelSelect2Widget(model=Venue,
search_fields=['venue_city__icontains'])}
No, not as such. You could probably use Django-select2's label override function to show only the city name from the venue model, and maybe override the queryset too if you want uniquely cities only.

User-generated fields in Django

I'm building a Djano application which displays a set of images, and a form for each image for recording specific image characteristics. The user initializes a "project", where they specify the set of images that will be displayed for assessment. At project initialization, I'd like to give the user the ability to add custom boolean fields (i.e. a set of checkboxes), but I can't figure out how to build the database models.
For example, a user might initialize my_project with image_A.png, image_B.png and image_C.png for assessment. The default form they'll get for each image lets them choose between PASS, FAIL and UNKNOWN. They might wish to add custom fields like "poorly cropped", "over-exposed" or "blurry" (the idea being that the image could be a global PASS, but small failures, specific to the context of this image set, could still be recorded).
Generally, I'm trying to come up with a way to model user-generated fields in Django.
If I correctly understand, you don't need dynamic model fields, instead you can add model, which contains specific attributes for image in project, something like:
class Image(models.Model):
name = models.CharField()
img = models.ImageField()
class ProjectImage(models.Model):
image = models.ForeignKey('Image')
project = models.ForeignKey('Project')
flag = models.CharField(choices=PASS_FAIL_UNKNOWN)
class ProjectImageTag(models.Model):
project_image = models.ForeignKey(ProjectImage)
value = models.CharField()
class Project(models.Model):
images = models.ManyToManyField('Image', through=ProjectImage)
Also, you can store such tags in json field or postgres hstore field instead of separate table.
EDIT
Variation with predefined keys:
class ProjectImage(models.Model):
image = models.ForeignKey('Image')
project = models.ForeignKey('Project')
flag = models.CharField(choices=PASS_FAIL_UNKNOWN)
class Image(models.Model):
name = models.CharField()
img = models.ImageField()
class Project(models.Model):
images = models.ManyToManyField('Image', through=ProjectImage)
class ProjectImageParams(models.Model):
project_image = models.ForeignKey(ProjectImage, related_name='params')
key = models.CharField()
value = models.BooleanField()
Params of image may be obtained with ProjectImage().params.all(). And yes, django-eav may be a good option.

Modelling a relationship to a meta-table with 2 primary keys

I am very new to Django and would appreciate your help with this problem:
I have a table with meta-informationen (like the number of clicks, votes, comments ...) for different areas of my website (news, events in the calendar, films ..). The table is referenced by two primary keys (fi = INTEGER and tbl = CHAR).
class News(models.Model):
title = models.CharField()
...
class Film(models.Model):
title = models.Charfield()
...
class Calendar(models.Model):
title = models.Charfield()
...
class MetaInfo(models.Model):
fi = ForeignKey(??) # Integer
tbl = ForeignKey(??) # CharField
Example: fi = 1 and tbl = 'news' would relate to news-entry with primary key 1. And fi = 100, tbl = 'film' would relate to film-entry with primary key 100.
How to implment this? Is this even possible with django?
Django has a built-in feature called Generic Foreign Keys that allow you to tie a single table to multiple models in this fashion.
This is how you would create your models:
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
class News(models.Model):
title = models.CharField()
...
class Film(models.Model):
title = models.Charfield()
...
class Calendar(models.Model):
title = models.Charfield()
...
class MetaInfo(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey()
If you wish, you can be more explicit about the relationship between a model and MetaInfo by using GenericRelation. For example:
class Film(models.Model):
title = models.CharField()
metainfo = generic.GenericRelation('MetaInfo')
...
This allows you to access the related MetaInfo records directly from the Film model, as in
f = Film.objects.get(pk=1)
for mi in f.metainfo.all():
#mi is a matching MetaInfo record for Film record with pk=1
Just to elaborate a bit:
In the MetaInfo model, content_type serves as the equivalent of your tbl column (although it points to a Django construct called a ContentType; Django constructs one for each model in the app/set of apps) and object_id corresponds to your fi key. You actually generally don't pay much attention to those fields. Instead, you get and set the content object, which is the corresponding record. For example, instead of storing or retrieving tlb='Film', fi=1, you'd get or set content_object which corresponds directly to the Film record matching pk=1.
In essence, contenttype__name='Film', object_id=1 while content_object=Film.object.get(pk=1)
This is all assuming that this database is for Django use only. If it's an existing database that you're trying to use within Django, there isn't a straightforward way to handle this that I'm aware of.

Is it possible to instruct Django to save a model instance to a particular table based on its fields?

I'm attempting to construct a Django application that models an existing set of tables. These tables all have the same fields, plus custom fields per table. What I'm wanting to do is model this structure, and have records save to a particular table based on what table model they are attached to.
These tables can be created quite often, so it is unfeasible to construct new models per table.
Perhaps the code will demonstrate what I'm trying to do more clearly:
class CustomField(models.Model):
column_name = models.CharField(max_length=100)
description = models.CharField(max_length=255, blank=True, null=True)
class CustomData(models.Model):
custom_field = models.ForeignKey(CustomField)
value = models.CharField(max_length=100, blank=True, null=True)
# value will always be a nullable varchar(100)
class Table(models.Model):
table_name = models.CharField(max_length=255)
name = models.CharField(max_length=100)
custom_fields = models.ManyToManyField(CustomField)
class Record(models.Model):
table = models.ForeignKey(Table)
... list of common fields omitted ...
custom_values = models.ManyToManyField(CustomData)
When saving a new record that has a foreign key to 'table_1', I would like the eventual operation to be along the lines of insert into table_1 (..fields..) values (..field values..)
Is this possible? I guess I could hook into signals or the save method, but I'd like to find the simplest approach if such exists.
You can create unmanaged models dynamically. You just need to create a dict mapping column names to the data values. Once you have that, you can do the following:
from django.db import models
# This is the dict you created, mapping column names to values
values = {col_1: value_1, col_2: value_2, col_3: value_3, ... }
# Create a dict defining the custom field types, eg {col_name: django_field}
attrs = dict((c, models.CharField(max_length=100, blank=True, null=True)) for c in values)
# Add a Meta class to define the table name, eg table_1
class Meta:
app_label = myapp
db_table = 'table_1'
managed = False
attrs['Meta'] = Meta
attrs['__module__'] = 'path.to.your.apps.module'
DynamicModel = type('MyModel', (models.Model,), attrs)
# Save your data
DynamicModel.objects.create(**values)
Wrap this up in a function, and put it in your .save() method on Record. If you have any common fields, you can add them to attrs, or even better: create an abstract model with all the common fields and inherit that in the last line above instead of models.Model.