I have two models, Client and PaymentOptions.
class Client(models.Model):
name = models.CharField(max_length=50, null=True, unique=False)
contact = models.CharField(max_length=50, null=True, unique=False)
address = models.CharField(max_length=300, null=True, unique=False)
class ClientPaymentOption(models.Model):
name = models.CharField(max_length=30, null=True, unique=False, choices=CARD_TYPE)
action = models.CharField(max_length=30, null=True, unique=False, choices=CLIENT_PAYMENT_OPTION)
percent = models.FloatField(max_length=10, null=True, unique=False)
fixamount = models.FloatField(max_length=20, null=True, unique=False)
itemcharged = models.CharField(max_length=10, null=True, unique=False)
In my admin.py, I just want to have when I create a new Client, it will also create it's ClientPaymentOption.
I have this in my admin.py:
admin.site.disable_action('delete_selected')
class ClientAdmin(admin.ModelAdmin):
#display list
list_display = ('name','b_type','banner','logo',
'contact','address','account_type',
'status','currency','color','user',
)
#display fields
fields = ('name','b_type','banner','logo','contact',
'address','account_type','status',
'currency','color','user',
)
pass
admin.site.register(Client, ClientAdmin)
I have done this in my views.py,
client = Client.objects.create( .... )
ClientPaymentOption.objects.create( ...., client=client )
but i dont have any idea to do this in django admin.
do anyone have an idea about my situation? thanks in advance ...
You can override standard django-admin change_view and add ClientPaymentOption.objects.create( ...., client=client )
there.
A short example from django docs:
class MyModelAdmin(admin.ModelAdmin):
# A template for a very customized change view:
change_form_template = 'admin/myapp/extras/openstreetmap_change_form.html'
def get_osm_info(self):
# ...
pass
def change_view(self, request, object_id, extra_context=None):
extra_context = extra_context or {}
extra_context['osm_data'] = self.get_osm_info()
return super(MyModelAdmin, self).change_view(request, object_id,
extra_context=extra_context)
Related
I want to create a post requests that sends a file along with information in the form of a dictionary. I have the following implementation:
# conftest.py
import pytest
#pytest.fixture
def api_client():
from rest_framework.test import APIClient
return APIClient()
Testing with pytest:
# test_dataset.py
#pytest.mark.django_db()
class TestDatasetEndpoint:
def test_dataset_create(self, api_client):
data_raw = baker.make(Dataset)
serialized_dataset = DatasetSerializer(data_raw).data
print(serialized_dataset)
file_path = "./Top 250s in IMDB.csv"
with open(file_path, "rb") as fp:
encoded_data = encode_multipart(
BOUNDARY, {"data": serialized_dataset, "file": fp}
)
response_post = api_client.post(
reverse("datasets-list"),
encoded_data,
content_type="multipart/form-data; boundary=BOUNDARY",
)
assert response_post.status_code == 201
Server side:
# views.py
class DatasetViewSet(viewsets.ModelViewSet):
queryset = Dataset.objects.all()
serializer_class = DatasetSerializer
def create(self, request, *args, **kwargs) -> Response:
data = request.data
return Response(request.data["data"], status=status.HTTP_201_CREATED)
Lastly, the Dataset model is:
class Dataset(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(max_length=100)
path = models.CharField(max_length=100, editable=False, null=True, blank=True)
description = models.CharField(max_length=500, null=True, blank=True)
useCase = models.CharField(max_length=100, editable=False, null=True, blank=True)
useCaseSpecificVariable = models.CharField(
max_length=50, editable=False, null=True, blank=True
)
origin = models.CharField(max_length=50, editable=False, default="")
creationDate = models.DateTimeField(editable=False, null=True, blank=True)
workflowsUsedOn = models.JSONField(blank=True, null=True)
owners = models.JSONField(blank=True, null=True)
sampleSize = models.IntegerField(editable=False, default=0)
featureSize = models.IntegerField(editable=False, default=0)
metadataPath = models.CharField(
max_length=100, editable=False, null=True, blank=True
)
timeFrom = models.DateTimeField(editable=False, null=True, blank=True)
timeUntil = models.DateTimeField(editable=False, null=True, blank=True)
The response i am getting is a combination of the dict and the file data. How can i handle the data and the file in the server side (views.py)?
Django can handle such requests via form. So the pattern is the following:
forms.py
from django import forms
class DatasetForm(forms.Form):
class Meta:
model = Dataset
views.py
class DatasetViewSet(viewsets.ModelViewSet):
queryset = Dataset.objects.all()
serializer_class = DatasetSerializer
def create(self, request, *args, **kwargs) -> Response:
dataset_form = DatasetForm(request.POST, request.FILES)
if dataset_form.is_valid():
dataset = dataset_form.save()
return Response(self.serializer_class(dataset).data, status=status.HTTP_201_CREATED)
else:
return Response(dataset_form.error_messages, status=status.HTTP_400_BAD_REQUEST)
Note that you will need to have a field that can store file on your model. E.g: file = models.FileField(upload_to='attachments', blank=False)
Then content of fields in dictionary (and content of your file) will be automatically mapped via form to the relevant fields.
See additional info: https://docs.djangoproject.com/en/4.0/topics/forms/
is it possible to add an age field that is auto filled in the runtime based on another date of birth field at the django admin interface, i added a screenshot trying to explain more what i mean
my models.py
class FamilyMember(models.Model):
transaction = models.ForeignKey(Transaction, on_delete=models.CASCADE)
family_group = models.ForeignKey(FamilyGroup,
on_delete=models.CASCADE,
null=True,
blank=True)
name = models.CharField(max_length=100, null=True, blank=True)
date_of_birth = models.DateField(null=True, blank=True)
relationship = models.ForeignKey(Relationship, on_delete=models.PROTECT)
dependant_child_age_range = models.ForeignKey(DependantChildAgeRange,
null=True,
blank=True,
on_delete=models.PROTECT)
care_percentage = models.PositiveSmallIntegerField(
null=True, blank=True, validators=[
MaxValueValidator(100),
])
income = models.DecimalField(max_digits=6,
decimal_places=2,
null=True,
blank=True)
rent_percentage = models.PositiveSmallIntegerField(
null=True, blank=True, validators=[
MaxValueValidator(100),
])
admin.py
class FamilyMemberInline(admin.TabularInline):
def formfield_for_foreignkey(self, db_field, request, **kwargs):
action = request.META['PATH_INFO'].strip('/').split('/')[-1]
if action == 'change':
transaction_id = request.META['PATH_INFO'].strip('/').split('/')[-2]
if db_field.name == "family_group":
kwargs["queryset"] = FamilyGroup.objects.filter(transaction=transaction_id)
return super(FamilyMemberInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
model = FamilyMember
extra = 0
def sufficient_info_provided (self, obj):
return obj.sufficient_information_provided
sufficient_info_provided.boolean = True
readonly_fields = ['sufficient_info_provided',]
Override your inline's get_queryset method to annotate the queryset with the calculation. The annotation will add an age attribute to each object in the queryset.
Then as you can see in the ModelAdmin.list_display documentation, you can include a string representing a ModelAdmin method that accepts one argument, the model instance. Inline's work in the same way but you must include the method in ModelAdmin.readonly_fields.
Putting it all together:
class FamilyMemberInline(admin.TabularInline):
...
fields = (..., 'get_age')
readonly_fields = ('get_age',)
def get_queryset(self, request):
return (
super().get_queryset(request)
.annotate(age=...)
)
def get_age(self, instance):
return instance.age
I am trying to create a blog post model and I added a schedule filed on Django model that I can schedule my post by date and time if schedule time == now. Then post should be verified and display to dashboard so for this I used def save function. But save function does not respond. When I tried to schedule a blog post from admin panel it did not change verified = True. Here is code what I did so far:
from django.utils import timezone
now = timezone.now() # get the current time
class Blog(models.Model):
author = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="post")
title = models.CharField(_("Title of blog post"),
max_length=250, null=True, blank=True)
header = models.CharField(
_("Blog title eg. TIPS, "), max_length=250, null=True, blank=True)
slug = models.SlugField(_("Slug of the title"), max_length=250,
unique_for_date='publish', null=True, blank=True)
photo = models.ImageField(_("Blog post main image"), default="img.png",
null=True, blank=True, upload_to='users/avatar')
read_time = models.TimeField(
_("Blog post read time"), null=True, blank=True)
category = models.ForeignKey(Category, verbose_name=_(
"Blog category list"), on_delete=models.CASCADE, null=True, blank=True)
publish = models.DateField()
tags = TaggableManager(blank=True)
description = HTMLField()
views = models.IntegerField(default="0") # <- here
verified = models.BooleanField(
_("Approved post before push on production"), default=False)
schedule = models.DateTimeField(
_("Schedule post by date and time"), auto_now=False, auto_now_add=False, null=True, blank=True)
class Meta:
verbose_name = _('blog')
verbose_name_plural = _('blogs')
def __str__(self):
return self.title
def save(self, *args, **kwargs):
if self.schedule >= now:
self.verified = True
print(self.verified)
else:
self.slug = slugify(self.title) # this also not respond
super(Blog, self).save(*args, **kwargs)
what is now ? I don't see it defined. I think that the correct way to do it is
from django.utils.timezone import now
if self.schedule <= now():
do it
The save() function is only called when you save an object. This thus means that although an object has a self.schedule that is already passed the current timestamp, one should wait until the object is saved again (and that can take a long time).
It is better to annotate the queryset with a field that specifies that it is verified when self.scheduled is less than (or equal to) Now(). We thus can define a manager that injects the annotation, and remove the verified field:
from django.db.models import BooleanField, ExpressionWrapper, Q
from django.db.models.functions import Now
class BlogManager(models.Manager):
def get_queryset(self, *args, **kwargs):
return super().get_queryset(*args, **kwargs).annotate(
verified=ExpressionWrapper(Q(scheduled__lte=Now()), BooleanField())
)
class Blog(models.Model):
author = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="post")
title = models.CharField(_("Title of blog post"),
max_length=250, null=True, blank=True)
header = models.CharField(
_("Blog title eg. TIPS, "), max_length=250, null=True, blank=True)
slug = models.SlugField(_("Slug of the title"), max_length=250,
unique_for_date='publish', null=True, blank=True)
photo = models.ImageField(_("Blog post main image"), default="img.png",
null=True, blank=True, upload_to='users/avatar')
read_time = models.TimeField(
_("Blog post read time"), null=True, blank=True)
category = models.ForeignKey(Category, verbose_name=_(
"Blog category list"), on_delete=models.CASCADE, null=True, blank=True)
publish = models.DateField()
tags = TaggableManager(blank=True)
description = HTMLField()
views = models.IntegerField(default=0)
schedule = models.DateTimeField(
_("Schedule post by date and time"), auto_now=False, auto_now_add=False, null=True, blank=True)
objects = BlogManager()
I have a created Django-CMS Plugin with a ManytoManyField to another model. When creating the Plugin on the Front-End, i want the user to be able to filter the ManytoManyField list (which might be too long).
By the way this future is already on Django admin:
class ModelAdmin(admin.ModelAdmin):
list_filter = ('field_name', )
form = PartnerLogoTableForm
Is it possible to have something similar like that on my
cms_plugins.py:
class PartnerLogoTablePlugin(CMSPluginBase):
model = LogoTablePlugin
form = LogoTablePluginForm
name = _('LogoTable Plugin')
render_template = False
search_fields = ('description',)
def render(self, context, instance, placeholder):
self.render_template = 'aldryn_logo_tables/plugins/%s/logotable.html' % instance.style
context.update({
'object': instance,
'placeholder': placeholder,
})
return context
plugin_pool.register_plugin(PartnerLogoTablePlugin)
models.py:
class PartnerLogoTable(models.Model):
name = models.CharField(_('Partner name'), max_length=255)
image = FilerImageField(verbose_name=_('Image'), null=True, blank=True, on_delete=models.SET_NULL)
partner_url = models.TextField(_('Partner url'), null=True, blank=True, validators=[URLValidator()])
is_active = models.BooleanField(_('Is active'), blank=True, default=True)
created_at = models.DateTimeField(_('Created at'), auto_now_add=True)
updated_at = models.DateTimeField(_('Updated at'), auto_now=True)
order = models.IntegerField(_('Order'), null=True, blank=True)
class Meta:
verbose_name = _('Partner Logo')
verbose_name_plural = _('Partner Logos')
ordering = ['order']
def __str__(self):
return self.name
class LogoTablePlugin(CMSPlugin):
DEFAULT = 'default'
LOGOTABLE_CHOICES = [
(DEFAULT, _('Default')),
]
description = models.CharField(_('Description'), max_length=255, null=True, blank=True)
partner = models.ManyToManyField(PartnerLogoTable, verbose_name=_('Partner'))
logo_per_row = models.IntegerField(_('Logo per line'), default=1, null=True, blank=True,
validators=[MaxValueValidator(4), MinValueValidator(1)],
help_text=_('Number of logos to be displayed per row'))
style = models.CharField(_('Style'), choices=LOGOTABLE_CHOICES + get_additional_styles(), default=DEFAULT,
max_length=50, blank=True, null=True, )
class Meta:
verbose_name = _('Partner Logo Plugin')
verbose_name_plural = _('Partner Logo Plugins')
def __unicode__(self):
return u'%s' % self.description
forms.py
class LogoTablePluginForm(forms.ModelForm):
model = LogoTablePlugin
def clean_style(self):
.....
return style
class PartnerLogoTableForm(forms.ModelForm):
model = PartnerLogoTable
def clean(self):
....
return self.cleaned_data
This is how the plugin looks now
ModelSelect2Multiple from django-autocomplete-light seems perfect for your use case.
here is my model, serializer and output but when i want to create a new page it ask me to add a whole new user as its just a foreign-key it need to be a number like 1 (user id) and same in the case of categories how can i solve it.... help me please
serializers.py
class TeamMembersSerializer(serializers.ModelSerializer):
class Meta:
model = TeamMembers
fields = [
'user',
'page',
]
depth = 1
class SocialAccountsSerializer(serializers.ModelSerializer):
social = SocialCatSerializer()
class Meta:
model = SocialAccounts
fields = [
'page',
'social',
'link'
]
depth = 1
class PageImageSerializer(serializers.ModelSerializer):
class Meta:
model = PageImages
fields = [
'page',
'image',
]
depth = 1
class PageSerializer(serializers.ModelSerializer):
owner = UserSerializer()
catagory = BusinessCatSerializers()
business_type = BusinessTypeSerializer()
TeamMembers = TeamMembersSerializer(read_only=True)
social_accounts = SocialAccountsSerializer(read_only=True)
images = PageImageSerializer(read_only=True)
class Meta:
model =Page
fields = [
'id',
'owner',
'catagory',
'name',
'username',
'images',
'start_date',
'business_type',
'contect_number',
'email_address',
'website',
'TeamMembers',
'social_accounts',
'about',
'impression',
'Awards',
'Product',
'privacy_policy',
'is_active',
]
Models.py
class Page(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE)
catagory = models.ForeignKey(BusinessCatagories, on_delete=models.CASCADE, null=True, blank=True, default=None)
name = models.CharField(max_length=254, unique=True ,default=None, blank=True)
username = models.CharField(max_length=254, unique=True, blank=True)
start_date = models.DateTimeField(auto_now_add=True)
business_type = models.ForeignKey(BusinessType, on_delete=models.CASCADE, null=True, blank=True, default=None)
contect_number = models.CharField(max_length=254, default=None, blank=True)
email_address = models.EmailField(default=None, blank=True)
website = models.URLField(default=None, blank=True)
about = models.TextField(default=None, blank=True)
impression = models.TextField(default=None, blank=True)
Awards = models.CharField(max_length=254, default=None, blank=True)
Product = models.CharField(max_length=254, default=None, blank=True)
privacy_policy = models.URLField(default=None, blank=True)
is_active = models.BooleanField(default=True)
def __str__(self):
return self.name
class TeamMembers(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, default=None, blank=True)
page = models.ForeignKey(Page, on_delete=models.CASCADE, default=None, blank=True)
def __str__(self):
return self.user.name
class SocialAccounts(models.Model):
page = models.ForeignKey(Page, on_delete=models.CASCADE, default=None, blank=True)
social = models.ForeignKey(SocialCats, on_delete=models.CASCADE, default=None, blank=True)
link = models.URLField(default=None, blank=True)
def __str__(self):
return self.link
class PageImages(models.Model):
page = models.ForeignKey(Page, on_delete=models.CASCADE, default=None, blank=True)
image = models.ImageField(default=None, blank=True, upload_to=settings.MEDIA_ROOT)
def __str__(self):
return self.page.name
output is this but i need images field TeamMember field in it but its not appearing plus it want me to add a new user instead of asking for Foreignkey "id"
What you want is to use Primary key related field. It helps you to represent the target of the relationship using its primary key.
It should look somewhat like this.
Note: Mind the typo for any name
class PageSerializer(serializers.ModelSerializer):
owner = serializers.PrimaryKeyRelatedField(queryset = User.objects.all())
catagory = serializers.PrimaryKeyRelatedField(queryset = BuisnessCat.objects.all())
business_type = BusinessTypeSerializer()
TeamMembers = TeamMembersSerializer(read_only=True)
social_accounts = SocialAccountsSerializer(read_only=True)
images = PageImageSerializer(read_only=True)
You can read more about PrimaryKeyRelatedField here.
Now whenever creating any Page, all you need to supply are primary key for owner and category.
You are looking for Writable Nested Serializer.
In short you have to override create() method of PageSerializer
class PageSerializer(serializers.ModelSerializer):
....
....
your code
def create(self, validated_data):
# pop data of every related fields like "owner", "cateagory" etc from validated_data
owner = validated_data.pop("owner")
owner = User.objects.create(**owner)
category = validated_data.pop("category")
# create or retrieve category instance ,as above
...
...
...
# finally
return Page.objects.create(**validated_data,owner=owner,category=category, and other related instances)