This is a Model Class
class ModelName(models.Model):
(...)
pasta = TaggableManager(verbose_name=u'Pasta')
and a form template (normal :P )
{{form.as_p}}
I'd like to leave everything very clean and usefull.
But result is a list of TaggedItem Object :( :
[<TaggedItem: id: 2 tagged with general >, <TaggedItem: id: 3 tagged with outer >]
Instead of something like
general, outer
How do it fashionably in Django?
Give a look at the code in: https://github.com/alex/django-taggit/blob/master/taggit/forms.py. You will find the widget used to render the tags. You can use it to render them correctly.
Example:
models.py
from django.db import models
from taggit.managers import TaggableManager
class Example(models.Model):
name = models.CharField(max_length=20)
tags = TaggableManager()
forms.py
.models import Example
from django import forms
from taggit.forms import TagWidget
class ExampleForm(forms.ModelForm):
class Meta:
model = Example
fields = ('name', 'tags',)
widgets = {
'tags': TagWidget(),
}
I'd recommend you to check this answer too.
django - django-taggit form
I would use django-taggit-autosuggest as it offers better UI to the user.
Related
I am new to Django but not to developing.
I need to make an application in which user can do CRUD operations (Create, Read, Update, Delete). This functionality should apply to all models and the fields for Create & Update will be auto-generated from model attributes.
What I describe is pretty much the functionality that comes with the Admin page. However, I want to use it in my own app instead of using the Admin app.
For example, let's suppose we have Author and Book models:
(models.py)
from django.db import models
class Author(models.Model):
first_name = models.CharField(max_length=60)
last_name = models.CharField(max_length=60)
def __str__(self):
return self.last_name
class Book(models.Model):
title = models.CharField(max_length=60)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
def __str__(self):
return self.title
I suppose that the above information (models) could be enough for CRUD operations, without repeating code of the same logic for each model. I am aiming at a functionality like in admin page where all you have to do is register your model.
I am aware of ModelForm and Generic Views but while they help avoiding hard-coding form fields, I have not found a non-repetitive coding approach. I would like to avoid approaches like the following where same code is being duplicated for each model:
(forms.py)
from django import forms
from todo.models import Author, Book
class AuthorForm(forms.ModelForm):
class Meta:
model = Author
fields = '__all__'
class BookForm(forms.ModelForm):
class Meta:
model = Book
fields = '__all__'
(views.py)
from django.views.generic import CreateView
from.forms import AuthorForm, BookForm
from.models import Author, Book
class AuthorCreateView(CreateView):
model = Author
form_class = AuthorForm
...
class BookCreateView(CreateView):
model = Book
form_class = BookForm
...
So, what is the best approach for a DRY CRUD solution (like in Admin page)? Am I missing any Django features?
Putting my explanation in the comment together, you would get something like this:
from django.views import generic
from myapp.apps import MyAppConfig
from django.forms import modelform_factory
urlpatterns = []
for model in MyAppConfig.get_models():
create_url = path(
f"{model.__class___.__name__.lower()}/create",
generic.CreateView.as_view(
form_class=modelform_factory(model=model, fields='__all__'),
template_name=f"{model._meta.app_label}/create.html",
model=model
),
),
list_url = path(
f"{model.__class__.__name__.lower()}/",
generic.ListView.as_view(
template_name=f"{model._meta.app_label}/list.html",
model=model
),
),
...
urlpatterns.extend([create_url, list_url, read_url, update_url, delete_url])
So the principle is to use the generic view and model form factory, to generate standard crud views, derive path names from model name and use one template per view, in the application (derived from model's app_label).
Using the documentation I linked before, you should be able to piece things together.
from oscar.apps.catalogue.abstract_models import AbstractProduct
from oscar.core.compat import AUTH_USER_MODEL
from django.db import models
class Product(AbstractProduct):
seller = models.ForeignKey(
AUTH_USER_MODEL,
on_delete=models.CASCADE,
null=True)
from oscar.apps.catalogue.models import *
I added this code to forked catalog model >
I want to show it in the dashboard,Image of dashboard and dropdown box I tried admin.site.register but it is not working.
This is the code for override of form , when I fork and overrtide it doesn't work but when I change the code in core it works .
from oscar.apps.dashboard.catalogue.forms import ProductForm
from oscar.core.loading import get_class, get_classes, get_model
from yourappsfolder.catalogue.models import Product
class SellerField(ProductForm):
class Meta(ProductForm.Meta):
model =Product
fields = [
'title','seller', 'upc', 'description', 'is_public', 'is_discountable', 'structure']
You have forked the form incorrectly. Calling your form class SellerField will not work. The form class needs to have exactly the same name as the core form, otherwise Oscar's loader will not find it. Change it like this:
from oscar.apps.dashboard.catalogue.forms import ProductForm as BaseProductForm
class ProductForm(BaseProductForm):
class Meta(BaseProductForm.Meta):
fields = ['title','seller', 'upc', 'description', 'is_public', 'is_discountable', 'structure']
I've a model in Django with some fields. Let's say this exemplary one:
# <app>/models.py
from django.db import models
class Something(models.Model):
first_field = models.Charfield()
second_field = models.Charfield()
I use DjangoObjectType from graphene_django to map Django models to GraphQL types.
# <app>/schema.py
from graphene_django import DjangoObjectType
from .models import Something
class SomethingType(DjangoObjectType):
class Meta:
model = Something
Cause of auto camelcasing the model field second_field results in secondField in the GraphQL type. Now I'd like to rename the GraphQL type field from secondField to somethingFancy. How can I get this done easiest?
You can overwrite any field with DjangoObjectType. Your code may look like this.
class SomethingType(DjangoObjectType):
class Meta:
model = Something
something_fency = graphene.String()
def resolve_something_fency(self, info):
return self.second_field
For more details check out the docs
I need to display multiple models in django admin change list view. I want to use single search box to filter all of them at once. Is there an easy way to do it?
My idea was to inherit from admin site, add another view to it and iterate over models in modified change_list.html but i can't import models and ModelAdmins because i get django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet. error so i can't get the same context that django uses to render regular change_list.html.
What's the correct way to do it? Is there simpler approach?
As Ohad suggested, the most robust approach is probably to make formal relationships between the models from which you want the objects to display together. You have a couple of options here. Essentially you will want to make a master class and then subclass your models from it. This makes a lot of sense if your models are ontologically related to a parent concept. For example:
Publication
Book
Magazine issue
Books and magazines are both publications. They both share some fields, like title and publication date. But they differ in that a book usually has a single author and a magazine has volumes and issue dates. Django already provides a couple different approaches to subclassing using Model inheritance. However, after trying these myself I found that the django-polymorphic extension is way better. Here is a code example of a Django 3.0 app using django-polymorphic which has a Book model and a Magazine model with a single listing of all publications that shows all of the books and magazines in the system.
models.py
from django.db import models
from polymorphic.models import PolymorphicModel
class Publication(PolymorphicModel):
title = models.CharField(max_length=256)
publication_year = models.IntegerField()
class Book(Publication):
author_first = models.CharField(max_length=256)
author_last = models.CharField(max_length=256)
class Magazine(Publication):
volume_number = models.IntegerField()
issue_name = models.CharField(max_length=256)
admin.py
from django.contrib import admin
from polymorphic.admin import PolymorphicParentModelAdmin, PolymorphicChildModelAdmin, PolymorphicChildModelFilter
from .models import Publication, Book, Magazine
class PublicationChildAdmin(PolymorphicChildModelAdmin):
""" Base admin class for all child models """
base_model = Publication # Optional, explicitly set here.
#admin.register(Book)
class BookAdmin(PublicationChildAdmin):
base_model = Book # Explicitly set here!
# show_in_index = True # makes child model admin visible in main admin site
list_display = ('title', 'publication_year', 'author_first', 'author_last')
#admin.register(Magazine)
class MagazineAdmin(PublicationChildAdmin):
base_model = Magazine # Explicitly set here!
# show_in_index = True # makes child model admin visible in main admin site
list_display = ('title', 'publication_year', 'issue_name')
#admin.register(Publication)
class PublicationParentAdmin(PolymorphicParentModelAdmin):
""" The parent model admin """
base_model = Publication # Optional, explicitly set here.
child_models = (Book, Magazine)
list_filter = (PolymorphicChildModelFilter,) # This is optional.
list_display = ('title', 'publication_year')
This will of course only display those fields that are common (in the Publication model). If you want to display fields that are particular to each model there are various tricks for this. Here's one quick way to do it:
admin.py
...
#admin.register(Publication)
class PublicationParentAdmin(PolymorphicParentModelAdmin):
""" The parent model admin """
base_model = Publication # Optional, explicitly set here.
child_models = (Book, Magazine)
list_filter = (PolymorphicChildModelFilter,) # This is optional.
list_display = ('title', 'publication_year', 'issue', 'author')
def author(self, obj):
if obj.polymorphic_ctype.model == 'book':
book = Book.objects.get(pk=obj.pk)
return book.author_first + ' ' + book.author_last
return None
def issue(self, obj):
if obj.polymorphic_ctype.model == 'magazine':
return str(Magazine.objects.get(pk=obj.pk).issue_name)
return None
Tada!
From the docs it seems that there is no easy solution.(if there is no relation between the models)
https://docs.djangoproject.com/en/2.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.search_fields
So if the search is commonly used build a special model/models that combines the data that might be searched
Using the example in the Django documentation for utilizing IntergerRangeField with Postgres backend to create ranges in "ages" with the following model:
from django.contrib.postgres.fields import IntegerRangeField
from psycopg2.extras import NumericRange
from django.db import models
class Event(models.Model):
name = models.CharField(max_length=200)
ages = IntegerRangeField()
def __str__(self):
return self.name
This works perfectly however when using Django Rest Frameworks and using filter view with the following filter:
import django_filters
from django_filters import rest_framework as filters
from app import Event
class EventFilter(django_filters.FilterSet):
ages = django_filters.NumericRangeFilter(queryset=Event.objects.all())
class Meta:
model = Event
fields = ['name','ages']
the view generates an AssertionError at /api/event_filter/ and suggests adding an override to Meta.filters_override.
What I would really appreciate is an example based on the example model for this override, the example in django-filters documentation http://django-filter.readthedocs.io/en/latest/ref/filterset.html#filter-overrides, isn't helping me understand how to get this to render. I would appreciate any help with this so I can understand with this example to utilize this in the future.
Based on the documentation, overriding custom option seems to be done inside the Meta class and not the way you have done it.
ages = django_filters.NumericRangeFilter(queryset=Event.objects.all())
There are a few potential issues here:
The declaration itself does not seem supported
The overrides appear to be supported from within the Meta class
queryset is not a valid option for NumericRangeFilter AFAIk
Can you try the following:
from django.contrib.postgres.fields import IntegerRangeField
class EventFilter(django_filters.FilterSet):
class Meta:
model = Event
fields = ['name','ages']
filter_overrides = {
IntegerRangeField: {
'filter_class': django_filters.NumericRangeFilter,
}
}
Working on a similar thing.
from django.contrib.postgres.fields import ArrayField
import django_filters
class SkillFilter(django_filters.Filters):
class Meta:
model = Skill
filter_overrides = {
ArrayField: {
'filter_class': django_filters.CharFilter,
'extra': lambda f: {
'lookup_expr': 'icontains',
},
},
}
class SkillType(DjangoObjectType):
class Meta:
model = Skill
filterset_class = SkillFilter
interfaces = (relay.Node, )
Then my model
from django.contrib.postgres.fields import ArrayField
from django.db import models
class Skill(models.Model):
name = models.CharField(max_length=50)
skills = ArrayField(models.CharField(max_length=200), blank=True)
Doing this solves the problem, hopefully you can leverage on this to get a solution
Note: I think django_filters does not have support for an array filter that is why I used the CharFilter and this works for me