How to access the instance from a model manager? - django

I was told that doesn't make sense as managers operate on all rows not a single instance but I see what I want to achieve done in django-taggit library.
Here: https://github.com/alex/django-taggit/blob/master/taggit/managers.py
And the the installation works as follows:
from django.db import models
from taggit.managers import TaggableManager
class Food(models.Model):
# ... fields here
tags = TaggableManager()
Then to tag anything, one can simply do the following:
apple.tags.add("red", "green", "fruit")
Note: apple not Apple.
Yet, when I try to do it myself, I get: AttributeError: Manager isn't accessible via MyModelName instances!
My code:
from django.db import models
class TagManager(models.Manager):
def add(self, *tags):
print("Testing...")
class List(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
title = models.CharField(max_length=500)
tags = TagManager()
Then I am trying to call the add method as follows:
l = List.objects.create(...)
l.tags.add(...)
How can I make it work?

Related

Registering derived child class of abstract class in admin.py in django 2.2

Does anyone know, how to register child class derived from abstract class in admin.py (the abstract class is in file abstract_models.py file) I tried major solution in the web but does not seem to work. It is possible as pointed by various contributors but don't know what I am doing wrong!
My folder structure is like this
'''
gaasc/ <- project folder
contain urls.py, admin.py,models.py,etc
gaasc_apps/<- contains all apps
core/
abstract_models.py
models.py
admin.py,...
about_app/
models.py,
admin.py
urls.py
'''
I am trying to leverage abstract class inside core app to models inside about_app app. Yes, between different apps.
Steps followed:
create abstract_models.py and define abstract class
import it in core/models.py
3.import the abstract class from core/models.py inside about_app/models.py
register the class in about_app/models.py to admin.py(in about_app/)
abstract_models.py file(inside core/abstract_models.py) has
import uuid
from django.db import models
class AbstractTimeStampModel(models.Model):
"""TimeStampModel that holds created_date and updated_date field"""
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
created_date = models.DateTimeField("Created date", auto_now_add=True)
updated_date = models.DateTimeField("Updated date", auto_now=True)
def __str__(self):
return self.created_date
class Meta:
abstract = True
class AbstractTextAreaOnly(AbstractTimeStampModel):
"""Abstract class for textfield"""
about = models.TextField(
verbose_name="Description",
blank=True
)
def __str__(self):
return "Textonly class-"+self.id
class Meta:
ordering = ['created_date']
models.py in core/models.py
from django.db import models
from .abstract_models import (
AbstractTextAreaOnly,
)
Now I want to use this abstract class in about_app/
So my derived class in models.py inside about_app/models.py looks:
from django.db import models
from gaasc_apps.core.models import(
AbstractTextAreaOnly,
)
class GeneralInformation(AbstractTextAreaOnly):
'''
Gives general information of college
'''
class Meta():
db_table = "general_information"
verbose_name="General information"
ordering=['created_date']
What I tried:
I tried to registering using following ways:
method1:
in admin.py in about_app/admin.py:
from django.contrib import admin
from .models import (
GeneralInformation,
)
#register(GeneralInformation)
class GeneralInformationAdmin(admin.ModelAdmin):
pass
method 2:
in about_app/admin.py
from django.contrib import admin
from .models import (
GeneralInformation,
)
class GeneralInformationAdmin(admin.ModelAdmin):
pass
admin.site.register(GeneralInformation,GeneralInformationAdmin)
method3:
in about_app/admin.py
......
class GeneralInformationAdmin(admin.ModelAdmin):
readonly_fields = ('id','about','created_date','updated_date')
list_display=('id','about','created_date')
fieldsets=[
('Id',{'fields':['id']}),
('About',{'fields':['about']}),
('Created_Date',{'fields':['created_date']}),
]
admin.site.register(GeneralInformation,GeneralInformationAdmin)
With all this solution GeneralInformation is not shown in admin panal/dashboard of django.
The solution seems to be simple but I don't know why its not working?
Some solution I tried are here:
How to register inherited sub class in admin.py file in django?
Django admin model Inheritance is it possible?
Register abstract model in admin django 1.6
VERSION:
Django-2.2
python-3.6
I have found the solution to the problem , it was simple
we need to define config setting in each apps. Due to lack of config setting and perticular directory structure it was not able to read it.E.g.
in about_app/__init__.py :
default_app_config = "gaasc_apps.about_app.apps.AboutAppConfig"
and in about_app/apps.py we should have like this
from django.apps import AppConfig
class AboutAppConfig(AppConfig):
name = 'gaasc_apps.about_app'
verbose_name="about application"
def ready(self):
pass

Django Relation between two models

I am very new to Django.
Can you please give a boilerplate of models how to relate two models between each other.
--Below is Section model
from articles.models import Article
# Create your models here.
class Section(models.Model):
#associations
user = models.ForeignKey(settings.AUTH_USER_MODEL)
article = models.ForeignKey(Article) #Article
--Below is Article model
from sections.models import Section
User = settings.AUTH_USER_MODEL
# Create your models here.
class Article(models.Model):
owner =models.ForeignKey(User, null=False)
sections = models.ManyToManyField( Section )
However. I got the below error:
ValueError: Cannot create form field for 'article' yet, because its related model 'articles.models' has not been loaded yet
Thanks All
B
Breaking cyclic imports
You defined a cyclic import: one module first has to import the other module, but the other module fist has to implement that module, so you defined a cycle.
In Django, one does not per se has to use a class reference to make ForeignKeys, one can use strings that refer to the correct model. In that case the Django framework, will later resolve these.
So we can break the cycle, for example with:
# sections/models.py
# no import from articles
# Create your models here.
class Section(models.Model):
#associations
user = models.ForeignKey(settings.AUTH_USER_MODEL)
# we use a string literal
article = models.ForeignKey('articles.Article', on_delete=models.CASCADE)
and then in the articles/models.py:
# articles/models.py
from sections.models import Section
User = settings.AUTH_USER_MODEL
# Create your models here.
class Article(models.Model):
owner = models.ForeignKey(User, null=False)
sections = models.ManyToManyField(Section)
So here we no longer import articles/models.py in the sections/models.py, and thus we break the cyclic import.
Note that you need to specify an on_delete for a ForeignKey, for example models.CASCADE.
Django's reverse relations
For this specific application however, it seems that you make a double relation between Section and Article, that basically is one relation, you should not do that, Django automatically writes the reverse relation, what you probably want to do, is give it a proper name, for example:
# sections/models.py
# no import from articles
# Create your models here.
class Section(models.Model):
#associations
user = models.ForeignKey(settings.AUTH_USER_MODEL)
# we use a string literal
article = models.ForeignKey(
'articles.Article',
on_delete=models.CASCADE,
related_name='sections'
)
and for articles/models.py:
# articles/models.py
User = settings.AUTH_USER_MODEL
# Create your models here.
class Article(models.Model):
owner = models.ForeignKey(User, null=False)
# no relation to section
Here we can obtain all Sections that relate to some_article with some_article.sections.all().

django-taggit on models with UUID as pk throwing out of range on save

I have models that uses UUID as its PK
class Foo(models.Model):
foo_id = models.UUIDField(
primary_key=True,
default=uuid.uuid4,
editable=False
)
tags = TaggableManager()
When I go and try to add a new tag
f = Foo.objects.latest('pk')
f.tags.add("testing")
I get DataError: integer out of range
When I import pdb on the cursor to view the SQL going in I see this.
(Pdb) params
(1, 287082253891563438098836942573405313042, 9)
(Pdb) sql
'INSERT INTO "taggit_taggeditem" ("tag_id", "object_id", "content_type_id") VALUES (%s, %s, %s) RETURNING "taggit_taggedit
m"."id"'
That long integer (287082253891563438098836942573405313042) trying to be insterted is obvsiouly the cause for the error. This number is the int of the UUID for foo_id
In [6]: foo.foo_id.int
Out[6]: 287082253891563438098836942573405313042
Is there something I can set to allow django-taggit to play nicely with contenttypes and UUID?
I'd like to extend #Pramod response, that was very helpful for me to find the right answer:
Taggit has another class that allows to change the behavior of the TaggedItem
Here is a snippet of how to implement this solution:
from django.db import models
from django.utils.translation import ugettext_lazy as _
from taggit.managers import TaggableManager
from taggit.models import GenericUUIDTaggedItemBase, TaggedItemBase
class UUIDTaggedItem(GenericUUIDTaggedItemBase, TaggedItemBase):
# If you only inherit GenericUUIDTaggedItemBase, you need to define
# a tag field. e.g.
# tag = models.ForeignKey(Tag, related_name="uuid_tagged_items", on_delete=models.CASCADE)
class Meta:
verbose_name = _("Tag")
verbose_name_plural = _("Tags")
class Food(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
# ... fields here
tags = TaggableManager(through=UUIDTaggedItem)
source: http://django-taggit.readthedocs.io/en/latest/custom_tagging.html#genericuuidtaggeditembase
Here's an answer based on Austin's comment.
In django-taggit, references to tagged models are stored in a model named GenericTaggedItemBase under a field called object_id. The object_id field is hardcoded to models.IntegerField. So it's not possible to tag models having UUID primary keys. The code is located here.
If all your models that need to be tagged are of the same type (in this case, models.UUIDField), then you can set object_id's type to models.UUIDField.
Here are the changes that have to be made, assuming you're using virtualenvwrapper
Locate the taggit package in the site packages folder. ~/virtualenvs/<your_virtualenv>/lib/<python_version>/site-packages/taggit
Copy the taggit directory into your project.
Delete the taggit directory from site-packages
In the models.py file in taggit, replace
object_id = models.IntegerField(verbose_name=_('Object id'), db_index=True) with
object_id = models.UUIDField(verbose_name=_('Object id'), db_index=True)
Migrate taggit.
python manage.py makemigrations taggit
python manage.py migrate

Django-photologue ImageModel

This is my first project in django and im using photologue for gallery, which is awesome and i really like it.
But there is one thing i dont get, how can i use its ImageModel?
I have a blog-app and with every new blogpost created in the admin interface i woud like to upload a image which is linked to that post.
from django.db import models
from tagging.fields import TagField
from tinymce import models as tinymce_models
from photologue.models import ImageModel
#import datetime
# Create your models here.
class Blog(models.Model):
title = models.CharField(max_length=150)
content = tinymce_models.HTMLField()
pub_date = models.DateTimeField(auto_now_add=True)
edit_date = models.DateTimeField(auto_now=True)
tags = TagField()
summary = models.CharField(max_length=30)
thumbnail = ImageModel()
def __unicode__(self):
return self.title
This code above doesn't seem to work or do anything in fact.
I have been rifling through the docs, google ect and trying to understand the photologue source myself but i cant seem to get it to work like i want to.
ImageModel is an abstract class. You can't use it as itself. Instead, you must subclass it:
class BlogImage(ImageModel):
pass
class Blog(models.Model):
...
thumbnail = models.ForeignKey(BlogImage, related_name='blogs')
But, the main purpose of ImageModel is to allow you to create a photo model with additional custom data that still behaves like one of photologue's models. photologue already has Photo which is a real model based on ImageModel that you can use if you just need the defaults.
class Blog(models.Model):
...
thumbnail = models.ForeignKey(Photo, related_name='blogs')

Linking Django ContentType framework through URLs

I have questionnaire app that allows for the dynamic creation of a Form. In my current system I link it to a Project. Here is an example of my models. I want to separate the questionnaire app completely from dependencies of the other apps in my current django project.
#project.models
class Project(models.Model):
name = models.CharField(max_length.....
category = models.CharField(max_length
question_sets = models.ManyToManyField(Question_Set)
#questionnaire.models
class Question(models.Model):
question = models.CharField(max_length....
question_type = models.IntegerField(choices=.....
class Question_set(models.Model):
name = models.CharField(....
questions = models.ManyToManyField(Question)
Inside my questionnaire.views, for this example, Ihave two basic functions Question_set create and Question create. In the Question_set create function I have a form that allows me to add created Questions to the Question_set and then save the Question_set. Currently I also pass the project_id in the url to this view so I can get the Project instance and add the Question_set
#questionnaire.views
def question_set_create(request, project_id, form_class=AddSetForm, template_name=....):
if request.method = "POST":
form = form_class(request.POST)
if form.is_valid():
set = form.save()
project = Project.objects.get(id=project_id)
project.question_sets.add(set)
....
#questionnaire.urls
#pattern for question_set_create
url(r'^(?P<project_id>[-\w]+)/add_set/$', 'questionnaire_create' , name="project_questionnaire_create"),
I believe the solution involves the Django ContentType Framework but I am not sure the best way to go about passing the model class via the url. So if the Question_set was to be saved to Foo model instead of Project. How in the url would I identify the model class?
I think the problem may be in the way you've organized your models. I would also avoid the use of a model name ending in _set as that could get very confusing. What about this instead:
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from questionnaire.models import Questionnaire
#project.models
class Project(models.Model):
name = models.CharField(max_length.....
category = models.CharField(max_length
questionnaires = generic.GenericRelation(Questionnaire)
#questionnaire.models
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
class Question(models.Model):
question = models.CharField(max_length....
question_type = models.IntegerField(choices=.....
class Questionnaire(models.Model):
name = models.CharField(...)
questions = models.ManyToManyField(Question)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey()
Once you have clearly defined the questionnaire as its own complete model, creating a URL becomes more straightforward:
#questionnaire.urls
#pattern for question_set_create
url(r'^(?P<content_type>[-\w]+)/(?P<object_id>[-\w]+)/add_set/$', 'questionnaire_create' , name="questionnaire_create"),
Where content_type is the name of the content type (say, 'projects.project' or something similar) and object_id is the primary key of the matching record.
So the equivalent URL for creating a questionnaire for project id #1 would be /questionnaires/projects.project/1/add_set/