Using Djongo's ArrayField at Django Admin - django

Djongo is a Django and MongoDB database connector witch brings, beside others, the ArrayField to Django Models. It allows one to store multiple instances of an other djongo.models.Model in an unique MongoDB Array field inside a document related with the Model that has the Arrayfield
As described in source documentation:
"The model of the container must be declared as abstract, thus should not be treated as a collection of its own."
As well as in djongo's site tutorials
"In case you don’t plan on using your embedded model as a standalone model (which means it will always be embedded inside a parent model) you should add the class Meta and abstract = True This way Djongo will never register this model as an actual model."
This way I made:
# models.py
class Contact(models.Model):
key = models.CharField(max_length=100)
class Meta:
abstract = True
class ContactForm(forms.ModelForm):
class Meta:
model = Contact
fields = ('key',)
class Person(models.Model):
_id = models.ObjectIdField()
...
contact = models.ArrayField(
model_container=Contact,
model_form_class=ContactForm,
)
objects = models.DjongoManager()
# admin.py
admin.site.register(Person)
$ pip freeze
Django==3.2.4
djongo==1.3.6
pymongo==3.11.4
...
However when I try to add a Person through Django Admin (in /admin/<app>/person/add/) I receive the error Abstract models cannot be instantiated from .../django/db/models/base.py
This seems inconsistent with Djongo's description. Am I doing something wrong?

Related

How to setup a flexible django models

I'm new to django. What I'm trying to achieve is when the ProductType combobox is changed, the fields changes to its specific fields then the users inputs using those field and entered to the database. My problem is how to create a flexible model that would accept extra fields
from django.db import models
class Product(models.Model):
"""SKU"""
stock = models.IntegerField(default=None)
class ProductType(models.Model):
product_field = models.ForeignKey(ProductFields, on_delete=models.CASCADE)
name = models.CharField(max_length=255)
class ProductFields(models.Model):
"""Fields of ProductType"""
Here's an DB example I'm trying to achieve See Image
SQL database is not suitable for that purpose.
Look for non-SQL databases for ex. Firebase

mongoengine and django rest framework - fields aren't allowed to be optional

I've setup a REST api with django rest framework, using mongoengine as the ORM for my models. However, I keep getting this response back from the api for a field that should be optional:
{"ref":["This field may not be null."]}
The problem I'm running into is that it seems like all fields (I'm specifically using ReferenceFields, but I've tried it with StringFields, etc too) are not allowed to be optional/null.
I've tried setting validation methods to an empty lambda (that returns True), setting null=True and required=False where the field is defined in the model.
from mongoengine import *
class B(Document):
...
class A(Document):
ref = ReferenceField('B', null=True, required=False, dbref=False, validation=lambda: True)
I even tried explicitly setting the serializer in A's serializer so that I could tell it to allow nulls (with allow_null=True):
from api.models import A,B
from rest_framework_mongoengine.serializers import DocumentSerializer
class BSerializer(DocumentSerializer):
class Meta:
model = B
depth = 2
class ASerializer(DocumentSerializer):
ref = BSerializer(allow_null=True)
class Meta:
model = A
depth = 2
How do I get optional (nullable) fields to work with django rest framework and mongoengine? Again, this isn't just ReferenceFields, it's the same with any field I try.

Add a GenericRelation in a Proxy Model

I have a group of models in django 1.5.2 that all use GenericForeignKey and GenericRelation. The problem is that I also use proxy inheritance. A generic relation is a Field, but not a DB field, but when validating the model, django sees a Field in a proxy inherited model and raises an error.
Below is a simplified version of my problem. Is there a simple solution that would allow me to access simply the tags from TaggableArticle ?
from django.db import models
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
class Tag(models.Model):
tag = models.SlugField()
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
class Article(models.Model):
text = models.TextField()
class TaggableArticle(Article):
tags = generic.GenericRelation(Tag)
class Meta:
proxy = True
The result is :
python manage.py validate
FieldError: Proxy model 'TaggableArticle' contains model fields.
[1] 15784 exit 1 python manage.py validate
My thoughts so far :
django 1.6 introduces a for_concrete_model flag in generic relations, but I haven't been able to see if this could solve my problem. I just understood that it could help if the relation was in Article, and if I wanted to be able to tag an object with the proper content type (Article vs TaggedArticle).
I could remove the relation and just access it from the other endpoint (i.e. `Tag.objects.filter(content_object=myTaggedArticle) or manually add a method to this) but part of the implementation I have integrates the fact I'm using a RelatedManager and not just a normal Manager, and I would not be getting a related manager if I came from the whole TaggedArticle class.
Tkank you !

Django model manager use_for_related_fields and ModelAdmin relationships

I am having trouble getting my model manager to behave correctly when using the Admin interface. Basically, I have two models:
class Employee(models.Model):
objects = models.EmployeeManager()
username = models.CharField(max_length=45, primary_key=True)
. . .
class Eotm(models.Model): #Employee of the Month
date = models.DateField()
employee = models.ForeignKey(Employee)
. . .
And I have an EmployeeManager class that overrides the get() method, something like this:
class EmployeeManager(models.Manager):
use_for_related_fields = True
def get(self, *arguments, **keywords):
try:
return super(EmployeeManager, self).get(*arguments, **keywords)
except self.model.DoesNotExist:
#If there is no Employee matching query, try an LDAP lookup and create
#a model instance for the result, if there is one.
Basically, the idea is to have Employee objects automatically created from the information in Active Directory if they don't already exist in the database. This works well from my application code, but when I tried to create a Django admin page for the Eotm model, things weren't so nice. I replaced the default widget for ForeignKey fields with a TextInput widget so users could type a username (since username is the primary key). In theory, this should call EmployeeManager.get(username='whatever'), which would either return an Employee just like the default manager or create one and return it if one didn't already exist. The problem is, my manager is not being used.
I can't find anything in the Django documentation about using custom Manager classes and the Admin site, aside from the generic manager documentation. I did find a blog entry that talked about specifying a custom manager for ModelAdmin classes, but that doesn't really help because I don't want to change the model represented by a ModelAdmin class, but one to which it is related.
I may not be understanding what you're trying to do here, but you could use a custom Form for your Eotm model:
#admin.py
from forms import EotmAdminForm
class EotmAdmin(models.ModelAdmin):
form = EotmAdminForm
#forms.py
from django import forms
from models import Eotm, Employee
class EotmAdminForm(forms.ModelForm)
class Meta:
model = Eotm
def clean_employee(self):
username = self.cleaned_data['employee']
return Employee.get(username=username)
That, in theory, should work. I haven't tested it.

Django fix Admin plural

How do I change some models name from "Categorys" to "Categories" on admin site in the new dev django version?
In the old version (whithout admin sites and admin models) you could just do this;
http://www.the-dig.com/blog/post/customize-plural-name-django-admin/
However - now setting verbose_name_plural inside my modeladmin based class does nothing.
Anyone encouter the same issue?
Well well, it seems like the Meta class approach still works.
So placing a meta class inside your model will still do the trick:
class Category(models.Model):
class Meta:
verbose_name_plural = "categories"
Note that we use the lower case here, as django is smart enough to capitalize it when we need it.
I find setting this option in model-class weird as opposed to the admin.py file.
Here is the location in the dev docs where it is described:
http://docs.djangoproject.com/en/dev/ref/models/options/#verbose-name-plural
for that you need to add meta classes for models
class Category(models.Model):
--- model field here ---
class Meta:
verbose_name = "Category"
verbose_name_plural = "Categories"
Bonus for your models admin in apps.py
class CategoryConfig(AppConfig):
name = "Category"
verbose_name = "Categories"