I have created the following TagBase and each category can have subcategory...
Will this work? How can I override its add function in the TaggableManager?
class Category(TagBase):
parent = models.ForeignKey('self', blank=True, null=True,
related_name='child')
description = models.TextField(blank=True, help_text="Optional")
class Meta:
verbose_name = _('Category')
verbose_name_plural = _('Categories')
django-taggit/docs/custom_tagging.txt describes how. You must define an intermediary model with a foreign key tag to your TagBase subclass.
from django.db import models
from taggit.managers import TaggableManager
from taggit.models import ItemBase
# Required to create database table connecting your tags to your model.
class CategorizedEntity(ItemBase):
content_object = models.ForeignKey('Entity')
# A ForeignKey that django-taggit looks at to determine the type of Tag
# e.g. ItemBase.tag_model()
tag = models.ForeignKey(Category, related_name="%(app_label)s_%(class)s_items")
# Appears one must copy this class method that appears in both TaggedItemBase and GenericTaggedItemBase
#classmethod
def tags_for(cls, model, instance=None):
if instance is not None:
return cls.tag_model().objects.filter(**{
'%s__content_object' % cls.tag_relname(): instance
})
return cls.tag_model().objects.filter(**{
'%s__content_object__isnull' % cls.tag_relname(): False
}).distinct()
class Entity(models.Model):
# ... fields here
tags = TaggableManager(through=CategorizedEntity)
Related
I've just set up the whole import-export thing and I just can't make it export a field from another model, using the foreign key.
models.py
from django.db import models
from django.contrib.auth.models import User
from datetime import date
from .validators import validate_file_size
# Create your models here.
class CORMeserii(models.Model):
CodCOR = models.CharField(max_length=25, primary_key=True, unique=True)
MeserieCor = models.CharField(max_length=50, unique=True)
def __str__(self):
return str(self.CodCOR + " - " + self.MeserieCor)
class Meta:
verbose_name_plural = "CORuri"
class Oferta(models.Model):
solicitant = models.ForeignKey(User, on_delete=models.CASCADE)
cor = models.ForeignKey(CORMeserii, on_delete=models.CASCADE)
dataSolicitare = models.DateField(default=date.today)
locuri = models.IntegerField()
agentEconomic = models.CharField(max_length=50)
adresa = models.CharField(max_length=150)
dataExpirare = models.DateField()
experientaSolicitata = models.CharField(max_length=200)
studiiSolicitate = models.CharField(max_length=200)
judet = models.CharField(max_length=20)
localitate = models.CharField(max_length=25)
telefon = models.CharField(max_length=12)
emailContact = models.EmailField(max_length=40)
rezolvata = models.BooleanField(default=False)
def __str__(self):
return str(self.cor)
admin.py
from django.contrib import admin
from .models import Oferta, CORMeserii
from import_export import resources
from import_export.admin import ImportExportMixin, ImportExportModelAdmin
import tablib
# Register your models here.
class CorImEx(resources.ModelResource):
class Meta:
model = CORMeserii
class CorAdmin(ImportExportMixin, admin.ModelAdmin):
list_display = ('CodCOR', 'MeserieCor')
resource_class = CorImEx
class CorImExAdmin(ImportExportModelAdmin):
resource_class = CorImEx
class OferteImEx(resources.ModelResource):
class Meta:
model = Oferta
fields = ('id', 'solicitant', 'cor', 'oferta.cor.MeserieCor')
class OfertaAdmin(ImportExportMixin, admin.ModelAdmin):
list_display = ('id', 'solicitant', 'dataExpirare', 'dataSolicitare')
resource_class = OferteImEx
class OferteImExAdmin(ImportExportModelAdmin):
resource_class = OferteImEx
admin.site.register(Oferta, OfertaAdmin)
admin.site.register(CORMeserii, CorAdmin)
You can see it in the OferteImEx class - the field 'oferta.cor.MeserieCor'.
I want to export the MeserieCor field from the model CORMeserii - but I can't figure it out.
I tried with: 'oferta.cor.MeserieCor',
cor.MeserieCor', 'MeserieCor' (even though the last 2 ones don't make sense to me at all).
Is there any way to export that field somehow, even though it is from another model? (I'm pretty sure there is but I can't figure it out)
Thanks.
In Django you use double underscore (__) to follow relationship in lookups. It's in the documentation:
Django offers a powerful and intuitive way to “follow” relationships in lookups, taking care of the SQL JOINs for you automatically, behind the scenes. To span a relationship, just use the field name of related fields across models, separated by double underscores, until you get to the field you want.
Link: Lookups that span relationship
There is even an example in the django import export documentation how to follow relationship:
When defining ModelResource fields it is possible to follow model relationships:
class BookResource(resources.ModelResource):
class Meta:
model = Book
fields = ('author__name',)
Source: https://django-import-export.readthedocs.io/en/latest/getting_started.html#customize-resource-options
I am creating a todo list API(backend) in django rest framework. I have two models List and Task
#models.py
from django.db import models
# Create your models here.
class List(models.Model):
list_name = models.CharField(max_length=200)
def __str__(self):
return self.list_name
class Meta:
db_table = 'list'
class Task(models.Model):
todo_list = models.ForeignKey(List, on_delete=models.CASCADE)
task_name = models.CharField(max_length=500)
due_date = models.DateField()
done = models.BooleanField(default=False)
def __str__(self):
return self.task_name
class Meta:
db_table = 'task'
The serializers file,
#serializers.py
from rest_framework import serializers
from rest_framework_serializer_extensions.serializers import SerializerExtensionsMixin
from .models import List, Task
class ListSerializer(SerializerExtensionsMixin, serializers.ModelSerializer):
class Meta:
model = List
fields = "__all__"
class TaskSerializer(SerializerExtensionsMixin, serializers.ModelSerializer):
class Meta:
model = Task
fields = "__all__"
expandable_fields = dict(
todolist=ListSerializer
)
My todo list app will have multiple lists and each list have multiple tasks. Each task will have a due date and can be marked as done. I am trying to add the number of pending tasks to my List json. How do I go about doing that?
You can add a new field using SerializerMethodField:
class ListSerializer(SerializerExtensionsMixin, serializers.ModelSerializer):
pending_count = serializers.SerializerMethodField()
class Meta:
model = List
fields = "__all__"
def get_pending_count(self, obj):
return obj.task_set.filter(done=False).count()
I have a Django model that looks like this (simplified of course):
from django.db import models
from polymorphic.models import PolymorphicModel
class Tournament(models.Model):
slug = models.CharField(max_length=100, unique=True)
class Event(PolymorphicModel):
tournament = models.ForeignKey(Tournament, related_name='events')
slug = models.CharField(max_length=100)
class PracticeEvent(Event):
pass
class MatchEvent(Event):
winner = models.CharField(max_length=100, null=True, blank=True, default=None)
Tournaments consist of two kinds of events: practice events, and matches. I'd like to expose this model using GraphQL, using Graphene. This is what I have come up with:
import graphene
from graphene_django import DjangoObjectType
from . import models
class TournamentType(DjangoObjectType):
class Meta:
model = models.Tournament
exclude_fields = ('id',)
class EventType(graphene.Interface):
tournament = graphene.Field(TournamentType, required=True)
slug = graphene.String(required=True)
class PracticeEventType(DjangoObjectType):
class Meta:
model = models.PracticeEvent
interfaces = (EventType,)
exclude_fields = ('id',)
class MatchEventType(DjangoObjectType):
class Meta:
model = models.MatchEvent
interfaces = (EventType,)
exclude_fields = ('id',)
extra_types = {PracticeEventType, MatchEventType}
class Query(graphene.ObjectType):
tournaments = graphene.List(TournamentType)
events = graphene.List(EventType)
# ... resolvers ...
schema = graphene.Schema(
query=Query,
types=schema_joust.extra_types,)
So far, so good; I can query events { ... } directly, and even the tournament is available. However, as there is no DjangoObjectType with model = models.Event, I can't query tournaments { events {...} }...
How can I fix this? I can't make EventType a DjangoObjectTpe, and I don't know to add the events field after the fact.
On their own, EventType.tournament and TournamentType.events aren't so hard. The first one is shown in the question, and the second one can be implemented like this:
class EventType(graphene.Interface):
slug = graphene.String(required=True)
class TournamentType(DjangoObjectType):
class Meta:
model = models.Tournament
exclude_fields = ('id',)
events = graphene.List(EventType)
def resolve_events(self, info):
return self.events.all()
graphene-django doesn't recognize the relationship, but declaring and resolving the field manually does the trick. To also get the reverse-field, which would work if we didn't need to reference TournamentType, I digged into graphene-django and found graphene_django.converter.convert_django_field_with_choices. This lets us define the field like this:
import graphene
from graphene_django import DjangoObjectType, converter, registry
from . import models
class EventType(graphene.Interface):
tournament = converter.convert_django_field_with_choices(
models.Event.tournament.field, registry.get_global_registry())
slug = graphene.String(required=True)
Perhaps a Union type is what you want, combined with declaring EventType explicitly to inherit from an interface:
import graphene
# Rename your existing EventType to EventTypeInterface and redefine like
class EventType(DjangoObjectType):
class Meta:
model = Event
interfaces = [EventTypeInterface]
class EventUnionType(graphene.Union):
#classmethod
def resolve_type(cls, instance, info):
if isinstance(instance, MatchEvent):
return MatchEventType
elif isinstance(instance, PracticeEvent):
return PracticeEventType
return EventType
class Meta:
types = [MatchEventType, PracticeEventType, EventType]
Given these models:
class Company(models.Model):
company_name = models.CharField(max_length=50, unique=True)
....
class Product(models.Model):
company = models.ForeignKey(Company)
product_name = models.CharField(max_length=100)
...
class Inventory(models.Model):
product = models.ForeignKey(Product, null=True, unique=True)
...
Importing from an XLS into Inventory with company_name and product_name properly specified, that is the XLS file contains a single row specifing the company_name and product_name for a unique Product.
The product object can be found in Django/python by::
Product.objects.filter(company__company_name=company_name, product_name=product_name)
How should the Django-import-export resources.ModelResources be constructed to support import via the admin?
In your Admin.py use this code.
from import_export.admin import ImportExportModelAdmin,ExportMixin
from import_export import fields,widgets
from import_export import resources
from django.contrib.admin import DateFieldListFilter
class ProductResource(resources.ModelResource):
def export(self, queryset=None):
if queryset is None:
queryset = self.get_queryset()
headers = self.get_export_headers()
data = tablib.Dataset(headers=headers)
for obj in queryset.iterator():
data.append(self.export_resource(obj))
return data
class Meta:
model = Product
class ProductAdmin(ImportExportModelAdmin):
resource_class = ProductResource
list_filter = ('product_name','company__company_name')
list_display = ('....','....','...')
admin.site.register(Product,ProductAdmin)
for further refrence use https://django-import-export.readthedocs.org/en/latest/installation.html
I've implemented a circular OneToMany relationship at a Django model and tried to use the limit_choices_to option at this very same class.
I can syncdb without any error or warning but the limit is not being respected.
Using shell I'm able to save and at admin I receive the error message:
"Join on field 'type' not permitted.
Did you misspell 'neq' for the lookup
type?"
class AdministrativeArea(models.Model):
type = models.CharField(max_length=1, choices=choices.ADMIN_AREA_TYPES)
name = models.CharField(max_length=60, unique=True)
parent = models.ForeignKey('AdministrativeArea',
null=True,
blank=True,
limit_choices_to = Q(type__neq='p') & Q(type__neq=type)
)
The basic idea for the limit_choices_to option is to guarantee that any type "p" cannot be parent ofr any other AdministrativeArea AND the parent cannot be of the same type as the current AdministrativeArea type.
I'm pretty new to Django ... what am I missing?
Thanks
You can create a model form that adjusts specific field's queryset dynamically when working with existing model instance.
### in my_app/models.py ###
class AdministrativeArea(models.Model):
type = models.CharField(max_length=1, choices=choices.ADMIN_AREA_TYPES)
name = models.CharField(max_length=60, unique=True)
parent = models.ForeignKey('AdministrativeArea',
null=True,
blank=True,
limit_choices_to = Q(type__neq='p')
)
### in my_app/admin.py ###
from django.contrib import admin
import django.forms as forms
from my_app.models import AdministrativeArea
class class AdministrativeAreaAdminForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(AdministrativeAreaAdminForm, self).__init__(*args, **kwargs)
instance = kwargs.get('instance', None)
if instance is not None:
parentField = self.fields['parent']
parentField.queryset = parentField.queryset.filter(type__neq=instance.type)
class Meta:
model = AdministrativeArea
class AdministrativeAreaAdmin(admin.ModelAdmin):
form = AdministrativeAreaAdminForm
Such form could be used also outside admin site if you need the filtering there.