I use two interconnected ChainedForeignKey fields, but they don't. why? - django

my problem:
I have three models. il (province), ilce (district) and mahalle (neighborhood).
I filter with smart-select. works smoothly in the entry of information. When I looked at the database, I saw that mahalle (neighborhood) data was recorded. but the mahalle (neighborhood) widget sounds empty.
my models:
class il(models.Model):
adi = models.CharField(max_length=20)
class ilce(models.Model):
ill = models.ForeignKey(il, on_delete=models.CASCADE)
adi = models.CharField(max_length=35)
class mahalle(models.Model):
ilcee = models.ForeignKey(ilce, on_delete=models.CASCADE)
adi = models.CharField(max_length=50)
class User(AbstractUser):
username = None
email = models.EmailField(_('email address'), unique=True)
.......
kurum_il = models.ForeignKey('il', on_delete=models.SET_NULL, null=True, blank=False)
kurum_ilce = ChainedForeignKey('ilce', chained_field="kurum_il", chained_model_field="ill", show_all=False, sort=False, null=True, blank=False)
kurum_mahalle = ChainedForeignKey('mahalle', chained_field="kurum_ilce", chained_model_field='ilcee', show_all=False, sort=False, null=True, blank=False)
Does not appear on the Admin page even though I enter and save neighborhood information
related screenshot

Django-smart-selects looks long unmaintained with last release in 2018.
However there are few issues raised / discussed for it that may relate to your question, one of them #237. As a solution it has this Pull Request with little change to .js file (actually it just comments out one line).
As it is not yet included in official release, you can apply these changes manually and provide new .js file to override package one:
copy chainedfk.js from master branch to your project
place it at 'smart-selects/admin/js/chainedfk.js' path in your directory for static files:
place inside static directory in your app and make this app appear before smart_selects in INSTALLED_APPS
or use same static directory or at another path by your preference but specify path to static directory in STATICFILES_DIRS (more preferred, not depend on order in INSTALLED_APPS)
edit this file, apply changes of this Pull Request and any other changes of your choice.

Related

How to store thumbnails in the same folder with Django ImageKit?

Does anyone have experience using ImageKit to manage thumbnails?
I currently have the following in my models.py:
class Item(models.Model):
id = models.AutoField(primary_key=True)
owner = models.ForeignKey(
get_user_model(),
on_delete=models.SET_NULL,
null=True,
blank=True
)
image = ProcessedImageField(
upload_to=image_upload,
blank=True,
validators=[validate_image],
format='JPEG',
help_text="Max file size is 3 MB."
)
image_thumbnail = ImageSpecField(
source='image',
processors=[ResizeToFill(50, 50)],
format='JPEG',
options={'quality': 60}
)
I'd like to rename the thumbnail and store it in a particular folder (not the CACHE/images/ folder that ImageKit defaults to), but can't figure out how to do that (and adding an "upload_to" to the thumbnail gives me an error). All help greatly appreciated! Thank you!
According to the docs:
ImageSpecFields, on the other hand, are virtual—they add no fields to your database and don’t require a database. This is handy for a lot of reasons, but it means that the path to the image file needs to be programmatically constructed based on the source image and the spec.
You might just want to stick to the ProcessedImageFIeld if you don't want your files to be stored in a cache folder.

How to structure User - Team - Project model Django (ManyToMany)

I'm hoping someone can give me a push in the right direction, at least conceptually. What I'm trying to achieve; a model where:
You have users, workstreams and projects;
Workstream should always be linked to a project (i.e. they exist "in" projects)
Users can be linked to a project without being a workstream;
Users can be in multiple teams and projects
I've read something about Models Managers before, should I use these?
Something else I'm struggling with is that users can/should be linked to projects directly or though a team, will this cause problems?
below some snippets from the models.py file
class User(models.Model):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True
)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
class Workstream(models.Model):
name = models.CharField(max_length=100)
project = models.ForeignKey(Project, on_delete=models.CASCADE)
members = models.ManyToManyField(User) #Like this?
class Project(models.Model):
name = models.CharField(max_length=100)
members = models.ManyToManyField(User) #Like this?
Any help in the right directions will be greatly appreaciated!
It is not advisable to link users directly to a project if it is possible to link teams to the same project. It would be possible for a given user to be two times in a Project, as a individual user or as part of a team, and you would have to search for Users and Users inside Teams when looking for all Users linked to a Project, which is cumbersome. Or if a Workstream represents a task to be done inside a Project, it wouldn't make sense to have a User that is not inside a task to be done.
I don't know the specifics of your project, but maybe each User would join a Team that is already part of a Project. A User could join a Team and be the sole member.
class Workstream(models.Model):
name = models.CharField(max_length=100)
project = models.ForeignKey(Project, on_delete=models.CASCADE)
members = models.ManyToManyField(User)
class Project(models.Model):
name = models.CharField(max_length=100)
An admin could assign a Team to a Project or a user that has a 'project leader' privilege could assign a Team to a Project.

How do you clone a model and its dependencies in Django 2.2?

How do I clone a model in such a way that it includes (clones) data on FK-related models? I've looked through various related questions on Stack, and found most of them are for old/outdated versions of Django. Here's some illustrative model code (with str methods, etc omitted for brevity):
class Tracking(models.Model):
entry = models.CharField(blank=False, max_length=50)
timestamp = models.DateTimeField(null=True, auto_now_add=True)
active = models.BooleanField(default=False)
class Author(models.Model):
entry = models.ForeignKey(Tracking, on_delete=models.CASCADE)
first_name = models.CharField(blank=False, max_length=50)
last_name = models.ImageField(null=True, blank=True)
class Scene(models.Model):
entry = models.ForeignKey(Tracking, on_delete=models.CASCADE)
location = models.CharField(blank=False, max_length=50)
image = models.ImageField(null=True, blank=True)
My desired result would be to clone an existing "entry" on the Tracking model, such that a new "entry" on a new row is created with its own PK, as well as cloned copies of "Author" and "Scene" data on their respective tables which also point to the new cloned "entry". Any pointers in the right direction would be helpful. I'm not finding anything in the django docs.
The answer, as it turns out, is a function written by Stephen G Tuggy, as shown in this post.
I was able to modify this code for my purposes and run it successfully in the shell. It's awesome. Big thanks to Stephen for this. The "has_key()" function is deprecated and needs to be replaced with "in", as in "if field.name in" etc. Otherwise it's all good as of Python 3.7/Django 2.2.

Deprecating fields in django model

I'm normalizing a database associated with a Django project and will be moving fields to different tables. As part of the implementation process, I'd like to throw a deprecation warning to my colleagues if they attempt to use the old attributes after adding the new tables before I actually remove the columns.
class Asset(Model):
model = models.CharField(max_length=64, blank=True, null=True)
part_number = models.CharField(max_length=32, blank=True, null=True) # this will be a redundant column to be deprecated
company = models.ForeignKey('Company', models.CASCADE, blank=True, null=True) # this will be a redundant column to be deprecated
# other database fields as attributes and class methods
My understanding is that I would need to add something along the lines of warnings.warn('<field name> is deprecated', DeprecationWarning) somewhere in the class, but where would I add it?
Perhaps you could use Django's system check framework (introduced in Django 1.7).
Some interesting examples, using the system-check-framework for deprecation of custom fields, are provided in the migrations docs.
It seems you can also use this approach to mark standard fields on your model.
Applied to the example from the original post, the following works for me (tested in Django 3.1.6).
class Asset(Model):
...
company = models.ForeignKey('Company', models.CASCADE, blank=True, null=True)
company.system_check_deprecated_details = dict(
msg='The Asset.company field has been deprecated.',
hint='Use OtherModel.other_field instead.',
id='fields.W900', # pick a unique ID for your field.
)
...
See the system check API reference for more detailed information, e.g. about the "unique ID".
The following warning will then show, whenever you call runserver, migrate, or other commands, as mentioned in the docs:
System check identified some issues:
WARNINGS:
myapp.Asset.company: (fields.W900) The Asset.company field has been deprecated.
HINT: Use OtherModel.other_field instead.
Also nice to know (from the docs):
... For performance reasons, checks are not run as part of the WSGI stack that is used in deployment. ...
You can use django_deprication.DeprecatedField
pip install django-deprecation
then use like this
class Album(models.Model):
name = DeprecatedField('title')
https://github.com/openbox/django-deprecation
I do something similar to this - turn the field into a property and handle the warning there. Note that this will still break any queries you make that filter on the field - just helps with accessing the attribute from instances.
class NewAsset(Model):
model = models.CharField(max_length=64, blank=True, null=True)
class Asset(Model):
#property
def model(self):
log.warning('Stop using this')
return NewAsset.model

Optional additional data on ManyToManyField

I have a ManyToManyField in Django, and I want to save additional information for the relation. What I am doing is
class Speaker(models.Model):
name = models.CharField(max_length=50)
title = models.CharField(max_length=100, blank=True)
description = models.TextField(blank=True)
class Event(models.Model):
title = models.CharField(max_length=120)
speakers = models.ManyToManyField(Speaker, blank=True, null=True, through='Role')
class Role(models.Model):
speaker = models.ForeignKey(Speaker)
event = models.ForeignKey(Event)
role = models.CharField(max_length=50, blank=True)
As per documentation, this prevents Django from doing some automatic stuff. What is particularly annoying is that it makes the Speaker list not available when creating an Event in the admin.
I realize that in general Django does not know what to put in the Role.role field. But that is optional (blank=True). I would expect that
either Django recognizes that Role has only optional fields and lets me use the many to many relation as usual (creating the fields with an empty default), or
Django admin lets me add Speakers to a newly created event, and for each such Speaker it asks for the additional information (the value of Role.role).
The second possibility would be more useful and more general than the first. Still Django admin does none of the two: instead the speakers field is removed from the Event.
Is there a way to make Django admin behave as described above?
The solution lies in this answer. Briefly, one should use InlineModelAdmin, as documented here. This realizes exactly the second behaviour I described.